mirror of
https://github.com/rui314/mold.git
synced 2024-10-26 13:10:46 +03:00
Compare commits
4 Commits
f9e4cb1a7f
...
315dfd3244
Author | SHA1 | Date | |
---|---|---|---|
|
315dfd3244 | ||
|
02ca830f42 | ||
|
18da5b654e | ||
|
97a1e218c5 |
@ -735,7 +735,7 @@ template <typename Context>
|
|||||||
class OutputFile {
|
class OutputFile {
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<OutputFile<Context>>
|
static std::unique_ptr<OutputFile<Context>>
|
||||||
open(Context &ctx, std::string path, i64 filesize, i64 perm);
|
open(Context &ctx, std::string path, i64 filesize, int perm);
|
||||||
|
|
||||||
virtual void close(Context &ctx) = 0;
|
virtual void close(Context &ctx) = 0;
|
||||||
virtual ~OutputFile() = default;
|
virtual ~OutputFile() = default;
|
||||||
@ -743,7 +743,7 @@ public:
|
|||||||
u8 *buf = nullptr;
|
u8 *buf = nullptr;
|
||||||
std::vector<u8> buf2;
|
std::vector<u8> buf2;
|
||||||
std::string path;
|
std::string path;
|
||||||
i64 fd = -1;
|
int fd = -1;
|
||||||
i64 filesize = 0;
|
i64 filesize = 0;
|
||||||
bool is_mmapped = false;
|
bool is_mmapped = false;
|
||||||
bool is_unmapped = false;
|
bool is_unmapped = false;
|
||||||
@ -756,7 +756,7 @@ protected:
|
|||||||
template <typename Context>
|
template <typename Context>
|
||||||
class MallocOutputFile : public OutputFile<Context> {
|
class MallocOutputFile : public OutputFile<Context> {
|
||||||
public:
|
public:
|
||||||
MallocOutputFile(Context &ctx, std::string path, i64 filesize, i64 perm)
|
MallocOutputFile(Context &ctx, std::string path, i64 filesize, int perm)
|
||||||
: OutputFile<Context>(path, filesize, false), ptr(new u8[filesize]),
|
: OutputFile<Context>(path, filesize, false), ptr(new u8[filesize]),
|
||||||
perm(perm) {
|
perm(perm) {
|
||||||
this->buf = ptr.get();
|
this->buf = ptr.get();
|
||||||
@ -792,7 +792,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<u8[]> ptr;
|
std::unique_ptr<u8[]> ptr;
|
||||||
i64 perm;
|
int perm;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -905,7 +905,7 @@ void release_global_lock();
|
|||||||
//
|
//
|
||||||
|
|
||||||
u32 compute_crc32(u32 crc, u8 *buf, i64 len);
|
u32 compute_crc32(u32 crc, u8 *buf, i64 len);
|
||||||
std::vector<u8> crc32_solve(i64 datalen, u32 current, u32 want);
|
std::vector<u8> crc32_solve(u32 current, u32 desired);
|
||||||
|
|
||||||
//
|
//
|
||||||
// compress.cc
|
// compress.cc
|
||||||
|
175
common/crc32.cc
175
common/crc32.cc
@ -1,42 +1,3 @@
|
|||||||
// This file contains a function to "forge" a CRC. That is, given a piece
|
|
||||||
// of data and a desired CRC32 value, crc32_solve() returns a binary blob
|
|
||||||
// to add to the end of the original data to yield the desired CRC32
|
|
||||||
// value. A trailing garbage is ignored for many bianry file formats, so
|
|
||||||
// you can create a file with a desired CRC using crc32_solve(). We need
|
|
||||||
// it for --separate-debug-info.
|
|
||||||
//
|
|
||||||
// The code in this file is based on Mark Adler's "spoof" program. You can
|
|
||||||
// obtain the original copy of it at the following URL:
|
|
||||||
//
|
|
||||||
// https://github.com/madler/spoof/blob/master/spoof.c
|
|
||||||
//
|
|
||||||
// Below is the original license:
|
|
||||||
|
|
||||||
/* spoof.c -- modify a message to have a desired CRC
|
|
||||||
|
|
||||||
Copyright (C) 2012, 2014, 2016, 2018, 2021 Mark Adler
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
In no event will the authors be held liable for any damages arising from the
|
|
||||||
use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not claim
|
|
||||||
that you wrote the original software. If you use this software in a
|
|
||||||
product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
Mark Adler
|
|
||||||
madler@alumni.caltech.edu
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include <tbb/parallel_for_each.h>
|
#include <tbb/parallel_for_each.h>
|
||||||
@ -44,101 +5,29 @@
|
|||||||
|
|
||||||
namespace mold {
|
namespace mold {
|
||||||
|
|
||||||
static constexpr i64 deg = 32;
|
// This function "forges" a CRC. That is, given the current and a desired
|
||||||
static constexpr u32 poly = 0xedb88320;
|
// CRC32 value, crc32_solve() returns a binary blob to add to the end of
|
||||||
|
// the original data to yield the desired CRC. Trailing garbage is ignored
|
||||||
|
// by many bianry file formats, so you can create a file with a desired
|
||||||
|
// CRC using crc32_solve(). We need it for --separate-debug-file.
|
||||||
|
std::vector<u8> crc32_solve(u32 current, u32 desired) {
|
||||||
|
constexpr u32 poly = 0xedb88320;
|
||||||
|
u32 x = ~desired;
|
||||||
|
|
||||||
using Mat = std::array<u32, deg>;
|
// Each iteration computes x = (x * x^-1) mod poly.
|
||||||
|
for (i64 i = 0; i < 32; i++) {
|
||||||
static constexpr u32 gf2_matrix_times(const Mat &mat, u32 vec) {
|
x = std::rotl(x, 1);
|
||||||
u32 n = 0;
|
x ^= (x & 1) * (poly << 1);
|
||||||
for (i64 i = 0; vec; vec >>= 1, i++)
|
|
||||||
if (vec & 1)
|
|
||||||
n ^= mat[i];
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr Mat gf2_matrix_square(const Mat &mat) {
|
|
||||||
Mat sq;
|
|
||||||
for (i64 i = 0; i < deg; i++)
|
|
||||||
sq[i] = gf2_matrix_times(mat, mat[i]);
|
|
||||||
return sq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static consteval std::array<Mat, 64> get_crc_zero_powers() {
|
|
||||||
std::array<Mat, 64> p;
|
|
||||||
|
|
||||||
p[1][0] = poly;
|
|
||||||
for (i64 n = 1; n < deg; n++)
|
|
||||||
p[1][n] = 1 << (n - 1);
|
|
||||||
|
|
||||||
p[0] = gf2_matrix_square(p[1]);
|
|
||||||
p[1] = gf2_matrix_square(p[0]);
|
|
||||||
p[0] = gf2_matrix_square(p[1]);
|
|
||||||
p[1] = gf2_matrix_square(p[0]);
|
|
||||||
|
|
||||||
for (i64 i = 2; i < 64; i++)
|
|
||||||
p[i] = gf2_matrix_square(p[i - 1]);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Efficiently apply len zero bytes to crc, returning the resulting crc.
|
|
||||||
static u32 crc_zeros(u32 crc, i64 len) {
|
|
||||||
static constexpr std::array<Mat, 64> power = get_crc_zero_powers();
|
|
||||||
|
|
||||||
// apply len zeros to crc
|
|
||||||
if (crc)
|
|
||||||
for (i64 n = 0; len; len >>= 1, n++)
|
|
||||||
if (len & 1)
|
|
||||||
crc = gf2_matrix_times(power[n], crc);
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solve M x = c for x
|
|
||||||
static std::vector<bool> gf2_matrix_solve(std::vector<u32> M, u32 c) {
|
|
||||||
i64 cols = M.size();
|
|
||||||
i64 rows = deg;
|
|
||||||
|
|
||||||
// create adjoining identity matrix
|
|
||||||
std::vector<std::vector<bool>> inv(cols);
|
|
||||||
for (i64 i = 0; i < cols; i++) {
|
|
||||||
inv[i].resize(cols);
|
|
||||||
inv[i][i] = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i64 j = 0; j < rows; j++) {
|
x ^= ~current;
|
||||||
u32 pos = 1 << j;
|
|
||||||
|
|
||||||
if ((M[j] & pos) == 0) {
|
std::vector<u8> out(4);
|
||||||
i64 k;
|
out[0] = x;
|
||||||
for (k = j + 1; k < cols; k++)
|
out[1] = x >> 8;
|
||||||
if (M[k] & pos)
|
out[2] = x >> 16;
|
||||||
break;
|
out[3] = x >> 24;
|
||||||
|
return out;
|
||||||
if (k == cols) {
|
|
||||||
std::cerr << "mold: internal error: crc32_solve: no solution\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::swap(M[j], M[k]);
|
|
||||||
std::swap(inv[j], inv[k]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i64 k = 0; k < cols; k++) {
|
|
||||||
if (k != j && (M[k] & pos)) {
|
|
||||||
M[k] ^= M[j];
|
|
||||||
for (i64 i = 0; i < cols; i++)
|
|
||||||
inv[k][i] = inv[k][i] ^ inv[j][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiply inverse by c to get result x
|
|
||||||
std::vector<bool> x(cols);
|
|
||||||
for (i64 j = 0; c; c >>= 1, j++)
|
|
||||||
if (c & 1)
|
|
||||||
for (i64 i = 0; i < cols; i++)
|
|
||||||
x[i] = x[i] ^ inv[j][i];
|
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute a CRC for given data in parallel
|
// Compute a CRC for given data in parallel
|
||||||
@ -168,30 +57,4 @@ u32 compute_crc32(u32 crc, u8 *buf, i64 len) {
|
|||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given input data and a desired CRC value, this function returns
|
|
||||||
// a binary blob such that if the blob is appended to the end of the
|
|
||||||
// input data, the entire data's CRC value becomes the desired CRC.
|
|
||||||
std::vector<u8> crc32_solve(i64 datalen, u32 current, u32 desired) {
|
|
||||||
// Compute the CRC for the given data and the all-zero trailer
|
|
||||||
constexpr i64 trailer_len = 16;
|
|
||||||
current = ~crc_zeros(~current, trailer_len);
|
|
||||||
|
|
||||||
// Compute CRCs for all bits in the trailer
|
|
||||||
std::vector<u32> mat;
|
|
||||||
for (i64 i = 0; i < trailer_len * 8; i++) {
|
|
||||||
u8 buf[trailer_len] = {};
|
|
||||||
buf[i / 8] = 1 << (i % 8);
|
|
||||||
mat.push_back(~crc32_z(~crc_zeros(0, datalen), buf, sizeof(buf)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find desired trailer data
|
|
||||||
std::vector<bool> sol = gf2_matrix_solve(mat, desired ^ current);
|
|
||||||
|
|
||||||
std::vector<u8> out(trailer_len);
|
|
||||||
for (i64 i = 0; i < trailer_len * 8; i++)
|
|
||||||
if (sol[i])
|
|
||||||
out[i / 8] |= 1 << (i % 8);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mold
|
} // namespace mold
|
||||||
|
@ -15,50 +15,47 @@ inline u32 get_umask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
static std::pair<i64, char *>
|
static int
|
||||||
open_or_create_file(Context &ctx, std::string path, i64 filesize, i64 perm) {
|
open_or_create_file(Context &ctx, std::string path, std::string tmpfile,
|
||||||
std::string tmpl = filepath(path).parent_path() / ".mold-XXXXXX";
|
int perm) {
|
||||||
char *path2 = (char *)save_string(ctx, tmpl).data();
|
|
||||||
|
|
||||||
i64 fd = mkstemp(path2);
|
|
||||||
if (fd == -1)
|
|
||||||
Fatal(ctx) << "cannot open " << path2 << ": " << errno_string();
|
|
||||||
|
|
||||||
// Reuse an existing file if exists and writable because on Linux,
|
// Reuse an existing file if exists and writable because on Linux,
|
||||||
// writing to an existing file is much faster than creating a fresh
|
// writing to an existing file is much faster than creating a fresh
|
||||||
// file and writing to it.
|
// file and writing to it.
|
||||||
if (ctx.overwrite_output_file && rename(path.c_str(), path2) == 0) {
|
if (ctx.overwrite_output_file && rename(path.c_str(), tmpfile.c_str()) == 0) {
|
||||||
::close(fd);
|
i64 fd = ::open(tmpfile.c_str(), O_RDWR | O_CREAT, perm);
|
||||||
fd = ::open(path2, O_RDWR | O_CREAT, perm);
|
if (fd != -1)
|
||||||
if (fd != -1 && !ftruncate(fd, filesize) && !fchmod(fd, perm & ~get_umask()))
|
return fd;
|
||||||
return {fd, path2};
|
unlink(tmpfile.c_str());
|
||||||
|
|
||||||
unlink(path2);
|
|
||||||
fd = ::open(path2, O_RDWR | O_CREAT, perm);
|
|
||||||
if (fd == -1)
|
|
||||||
Fatal(ctx) << "cannot open " << path2 << ": " << errno_string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fchmod(fd, (perm & ~get_umask())) == -1)
|
i64 fd = ::open(tmpfile.c_str(), O_RDWR | O_CREAT, perm);
|
||||||
Fatal(ctx) << "fchmod failed: " << errno_string();
|
if (fd == -1)
|
||||||
|
Fatal(ctx) << "cannot open " << tmpfile << ": " << errno_string();
|
||||||
#ifdef __linux__
|
return fd;
|
||||||
if (fallocate(fd, 0, 0, filesize) == 0)
|
|
||||||
return {fd, path2};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ftruncate(fd, filesize) == -1)
|
|
||||||
Fatal(ctx) << "ftruncate failed: " << errno_string();
|
|
||||||
return {fd, path2};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class MemoryMappedOutputFile : public OutputFile<Context> {
|
class MemoryMappedOutputFile : public OutputFile<Context> {
|
||||||
public:
|
public:
|
||||||
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, i64 perm)
|
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm)
|
||||||
: OutputFile<Context>(path, filesize, true) {
|
: OutputFile<Context>(path, filesize, true) {
|
||||||
std::tie(this->fd, output_tmpfile) =
|
std::filesystem::path dir = filepath(path).parent_path();
|
||||||
open_or_create_file(ctx, path, filesize, perm);
|
std::string filename = filepath(path).filename().string();
|
||||||
|
std::string tmpfile = dir / ("." + filename + "." + std::to_string(getpid()));
|
||||||
|
|
||||||
|
this->fd = open_or_create_file(ctx, path, tmpfile, perm);
|
||||||
|
|
||||||
|
if (fchmod(this->fd, perm & ~get_umask()) == -1)
|
||||||
|
Fatal(ctx) << "fchmod failed: " << errno_string();
|
||||||
|
|
||||||
|
if (ftruncate(this->fd, filesize) == -1)
|
||||||
|
Fatal(ctx) << "ftruncate failed: " << errno_string();
|
||||||
|
|
||||||
|
output_tmpfile = (char *)save_string(ctx, tmpfile).data();
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
fallocate(this->fd, 0, 0, filesize);
|
||||||
|
#endif
|
||||||
|
|
||||||
this->buf = (u8 *)mmap(nullptr, filesize, PROT_READ | PROT_WRITE,
|
this->buf = (u8 *)mmap(nullptr, filesize, PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED, this->fd, 0);
|
MAP_SHARED, this->fd, 0);
|
||||||
@ -107,7 +104,7 @@ private:
|
|||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
std::unique_ptr<OutputFile<Context>>
|
std::unique_ptr<OutputFile<Context>>
|
||||||
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, i64 perm) {
|
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, int perm) {
|
||||||
Timer t(ctx, "open_file");
|
Timer t(ctx, "open_file");
|
||||||
|
|
||||||
if (path.starts_with('/') && !ctx.arg.chroot.empty())
|
if (path.starts_with('/') && !ctx.arg.chroot.empty())
|
||||||
|
@ -9,36 +9,35 @@ namespace mold {
|
|||||||
template <typename Context>
|
template <typename Context>
|
||||||
class MemoryMappedOutputFile : public OutputFile<Context> {
|
class MemoryMappedOutputFile : public OutputFile<Context> {
|
||||||
public:
|
public:
|
||||||
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, i64 perm)
|
MemoryMappedOutputFile(Context &ctx, std::string path, i64 filesize, int perm)
|
||||||
: OutputFile<Context>(path, filesize, true) {
|
: OutputFile<Context>(path, filesize, true) {
|
||||||
// TODO: use intermediate temporary file for output.
|
// TODO: use intermediate temporary file for output.
|
||||||
DWORD file_attrs =
|
DWORD attrs = (perm & 0200) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY;
|
||||||
(perm & 0200) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY;
|
|
||||||
file_handle =
|
handle = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
nullptr, CREATE_ALWAYS, attrs, nullptr);
|
||||||
nullptr, CREATE_ALWAYS, file_attrs, nullptr);
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
if (file_handle == INVALID_HANDLE_VALUE)
|
|
||||||
Fatal(ctx) << "cannot open " << path << ": " << GetLastError();
|
Fatal(ctx) << "cannot open " << path << ": " << GetLastError();
|
||||||
|
|
||||||
HANDLE mapping_handle = CreateFileMapping(
|
HANDLE map = CreateFileMapping(handle, nullptr, PAGE_READWRITE, 0,
|
||||||
file_handle, nullptr, PAGE_READWRITE, 0, filesize, nullptr);
|
filesize, nullptr);
|
||||||
if (!mapping_handle)
|
if (!map)
|
||||||
Fatal(ctx) << path << ": CreateFileMapping failed: " << GetLastError();
|
Fatal(ctx) << path << ": CreateFileMapping failed: " << GetLastError();
|
||||||
|
|
||||||
this->buf =
|
this->buf = (u8 *)MapViewOfFile(map, FILE_MAP_WRITE, 0, 0, filesize);
|
||||||
(u8 *)MapViewOfFile(mapping_handle, FILE_MAP_WRITE, 0, 0, filesize);
|
|
||||||
CloseHandle(mapping_handle);
|
|
||||||
if (!this->buf)
|
if (!this->buf)
|
||||||
Fatal(ctx) << path << ": MapViewOfFile failed: " << GetLastError();
|
Fatal(ctx) << path << ": MapViewOfFile failed: " << GetLastError();
|
||||||
|
|
||||||
|
CloseHandle(map);
|
||||||
|
|
||||||
mold::output_buffer_start = this->buf;
|
mold::output_buffer_start = this->buf;
|
||||||
mold::output_buffer_end = this->buf + filesize;
|
mold::output_buffer_end = this->buf + filesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
~MemoryMappedOutputFile() {
|
~MemoryMappedOutputFile() {
|
||||||
if (file_handle != INVALID_HANDLE_VALUE)
|
if (handle != INVALID_HANDLE_VALUE)
|
||||||
CloseHandle(file_handle);
|
CloseHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close(Context &ctx) override {
|
void close(Context &ctx) override {
|
||||||
@ -47,28 +46,27 @@ public:
|
|||||||
UnmapViewOfFile(this->buf);
|
UnmapViewOfFile(this->buf);
|
||||||
|
|
||||||
if (!this->buf2.empty()) {
|
if (!this->buf2.empty()) {
|
||||||
if (SetFilePointer(file_handle, 0, nullptr, FILE_END) ==
|
if (SetFilePointer(handle, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER)
|
||||||
INVALID_SET_FILE_POINTER)
|
Fatal(ctx) << this->path << ": SetFilePointer failed: "
|
||||||
Fatal(ctx) << this->path
|
<< GetLastError();
|
||||||
<< ": SetFilePointer failed: " << GetLastError();
|
|
||||||
|
|
||||||
DWORD written;
|
DWORD written;
|
||||||
if (!WriteFile(file_handle, this->buf2.data(), this->buf2.size(),
|
if (!WriteFile(handle, this->buf2.data(), this->buf2.size(), &written,
|
||||||
&written, nullptr))
|
nullptr))
|
||||||
Fatal(ctx) << this->path << ": WriteFile failed: " << GetLastError();
|
Fatal(ctx) << this->path << ": WriteFile failed: " << GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(file_handle);
|
CloseHandle(handle);
|
||||||
file_handle = INVALID_HANDLE_VALUE;
|
handle = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HANDLE file_handle;
|
HANDLE handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
std::unique_ptr<OutputFile<Context>>
|
std::unique_ptr<OutputFile<Context>>
|
||||||
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, i64 perm) {
|
OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, int perm) {
|
||||||
Timer t(ctx, "open_file");
|
Timer t(ctx, "open_file");
|
||||||
|
|
||||||
if (path.starts_with('/') && !ctx.arg.chroot.empty())
|
if (path.starts_with('/') && !ctx.arg.chroot.empty())
|
||||||
@ -78,14 +76,13 @@ OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, i64 perm
|
|||||||
if (path == "-") {
|
if (path == "-") {
|
||||||
is_special = true;
|
is_special = true;
|
||||||
} else {
|
} else {
|
||||||
HANDLE file_handle =
|
HANDLE h = CreateFileA(path.c_str(), GENERIC_READ,
|
||||||
CreateFileA(path.c_str(), GENERIC_READ,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
if (h != INVALID_HANDLE_VALUE) {
|
||||||
if (file_handle != INVALID_HANDLE_VALUE) {
|
if (GetFileType(h) != FILE_TYPE_DISK)
|
||||||
if (GetFileType(file_handle) != FILE_TYPE_DISK)
|
|
||||||
is_special = true;
|
is_special = true;
|
||||||
CloseHandle(file_handle);
|
CloseHandle(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +85,8 @@ Options:
|
|||||||
--defsym=SYMBOL=VALUE Define a symbol alias
|
--defsym=SYMBOL=VALUE Define a symbol alias
|
||||||
--demangle Demangle C++ symbols in log messages (default)
|
--demangle Demangle C++ symbols in log messages (default)
|
||||||
--no-demangle
|
--no-demangle
|
||||||
|
--detach Create separate debug info file in the background (default)
|
||||||
|
--no-detach
|
||||||
--enable-new-dtags Emit DT_RUNPATH for --rpath (default)
|
--enable-new-dtags Emit DT_RUNPATH for --rpath (default)
|
||||||
--disable-new-dtags Emit DT_RPATH for --rpath
|
--disable-new-dtags Emit DT_RPATH for --rpath
|
||||||
--execute-only Make executable segments unreadable
|
--execute-only Make executable segments unreadable
|
||||||
@ -759,6 +761,10 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
|||||||
ctx.arg.demangle = true;
|
ctx.arg.demangle = true;
|
||||||
} else if (read_flag("no-demangle")) {
|
} else if (read_flag("no-demangle")) {
|
||||||
ctx.arg.demangle = false;
|
ctx.arg.demangle = false;
|
||||||
|
} else if (read_flag("detach")) {
|
||||||
|
ctx.arg.detach = true;
|
||||||
|
} else if (read_flag("no-detach")) {
|
||||||
|
ctx.arg.detach = false;
|
||||||
} else if (read_flag("default-symver")) {
|
} else if (read_flag("default-symver")) {
|
||||||
ctx.arg.default_symver = true;
|
ctx.arg.default_symver = true;
|
||||||
} else if (read_flag("noinhibit-exec")) {
|
} else if (read_flag("noinhibit-exec")) {
|
||||||
@ -1413,6 +1419,10 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
|||||||
if (ctx.arg.shared && warn_shared_textrel)
|
if (ctx.arg.shared && warn_shared_textrel)
|
||||||
ctx.arg.warn_textrel = true;
|
ctx.arg.warn_textrel = true;
|
||||||
|
|
||||||
|
// We don't want the background process to write to stdout
|
||||||
|
if (ctx.arg.stats || ctx.arg.perf)
|
||||||
|
ctx.arg.detach = false;
|
||||||
|
|
||||||
ctx.arg.undefined.push_back(ctx.arg.entry);
|
ctx.arg.undefined.push_back(ctx.arg.entry);
|
||||||
|
|
||||||
for (i64 i = 0; i < ctx.arg.defsyms.size(); i++) {
|
for (i64 i = 0; i < ctx.arg.defsyms.size(); i++) {
|
||||||
|
@ -1740,6 +1740,7 @@ struct Context {
|
|||||||
bool color_diagnostics = false;
|
bool color_diagnostics = false;
|
||||||
bool default_symver = false;
|
bool default_symver = false;
|
||||||
bool demangle = true;
|
bool demangle = true;
|
||||||
|
bool detach = true;
|
||||||
bool discard_all = false;
|
bool discard_all = false;
|
||||||
bool discard_locals = false;
|
bool discard_locals = false;
|
||||||
bool eh_frame_hdr = true;
|
bool eh_frame_hdr = true;
|
||||||
|
@ -3058,7 +3058,7 @@ void write_separate_debug_file(Context<E> &ctx) {
|
|||||||
|
|
||||||
// We want to write to the debug info file in background so that the
|
// We want to write to the debug info file in background so that the
|
||||||
// user doesn't have to wait for it to complete.
|
// user doesn't have to wait for it to complete.
|
||||||
if (!ctx.arg.stats && !ctx.arg.perf)
|
if (ctx.arg.detach)
|
||||||
notify_parent();
|
notify_parent();
|
||||||
|
|
||||||
// A debug info file contains all sections as the original file, though
|
// A debug info file contains all sections as the original file, though
|
||||||
@ -3102,13 +3102,13 @@ void write_separate_debug_file(Context<E> &ctx) {
|
|||||||
// Reverse-compute a CRC32 value so that the CRC32 checksum embedded to
|
// Reverse-compute a CRC32 value so that the CRC32 checksum embedded to
|
||||||
// the .gnu_debuglink section in the main executable matches with the
|
// the .gnu_debuglink section in the main executable matches with the
|
||||||
// debug info file's CRC32 checksum.
|
// debug info file's CRC32 checksum.
|
||||||
std::vector<u8> &buf2 = ctx.output_file->buf2;
|
|
||||||
i64 datalen = filesize + buf2.size();
|
|
||||||
|
|
||||||
u32 crc = compute_crc32(0, ctx.buf, filesize);
|
u32 crc = compute_crc32(0, ctx.buf, filesize);
|
||||||
crc = compute_crc32(crc, buf2.data(), buf2.size());
|
|
||||||
|
|
||||||
std::vector<u8> trailer = crc32_solve(datalen, crc, ctx.gnu_debuglink->crc32);
|
std::vector<u8> &buf2 = ctx.output_file->buf2;
|
||||||
|
if (!buf2.empty())
|
||||||
|
crc = compute_crc32(crc, buf2.data(), buf2.size());
|
||||||
|
|
||||||
|
std::vector<u8> trailer = crc32_solve(crc, ctx.gnu_debuglink->crc32);
|
||||||
append(ctx.output_file->buf2, trailer);
|
append(ctx.output_file->buf2, trailer);
|
||||||
ctx.output_file->close(ctx);
|
ctx.output_file->close(ctx);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user