1
1
mirror of https://github.com/rui314/mold.git synced 2024-12-24 00:43:18 +03:00

Add -build-id=HEXVALUE

This commit is contained in:
Rui Ueyama 2021-03-08 20:48:21 +09:00
parent 5f492fea70
commit 5ae09ee9d3
5 changed files with 90 additions and 32 deletions

View File

@ -140,7 +140,32 @@ static i64 parse_hex(std::string opt, std::string_view value) {
static i64 parse_number(std::string opt, std::string_view value) {
if (value.find_first_not_of("0123456789") != std::string_view::npos)
Fatal() << "option -" << opt << ": not a number";
return std::stol(std::string(value));
return std::stol(std::string(value), nullptr, 16);
}
static std::vector<u8> parse_hex_build_id(std::string_view arg) {
assert(arg.starts_with("0x") || arg.starts_with("0X"));
if (arg.size() % 2)
Fatal() << "invalid build-id: " << arg;
if (arg.substr(2).find_first_not_of("0123456789abcdefABCDEF") != arg.npos)
Fatal() << "invalid build-id: " << arg;
arg = arg.substr(2);
auto fn = [](char c) {
if ('0' <= c && c <= '9')
return c - '0';
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
assert('A' <= c && c <= 'F');
return c - 'A' + 10;
};
std::vector<u8> vec(arg.size() / 2);
for (i64 i = 0; i < vec.size(); i++)
vec[i] = (fn(arg[i * 2]) << 4) | fn(arg[i * 2 + 1]);
return vec;
}
static std::vector<std::string_view>
@ -294,28 +319,30 @@ void parse_nonpositional_args(std::span<std::string_view> args,
} else if (read_arg(args, arg, "version-script")) {
parse_version_script(std::string(arg));
} else if (read_flag(args, "build-id")) {
config.build_id = BuildIdKind::HASH;
config.build_id_size = 20;
config.build_id.kind = BuildId::HASH;
config.build_id.hash_size = 20;
} else if (read_arg(args, arg, "build-id")) {
if (arg == "none") {
config.build_id = BuildIdKind::NONE;
config.build_id.kind = BuildId::NONE;
} else if (arg == "uuid") {
config.build_id = BuildIdKind::UUID;
config.build_id_size = 16;
config.build_id.kind = BuildId::UUID;
} else if (arg == "md5") {
config.build_id = BuildIdKind::HASH;
config.build_id_size = 16;
config.build_id.kind = BuildId::HASH;
config.build_id.hash_size = 16;
} else if (arg == "sha1") {
config.build_id = BuildIdKind::HASH;
config.build_id_size = 20;
config.build_id.kind = BuildId::HASH;
config.build_id.hash_size = 20;
} else if (arg == "sha256") {
config.build_id = BuildIdKind::HASH;
config.build_id_size = 32;
config.build_id.kind = BuildId::HASH;
config.build_id.hash_size = 32;
} else if (arg.starts_with("0x") || arg.starts_with("0X")) {
config.build_id.kind = BuildId::HEX;
config.build_id.value = parse_hex_build_id(arg);
} else {
Fatal() << "invalid --build-id argument: " << arg;
}
} else if (read_flag(args, "no-build-id")) {
config.build_id = BuildIdKind::NONE;
config.build_id.kind = BuildId::NONE;
} else if (read_arg(args, arg, "exclude-libs")) {
config.exclude_libs = split(arg, ",");
} else if (read_flag(args, "preload")) {

14
main.cc
View File

@ -12,6 +12,18 @@
static tbb::task_group parser_tg;
static bool preloading;
i64 BuildId::size() const {
switch (kind) {
case HEX:
return value.size();
case HASH:
return hash_size;
case UUID:
return 16;
}
unreachable();
}
static bool is_text_file(MemoryMappedFile *mb) {
return mb->size() >= 4 &&
isprint(mb->data()[0]) &&
@ -926,7 +938,7 @@ int main(int argc, char **argv) {
out::copyrel = new CopyrelSection(".bss");
out::copyrel_relro = new CopyrelSection(".bss.rel.ro");
if (config.build_id != BuildIdKind::NONE)
if (config.build_id.kind != BuildId::NONE)
out::buildid = new BuildIdSection;
if (config.eh_frame_hdr)
out::eh_frame_hdr = new EhFrameHdrSection;

12
mold.h
View File

@ -49,10 +49,16 @@ class OutputSection;
class SharedFile;
class Symbol;
enum class BuildIdKind : u8 { NONE, HASH, UUID };
struct BuildId {
i64 size() const;
enum { NONE, HEX, HASH, UUID } kind = NONE;
std::vector<u8> value;
i64 hash_size = 0;
};
struct Config {
BuildIdKind build_id = BuildIdKind::NONE;
BuildId build_id;
bool Bsymbolic = false;
bool Bsymbolic_functions = false;
bool allow_multiple_definition = false;
@ -84,7 +90,6 @@ struct Config {
i16 default_version = VER_NDX_GLOBAL;
std::vector<std::string_view> version_definitions;
std::vector<std::pair<std::string_view, i16>> version_patterns;
i64 build_id_size = 0;
i64 filler = -1;
i64 thread_count = -1;
std::string dynamic_linker = "/lib64/ld-linux-x86-64.so.2";
@ -99,6 +104,7 @@ struct Config {
std::vector<std::string_view> library_paths;
std::vector<std::string_view> trace_symbol;
std::vector<std::string_view> undefined;
std::vector<u8> build_id_value;
u64 image_base = 0x200000;
};

View File

@ -1055,16 +1055,16 @@ void VerdefSection::copy_buf() {
}
void BuildIdSection::update_shdr() {
shdr.sh_size = HEADER_SIZE + config.build_id_size;
shdr.sh_size = HEADER_SIZE + config.build_id.size();
}
void BuildIdSection::copy_buf() {
u32 *base = (u32 *)(out::buf + shdr.sh_offset);
memset(base, 0, shdr.sh_size);
base[0] = 4; // Name size
base[1] = config.build_id_size; // Hash size
base[2] = NT_GNU_BUILD_ID; // Type
memcpy(base + 3, "GNU", 4); // Name string
base[0] = 4; // Name size
base[1] = config.build_id.size(); // Hash size
base[2] = NT_GNU_BUILD_ID; // Type
memcpy(base + 3, "GNU", 4); // Name string
}
static void compute_sha256(u8 *buf, i64 size, u8 *digest) {
@ -1082,19 +1082,29 @@ static void compute_sha256(u8 *buf, i64 size, u8 *digest) {
}
void BuildIdSection::write_buildid(i64 filesize) {
if (config.build_id == BuildIdKind::UUID) {
switch (config.build_id.kind) {
case BuildId::HEX:
write_vector(out::buf + shdr.sh_offset + HEADER_SIZE,
config.build_id.value);
return;
case BuildId::HASH: {
// Modern x86 processors have purpose-built instructions to accelerate
// SHA256 computation, and SHA256 outperforms MD5 on such computers.
// So, we always compute SHA256 and truncate it if smaller digest was
// requested.
u8 digest[SHA256_SIZE];
assert(config.build_id.size() <= SHA256_SIZE);
compute_sha256(out::buf, filesize, digest);
memcpy(out::buf + shdr.sh_offset + HEADER_SIZE, digest,
config.build_id.size());
return;
}
case BuildId::UUID:
if (!RAND_bytes(out::buf + shdr.sh_offset + HEADER_SIZE,
config.build_id_size))
config.build_id.size()))
Fatal() << "RAND_bytes failed";
return;
}
// Modern x86 processors have purpose-built instructions to accelerate
// SHA256 computation, and SHA256 outperforms MD5 on such computers.
// So, we always compute SHA256 and truncate it if smaller digest was
// requested.
u8 digest[SHA256_SIZE];
assert(config.build_id_size <= SHA256_SIZE);
compute_sha256(out::buf, filesize, digest);
memcpy(out::buf + shdr.sh_offset + HEADER_SIZE, digest, config.build_id_size);
unreachable();
}

View File

@ -22,4 +22,7 @@ readelf -n $t/exe | grep -q 'GNU.*0x00000014.*NT_GNU_BUILD_ID'
clang -o $t/exe $t/a.c -fuse-ld=`pwd`/../mold -Wl,-build-id=sha256
readelf -n $t/exe | grep -q 'GNU.*0x00000020.*NT_GNU_BUILD_ID'
clang -o $t/exe $t/a.c -fuse-ld=`pwd`/../mold -Wl,-build-id=0xdeadbeef
readelf -n $t/exe | grep -q 'Build ID: deadbeef'
echo OK