mirror of
https://github.com/rui314/mold.git
synced 2024-09-22 02:20:51 +03:00
wip
This commit is contained in:
parent
48759ed6b5
commit
244cc6cb28
218
cmdline.cc
218
cmdline.cc
@ -193,7 +193,7 @@ static i64 get_default_thread_count() {
|
||||
|
||||
void parse_nonpositional_args(std::span<std::string_view> args,
|
||||
std::vector<std::string_view> &remaining) {
|
||||
config.thread_count = get_default_thread_count();
|
||||
ctx.arg.thread_count = get_default_thread_count();
|
||||
|
||||
while (!args.empty()) {
|
||||
std::string_view arg;
|
||||
@ -204,205 +204,205 @@ void parse_nonpositional_args(std::span<std::string_view> args,
|
||||
}
|
||||
|
||||
if (read_arg(args, arg, "o")) {
|
||||
config.output = arg;
|
||||
ctx.arg.output = arg;
|
||||
} else if (read_arg(args, arg, "dynamic-linker") ||
|
||||
read_arg(args, arg, "I")) {
|
||||
config.dynamic_linker = arg;
|
||||
ctx.arg.dynamic_linker = arg;
|
||||
} else if (read_arg(args, arg, "no-dynamic-linker")) {
|
||||
config.dynamic_linker = "";
|
||||
ctx.arg.dynamic_linker = "";
|
||||
} else if (read_flag(args, "export-dynamic") || read_flag(args, "E")) {
|
||||
config.export_dynamic = true;
|
||||
ctx.arg.export_dynamic = true;
|
||||
} else if (read_flag(args, "no-export-dynamic")) {
|
||||
config.export_dynamic = false;
|
||||
ctx.arg.export_dynamic = false;
|
||||
} else if (read_flag(args, "Bsymbolic")) {
|
||||
config.Bsymbolic = true;
|
||||
ctx.arg.Bsymbolic = true;
|
||||
} else if (read_flag(args, "Bsymbolic-functions")) {
|
||||
config.Bsymbolic_functions = true;
|
||||
ctx.arg.Bsymbolic_functions = true;
|
||||
} else if (read_arg(args, arg, "e") || read_arg(args, arg, "entry")) {
|
||||
config.entry = arg;
|
||||
ctx.arg.entry = arg;
|
||||
} else if (read_arg(args, arg, "Map")) {
|
||||
config.Map = arg;
|
||||
config.print_map = true;
|
||||
ctx.arg.Map = arg;
|
||||
ctx.arg.print_map = true;
|
||||
} else if (read_flag(args, "print-map") || read_flag(args, "M")) {
|
||||
config.print_map = true;
|
||||
ctx.arg.print_map = true;
|
||||
} else if (read_flag(args, "static") || read_flag(args, "Bstatic")) {
|
||||
config.is_static = true;
|
||||
ctx.arg.is_static = true;
|
||||
remaining.push_back("-Bstatic");
|
||||
} else if (read_flag(args, "Bdynamic")) {
|
||||
config.is_static = false;
|
||||
ctx.arg.is_static = false;
|
||||
remaining.push_back("-Bdynamic");
|
||||
} else if (read_flag(args, "shared") || read_flag(args, "Bshareable")) {
|
||||
config.shared = true;
|
||||
ctx.arg.shared = true;
|
||||
} else if (read_flag(args, "demangle")) {
|
||||
config.demangle = true;
|
||||
ctx.arg.demangle = true;
|
||||
} else if (read_flag(args, "no-demangle")) {
|
||||
config.demangle = false;
|
||||
ctx.arg.demangle = false;
|
||||
} else if (read_arg(args, arg, "y") || read_arg(args, arg, "trace-symbol")) {
|
||||
config.trace_symbol.push_back(arg);
|
||||
ctx.arg.trace_symbol.push_back(arg);
|
||||
} else if (read_arg(args, arg, "filler")) {
|
||||
config.filler = parse_hex("filler", arg);
|
||||
ctx.arg.filler = parse_hex("filler", arg);
|
||||
} else if (read_arg(args, arg, "L") || read_arg(args, arg, "library-path")) {
|
||||
config.library_paths.push_back(arg);
|
||||
ctx.arg.library_paths.push_back(arg);
|
||||
} else if (read_arg(args, arg, "sysroot")) {
|
||||
config.sysroot = arg;
|
||||
ctx.arg.sysroot = arg;
|
||||
} else if (read_arg(args, arg, "u") || read_arg(args, arg, "undefined")) {
|
||||
config.undefined.push_back(arg);
|
||||
ctx.arg.undefined.push_back(arg);
|
||||
} else if (read_arg(args, arg, "init")) {
|
||||
config.init = arg;
|
||||
ctx.arg.init = arg;
|
||||
} else if (read_arg(args, arg, "fini")) {
|
||||
config.fini = arg;
|
||||
ctx.arg.fini = arg;
|
||||
} else if (read_arg(args, arg, "hash-style")) {
|
||||
if (arg == "sysv") {
|
||||
config.hash_style_sysv = true;
|
||||
config.hash_style_gnu = false;
|
||||
ctx.arg.hash_style_sysv = true;
|
||||
ctx.arg.hash_style_gnu = false;
|
||||
} else if (arg == "gnu") {
|
||||
config.hash_style_sysv = false;
|
||||
config.hash_style_gnu = true;
|
||||
ctx.arg.hash_style_sysv = false;
|
||||
ctx.arg.hash_style_gnu = true;
|
||||
} else if (arg == "both") {
|
||||
config.hash_style_sysv = true;
|
||||
config.hash_style_gnu = true;
|
||||
ctx.arg.hash_style_sysv = true;
|
||||
ctx.arg.hash_style_gnu = true;
|
||||
} else {
|
||||
Fatal() << "invalid --hash-style argument: " << arg;
|
||||
}
|
||||
} else if (read_arg(args, arg, "soname") || read_arg(args, arg, "h")) {
|
||||
config.soname = arg;
|
||||
ctx.arg.soname = arg;
|
||||
} else if (read_flag(args, "allow-multiple-definition")) {
|
||||
config.allow_multiple_definition = true;
|
||||
ctx.arg.allow_multiple_definition = true;
|
||||
} else if (read_flag(args, "trace")) {
|
||||
config.trace = true;
|
||||
ctx.arg.trace = true;
|
||||
} else if (read_flag(args, "eh-frame-hdr")) {
|
||||
config.eh_frame_hdr = true;
|
||||
ctx.arg.eh_frame_hdr = true;
|
||||
} else if (read_flag(args, "no-eh-frame-hdr")) {
|
||||
config.eh_frame_hdr = false;
|
||||
ctx.arg.eh_frame_hdr = false;
|
||||
} else if (read_flag(args, "pie") || read_flag(args, "pic-executable")) {
|
||||
config.pic = true;
|
||||
config.pie = true;
|
||||
ctx.arg.pic = true;
|
||||
ctx.arg.pie = true;
|
||||
} else if (read_flag(args, "no-pie") ||
|
||||
read_flag(args, "no-pic-executable")) {
|
||||
config.pic = false;
|
||||
config.pie = false;
|
||||
ctx.arg.pic = false;
|
||||
ctx.arg.pie = false;
|
||||
} else if (read_flag(args, "relax")) {
|
||||
config.relax = true;
|
||||
ctx.arg.relax = true;
|
||||
} else if (read_flag(args, "no-relax")) {
|
||||
config.relax = false;
|
||||
ctx.arg.relax = false;
|
||||
} else if (read_flag(args, "perf")) {
|
||||
config.perf = true;
|
||||
ctx.arg.perf = true;
|
||||
} else if (read_flag(args, "stats")) {
|
||||
config.stats = true;
|
||||
ctx.arg.stats = true;
|
||||
Counter::enabled = true;
|
||||
} else if (read_flag(args, "warn-common")) {
|
||||
config.warn_common = true;
|
||||
ctx.arg.warn_common = true;
|
||||
} else if (read_flag(args, "no-warn-common")) {
|
||||
config.warn_common = false;
|
||||
ctx.arg.warn_common = false;
|
||||
} else if (read_z_flag(args, "now")) {
|
||||
config.z_now = true;
|
||||
ctx.arg.z_now = true;
|
||||
} else if (read_z_flag(args, "execstack")) {
|
||||
config.z_execstack = true;
|
||||
ctx.arg.z_execstack = true;
|
||||
} else if (read_z_flag(args, "noexecstack")) {
|
||||
config.z_execstack = false;
|
||||
ctx.arg.z_execstack = false;
|
||||
} else if (read_z_flag(args, "relro")) {
|
||||
config.z_relro = true;
|
||||
ctx.arg.z_relro = true;
|
||||
} else if (read_z_flag(args, "norelro")) {
|
||||
config.z_relro = false;
|
||||
ctx.arg.z_relro = false;
|
||||
} else if (read_z_flag(args, "defs")) {
|
||||
config.z_defs = true;
|
||||
ctx.arg.z_defs = true;
|
||||
} else if (read_z_flag(args, "nodefs")) {
|
||||
config.z_defs = false;
|
||||
ctx.arg.z_defs = false;
|
||||
} else if (read_z_flag(args, "nodlopen")) {
|
||||
config.z_dlopen = false;
|
||||
ctx.arg.z_dlopen = false;
|
||||
} else if (read_z_flag(args, "nodelete")) {
|
||||
config.z_delete = false;
|
||||
ctx.arg.z_delete = false;
|
||||
} else if (read_z_flag(args, "nocopyreloc")) {
|
||||
config.z_copyreloc = false;
|
||||
ctx.arg.z_copyreloc = false;
|
||||
} else if (read_flag(args, "no-undefined")) {
|
||||
config.z_defs = true;
|
||||
ctx.arg.z_defs = true;
|
||||
} else if (read_flag(args, "fatal-warnings")) {
|
||||
config.fatal_warnings = true;
|
||||
ctx.arg.fatal_warnings = true;
|
||||
} else if (read_flag(args, "no-fatal-warnings")) {
|
||||
config.fatal_warnings = false;
|
||||
ctx.arg.fatal_warnings = false;
|
||||
} else if (read_flag(args, "fork")) {
|
||||
config.fork = true;
|
||||
ctx.arg.fork = true;
|
||||
} else if (read_flag(args, "no-fork")) {
|
||||
config.fork = false;
|
||||
ctx.arg.fork = false;
|
||||
} else if (read_flag(args, "gc-sections")) {
|
||||
config.gc_sections = true;
|
||||
ctx.arg.gc_sections = true;
|
||||
} else if (read_flag(args, "no-gc-sections")) {
|
||||
config.gc_sections = false;
|
||||
ctx.arg.gc_sections = false;
|
||||
} else if (read_flag(args, "print-gc-sections")) {
|
||||
config.print_gc_sections = true;
|
||||
ctx.arg.print_gc_sections = true;
|
||||
} else if (read_flag(args, "no-print-gc-sections")) {
|
||||
config.print_gc_sections = false;
|
||||
ctx.arg.print_gc_sections = false;
|
||||
} else if (read_flag(args, "icf")) {
|
||||
config.icf = true;
|
||||
ctx.arg.icf = true;
|
||||
} else if (read_flag(args, "no-icf")) {
|
||||
config.icf = false;
|
||||
ctx.arg.icf = false;
|
||||
} else if (read_flag(args, "quick-exit")) {
|
||||
config.quick_exit = true;
|
||||
ctx.arg.quick_exit = true;
|
||||
} else if (read_flag(args, "no-quick-exit")) {
|
||||
config.quick_exit = false;
|
||||
ctx.arg.quick_exit = false;
|
||||
} else if (read_flag(args, "print-icf-sections")) {
|
||||
config.print_icf_sections = true;
|
||||
ctx.arg.print_icf_sections = true;
|
||||
} else if (read_flag(args, "no-print-icf-sections")) {
|
||||
config.print_icf_sections = false;
|
||||
ctx.arg.print_icf_sections = false;
|
||||
} else if (read_flag(args, "quick-exit")) {
|
||||
config.quick_exit = true;
|
||||
ctx.arg.quick_exit = true;
|
||||
} else if (read_flag(args, "no-quick-exit")) {
|
||||
config.quick_exit = false;
|
||||
ctx.arg.quick_exit = false;
|
||||
} else if (read_arg(args, arg, "thread-count")) {
|
||||
config.thread_count = parse_number("thread-count", arg);
|
||||
ctx.arg.thread_count = parse_number("thread-count", arg);
|
||||
} else if (read_flag(args, "threads")) {
|
||||
config.thread_count = get_default_thread_count();
|
||||
ctx.arg.thread_count = get_default_thread_count();
|
||||
} else if (read_flag(args, "no-threads")) {
|
||||
config.thread_count = 1;
|
||||
ctx.arg.thread_count = 1;
|
||||
} else if (read_flag(args, "discard-all") || read_flag(args, "x")) {
|
||||
config.discard_all = true;
|
||||
ctx.arg.discard_all = true;
|
||||
} else if (read_flag(args, "discard-locals") || read_flag(args, "X")) {
|
||||
config.discard_locals = true;
|
||||
ctx.arg.discard_locals = true;
|
||||
} else if (read_flag(args, "strip-all") || read_flag(args, "s")) {
|
||||
config.strip_all = true;
|
||||
ctx.arg.strip_all = true;
|
||||
} else if (read_flag(args, "strip-debug") || read_flag(args, "S")) {
|
||||
config.strip_debug = true;
|
||||
ctx.arg.strip_debug = true;
|
||||
} else if (read_arg(args, arg, "rpath")) {
|
||||
if (!config.rpaths.empty())
|
||||
config.rpaths += ":";
|
||||
config.rpaths += arg;
|
||||
if (!ctx.arg.rpaths.empty())
|
||||
ctx.arg.rpaths += ":";
|
||||
ctx.arg.rpaths += arg;
|
||||
} else if (read_arg(args, arg, "version-script")) {
|
||||
parse_version_script(std::string(arg));
|
||||
} else if (read_arg(args, arg, "dynamic-list")) {
|
||||
parse_dynamic_list(std::string(arg));
|
||||
} else if (read_flag(args, "build-id")) {
|
||||
config.build_id.kind = BuildId::HASH;
|
||||
config.build_id.hash_size = 20;
|
||||
ctx.arg.build_id.kind = BuildId::HASH;
|
||||
ctx.arg.build_id.hash_size = 20;
|
||||
} else if (read_arg(args, arg, "build-id")) {
|
||||
if (arg == "none") {
|
||||
config.build_id.kind = BuildId::NONE;
|
||||
ctx.arg.build_id.kind = BuildId::NONE;
|
||||
} else if (arg == "uuid") {
|
||||
config.build_id.kind = BuildId::UUID;
|
||||
ctx.arg.build_id.kind = BuildId::UUID;
|
||||
} else if (arg == "md5") {
|
||||
config.build_id.kind = BuildId::HASH;
|
||||
config.build_id.hash_size = 16;
|
||||
ctx.arg.build_id.kind = BuildId::HASH;
|
||||
ctx.arg.build_id.hash_size = 16;
|
||||
} else if (arg == "sha1") {
|
||||
config.build_id.kind = BuildId::HASH;
|
||||
config.build_id.hash_size = 20;
|
||||
ctx.arg.build_id.kind = BuildId::HASH;
|
||||
ctx.arg.build_id.hash_size = 20;
|
||||
} else if (arg == "sha256") {
|
||||
config.build_id.kind = BuildId::HASH;
|
||||
config.build_id.hash_size = 32;
|
||||
ctx.arg.build_id.kind = BuildId::HASH;
|
||||
ctx.arg.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);
|
||||
ctx.arg.build_id.kind = BuildId::HEX;
|
||||
ctx.arg.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.kind = BuildId::NONE;
|
||||
ctx.arg.build_id.kind = BuildId::NONE;
|
||||
} else if (read_arg(args, arg, "auxiliary") || read_arg(args, arg, "f")) {
|
||||
config.auxiliary.push_back(arg);
|
||||
ctx.arg.auxiliary.push_back(arg);
|
||||
} else if (read_arg(args, arg, "filter") || read_arg(args, arg, "F")) {
|
||||
config.filter.push_back(arg);
|
||||
ctx.arg.filter.push_back(arg);
|
||||
} else if (read_arg(args, arg, "exclude-libs")) {
|
||||
config.exclude_libs = split(arg, ",");
|
||||
ctx.arg.exclude_libs = split(arg, ",");
|
||||
} else if (read_flag(args, "preload")) {
|
||||
config.preload = true;
|
||||
ctx.arg.preload = true;
|
||||
} else if (read_arg(args, arg, "z")) {
|
||||
} else if (read_arg(args, arg, "O")) {
|
||||
} else if (read_flag(args, "O0")) {
|
||||
@ -449,21 +449,21 @@ void parse_nonpositional_args(std::span<std::string_view> args,
|
||||
}
|
||||
}
|
||||
|
||||
if (config.shared) {
|
||||
config.pic = true;
|
||||
config.dynamic_linker = "";
|
||||
if (ctx.arg.shared) {
|
||||
ctx.arg.pic = true;
|
||||
ctx.arg.dynamic_linker = "";
|
||||
}
|
||||
|
||||
if (config.pic)
|
||||
config.image_base = 0;
|
||||
if (ctx.arg.pic)
|
||||
ctx.arg.image_base = 0;
|
||||
|
||||
if (!config.shared) {
|
||||
if (!config.filter.empty())
|
||||
if (!ctx.arg.shared) {
|
||||
if (!ctx.arg.filter.empty())
|
||||
Fatal() << "-filter may not be used without -shared";
|
||||
if (!config.auxiliary.empty())
|
||||
if (!ctx.arg.auxiliary.empty())
|
||||
Fatal() << "-auxiliary may not be used without -shared";
|
||||
}
|
||||
|
||||
if (config.output.empty())
|
||||
config.output = "a.out";
|
||||
if (ctx.arg.output.empty())
|
||||
ctx.arg.output = "a.out";
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ static tbb::concurrent_vector<InputSection *> collect_root_set() {
|
||||
};
|
||||
|
||||
// Add sections that are not subject to garbage collection.
|
||||
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) {
|
||||
for (InputSection *isec : file->sections) {
|
||||
if (!isec)
|
||||
continue;
|
||||
@ -100,22 +100,22 @@ static tbb::concurrent_vector<InputSection *> collect_root_set() {
|
||||
});
|
||||
|
||||
// Add sections containing exported symbols
|
||||
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) {
|
||||
for (Symbol *sym : file->symbols)
|
||||
if (sym->file == file && sym->is_exported)
|
||||
enqueue_symbol(sym);
|
||||
});
|
||||
|
||||
// Add sections referenced by root symbols.
|
||||
enqueue_symbol(Symbol::intern(config.entry));
|
||||
enqueue_symbol(Symbol::intern(ctx.arg.entry));
|
||||
|
||||
for (std::string_view name : config.undefined)
|
||||
for (std::string_view name : ctx.arg.undefined)
|
||||
enqueue_symbol(Symbol::intern(name));
|
||||
|
||||
// .eh_frame consists of variable-length records called CIE and FDE
|
||||
// records, and they are a unit of inclusion or exclusion.
|
||||
// We just keep all CIEs and everything that are referenced by them.
|
||||
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) {
|
||||
for (CieRecord &cie : file->cies)
|
||||
for (EhReloc &rel : cie.rels)
|
||||
enqueue_section(rel.sym.input_section);
|
||||
@ -138,12 +138,12 @@ static void sweep() {
|
||||
Timer t("sweep");
|
||||
static Counter counter("garbage_sections");
|
||||
|
||||
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) {
|
||||
for (i64 i = 0; i < file->sections.size(); i++) {
|
||||
InputSection *isec = file->sections[i];
|
||||
|
||||
if (isec && isec->is_alive && !isec->is_visited) {
|
||||
if (config.print_gc_sections)
|
||||
if (ctx.arg.print_gc_sections)
|
||||
SyncOut() << "removing unused section " << *isec;
|
||||
isec->kill();
|
||||
counter++;
|
||||
@ -157,7 +157,7 @@ static void sweep() {
|
||||
static void mark_nonalloc_fragments() {
|
||||
Timer t("mark_nonalloc_fragments");
|
||||
|
||||
tbb::parallel_for_each(out::objs, [](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [](ObjectFile *file) {
|
||||
for (SectionFragment *frag : file->fragments)
|
||||
if (!(frag->output_section.shdr.sh_flags & SHF_ALLOC))
|
||||
frag->is_alive = true;
|
||||
|
30
icf.cc
30
icf.cc
@ -81,7 +81,7 @@ static void uniquify_cies() {
|
||||
Timer t("uniquify_cies");
|
||||
std::vector<CieRecord *> cies;
|
||||
|
||||
for (ObjectFile *file : out::objs) {
|
||||
for (ObjectFile *file : ctx.objs) {
|
||||
for (CieRecord &cie : file->cies) {
|
||||
for (i64 i = 0; i < cies.size(); i++) {
|
||||
if (cie_equal(cie, *cies[i])) {
|
||||
@ -176,8 +176,8 @@ static void merge_leaf_nodes() {
|
||||
tbb::concurrent_unordered_map<InputSection *, InputSection *,
|
||||
LeafHasher, LeafEq> map;
|
||||
|
||||
tbb::parallel_for((i64)0, (i64)out::objs.size(), [&](i64 i) {
|
||||
for (InputSection *isec : out::objs[i]->sections) {
|
||||
tbb::parallel_for((i64)0, (i64)ctx.objs.size(), [&](i64 i) {
|
||||
for (InputSection *isec : ctx.objs[i]->sections) {
|
||||
if (!isec)
|
||||
continue;
|
||||
|
||||
@ -199,8 +199,8 @@ static void merge_leaf_nodes() {
|
||||
}
|
||||
});
|
||||
|
||||
tbb::parallel_for((i64)0, (i64)out::objs.size(), [&](i64 i) {
|
||||
for (InputSection *isec : out::objs[i]->sections) {
|
||||
tbb::parallel_for((i64)0, (i64)ctx.objs.size(), [&](i64 i) {
|
||||
for (InputSection *isec : ctx.objs[i]->sections) {
|
||||
if (isec && isec->icf_leaf) {
|
||||
auto it = map.find(isec);
|
||||
assert(it != map.end());
|
||||
@ -293,24 +293,24 @@ static std::vector<InputSection *> gather_sections() {
|
||||
Timer t("gather_sections");
|
||||
|
||||
// Count the number of input sections for each input file.
|
||||
std::vector<i64> num_sections(out::objs.size());
|
||||
std::vector<i64> num_sections(ctx.objs.size());
|
||||
|
||||
tbb::parallel_for((i64)0, (i64)out::objs.size(), [&](i64 i) {
|
||||
for (InputSection *isec : out::objs[i]->sections)
|
||||
tbb::parallel_for((i64)0, (i64)ctx.objs.size(), [&](i64 i) {
|
||||
for (InputSection *isec : ctx.objs[i]->sections)
|
||||
if (isec && isec->icf_eligible)
|
||||
num_sections[i]++;
|
||||
});
|
||||
|
||||
std::vector<i64> section_indices(out::objs.size());
|
||||
for (i64 i = 0; i < out::objs.size() - 1; i++)
|
||||
std::vector<i64> section_indices(ctx.objs.size());
|
||||
for (i64 i = 0; i < ctx.objs.size() - 1; i++)
|
||||
section_indices[i + 1] = section_indices[i] + num_sections[i];
|
||||
|
||||
std::vector<InputSection *> sections(section_indices.back() + num_sections.back());
|
||||
|
||||
// Fill `sections` contents.
|
||||
tbb::parallel_for((i64)0, (i64)out::objs.size(), [&](i64 i) {
|
||||
tbb::parallel_for((i64)0, (i64)ctx.objs.size(), [&](i64 i) {
|
||||
i64 idx = section_indices[i];
|
||||
for (InputSection *isec : out::objs[i]->sections)
|
||||
for (InputSection *isec : ctx.objs[i]->sections)
|
||||
if (isec && isec->icf_eligible)
|
||||
sections[idx++] = isec;
|
||||
});
|
||||
@ -423,7 +423,7 @@ static void print_icf_sections() {
|
||||
tbb::concurrent_vector<InputSection *> leaders;
|
||||
tbb::concurrent_unordered_multimap<InputSection *, InputSection *> map;
|
||||
|
||||
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) {
|
||||
for (InputSection *isec : file->sections) {
|
||||
if (isec && isec->leader) {
|
||||
if (isec == isec->leader)
|
||||
@ -525,13 +525,13 @@ void icf_sections() {
|
||||
});
|
||||
}
|
||||
|
||||
if (config.print_icf_sections)
|
||||
if (ctx.arg.print_icf_sections)
|
||||
print_icf_sections();
|
||||
|
||||
// Re-assign input sections to symbols.
|
||||
{
|
||||
Timer t("reassign");
|
||||
tbb::parallel_for_each(out::objs, [](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [](ObjectFile *file) {
|
||||
for (Symbol *sym : file->symbols) {
|
||||
if (sym->file != file)
|
||||
continue;
|
||||
|
@ -193,7 +193,7 @@ void InputSection::copy_buf() {
|
||||
return;
|
||||
|
||||
// Copy data
|
||||
u8 *base = out::buf + output_section->shdr.sh_offset + offset;
|
||||
u8 *base = ctx.buf + output_section->shdr.sh_offset + offset;
|
||||
memcpy(base, contents.data(), contents.size());
|
||||
|
||||
// Apply relocations
|
||||
@ -262,8 +262,8 @@ void InputSection::apply_reloc_alloc(u8 *base) {
|
||||
i64 ref_idx = 0;
|
||||
ElfRela *dynrel = nullptr;
|
||||
|
||||
if (out::reldyn)
|
||||
dynrel = (ElfRela *)(out::buf + out::reldyn->shdr.sh_offset +
|
||||
if (ctx.reldyn)
|
||||
dynrel = (ElfRela *)(ctx.buf + ctx.reldyn->shdr.sh_offset +
|
||||
file.reldyn_offset + this->reldyn_offset);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
@ -283,8 +283,8 @@ void InputSection::apply_reloc_alloc(u8 *base) {
|
||||
#define S (ref ? ref->frag->get_addr() : sym.get_addr())
|
||||
#define A (ref ? ref->addend : rel.r_addend)
|
||||
#define P (output_section->shdr.sh_addr + offset + rel.r_offset)
|
||||
#define G (sym.get_got_addr() - out::got->shdr.sh_addr)
|
||||
#define GOT out::got->shdr.sh_addr
|
||||
#define G (sym.get_got_addr() - ctx.got->shdr.sh_addr)
|
||||
#define GOT ctx.got->shdr.sh_addr
|
||||
|
||||
switch (rel_types[i]) {
|
||||
case R_NONE:
|
||||
@ -335,12 +335,12 @@ void InputSection::apply_reloc_alloc(u8 *base) {
|
||||
0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea 0(%rax), %rax
|
||||
};
|
||||
memcpy(loc - 4, insn, sizeof(insn));
|
||||
*(u32 *)(loc + 8) = S - out::tls_end + A + 4;
|
||||
*(u32 *)(loc + 8) = S - ctx.tls_end + A + 4;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
case R_TLSLD:
|
||||
write(out::got->get_tlsld_addr() + A - P);
|
||||
write(ctx.got->get_tlsld_addr() + A - P);
|
||||
break;
|
||||
case R_TLSLD_RELAX_LE: {
|
||||
// Relax LD to LE
|
||||
@ -353,13 +353,13 @@ void InputSection::apply_reloc_alloc(u8 *base) {
|
||||
break;
|
||||
}
|
||||
case R_DTPOFF:
|
||||
write(S + A - out::tls_begin);
|
||||
write(S + A - ctx.tls_begin);
|
||||
break;
|
||||
case R_DTPOFF_RELAX:
|
||||
write(S + A - out::tls_end);
|
||||
write(S + A - ctx.tls_end);
|
||||
break;
|
||||
case R_TPOFF:
|
||||
write(S + A - out::tls_end);
|
||||
write(S + A - ctx.tls_end);
|
||||
break;
|
||||
case R_GOTTPOFF:
|
||||
write(sym.get_gottpoff_addr() + A - P);
|
||||
@ -369,7 +369,7 @@ void InputSection::apply_reloc_alloc(u8 *base) {
|
||||
loc[-3] = insn >> 16;
|
||||
loc[-2] = insn >> 8;
|
||||
loc[-1] = insn;
|
||||
write(S + A - out::tls_end + 4);
|
||||
write(S + A - ctx.tls_end + 4);
|
||||
break;
|
||||
}
|
||||
case R_GOTPC_TLSDESC:
|
||||
@ -380,7 +380,7 @@ void InputSection::apply_reloc_alloc(u8 *base) {
|
||||
0x48, 0xc7, 0xc0, 0, 0, 0, 0, // mov $0, %rax
|
||||
};
|
||||
memcpy(loc - 3, insn, sizeof(insn));
|
||||
write(S + A - out::tls_end + 4);
|
||||
write(S + A - ctx.tls_end + 4);
|
||||
break;
|
||||
}
|
||||
case R_SIZE:
|
||||
@ -455,7 +455,7 @@ void InputSection::apply_reloc_nonalloc(u8 *base) {
|
||||
break;
|
||||
case R_X86_64_DTPOFF32:
|
||||
case R_X86_64_DTPOFF64:
|
||||
write(sym.get_addr() + rel.r_addend - out::tls_begin);
|
||||
write(sym.get_addr() + rel.r_addend - ctx.tls_begin);
|
||||
break;
|
||||
case R_X86_64_SIZE32:
|
||||
case R_X86_64_SIZE64:
|
||||
@ -490,9 +490,9 @@ void InputSection::apply_reloc_nonalloc(u8 *base) {
|
||||
}
|
||||
|
||||
static i64 get_output_type() {
|
||||
if (config.shared)
|
||||
if (ctx.arg.shared)
|
||||
return 0;
|
||||
if (config.pie)
|
||||
if (ctx.arg.pie)
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
@ -543,7 +543,7 @@ void InputSection::scan_relocations() {
|
||||
case ERROR:
|
||||
break;
|
||||
case COPYREL:
|
||||
if (!config.z_copyreloc)
|
||||
if (!ctx.arg.z_copyreloc)
|
||||
break;
|
||||
if (sym.esym->st_visibility == STV_PROTECTED)
|
||||
Error() << *this << ": cannot make copy relocation for "
|
||||
@ -658,7 +658,7 @@ void InputSection::scan_relocations() {
|
||||
if (rel.r_addend != -4)
|
||||
Fatal() << *this << ": bad r_addend for R_X86_64_GOTPCRELX";
|
||||
|
||||
if (config.relax && !sym.is_imported && sym.is_relative() &&
|
||||
if (ctx.arg.relax && !sym.is_imported && sym.is_relative() &&
|
||||
relax_gotpcrelx(loc - 2)) {
|
||||
rel_types[i] = R_GOTPCRELX_RELAX;
|
||||
} else {
|
||||
@ -671,7 +671,7 @@ void InputSection::scan_relocations() {
|
||||
if (rel.r_addend != -4)
|
||||
Fatal() << *this << ": bad r_addend for R_X86_64_REX_GOTPCRELX";
|
||||
|
||||
if (config.relax && !sym.is_imported && sym.is_relative() &&
|
||||
if (ctx.arg.relax && !sym.is_imported && sym.is_relative() &&
|
||||
relax_rex_gotpcrelx(loc - 3)) {
|
||||
rel_types[i] = R_REX_GOTPCRELX_RELAX;
|
||||
} else {
|
||||
@ -688,7 +688,7 @@ void InputSection::scan_relocations() {
|
||||
if (i + 1 == rels.size())
|
||||
Fatal() << *this << ": TLSGD reloc must be followed by PLT32 or GOTPCREL";
|
||||
|
||||
if (config.relax && !config.shared && !sym.is_imported) {
|
||||
if (ctx.arg.relax && !ctx.arg.shared && !sym.is_imported) {
|
||||
rel_types[i++] = R_TLSGD_RELAX_LE;
|
||||
} else {
|
||||
sym.flags |= NEEDS_TLSGD;
|
||||
@ -702,7 +702,7 @@ void InputSection::scan_relocations() {
|
||||
if (sym.is_imported)
|
||||
Fatal() << *this << ": TLSLD reloc refers external symbol " << sym;
|
||||
|
||||
if (config.relax && !config.shared) {
|
||||
if (ctx.arg.relax && !ctx.arg.shared) {
|
||||
rel_types[i++] = R_TLSLD_RELAX_LE;
|
||||
} else {
|
||||
sym.flags |= NEEDS_TLSLD;
|
||||
@ -714,7 +714,7 @@ void InputSection::scan_relocations() {
|
||||
if (sym.is_imported)
|
||||
Fatal() << *this << ": DTPOFF reloc refers external symbol " << sym;
|
||||
|
||||
if (config.relax && !config.shared)
|
||||
if (ctx.arg.relax && !ctx.arg.shared)
|
||||
rel_types[i] = R_DTPOFF_RELAX;
|
||||
else
|
||||
rel_types[i] = R_DTPOFF;
|
||||
@ -724,9 +724,9 @@ void InputSection::scan_relocations() {
|
||||
rel_types[i] = R_TPOFF;
|
||||
break;
|
||||
case R_X86_64_GOTTPOFF:
|
||||
out::has_gottpoff = true;
|
||||
ctx.has_gottpoff = true;
|
||||
|
||||
if (config.relax && !config.shared && !sym.is_imported &&
|
||||
if (ctx.arg.relax && !ctx.arg.shared && !sym.is_imported &&
|
||||
relax_gottpoff(loc - 3)) {
|
||||
rel_types[i] = R_GOTTPOFF_RELAX;
|
||||
} else {
|
||||
@ -739,7 +739,7 @@ void InputSection::scan_relocations() {
|
||||
Fatal() << *this << ": GOTPC32_TLSDESC relocation is used"
|
||||
<< " against an invalid code sequence";
|
||||
|
||||
if (config.relax && !config.shared) {
|
||||
if (ctx.arg.relax && !ctx.arg.shared) {
|
||||
rel_types[i] = R_GOTPC_TLSDESC_RELAX_LE;
|
||||
} else {
|
||||
sym.flags |= NEEDS_TLSDESC;
|
||||
@ -751,7 +751,7 @@ void InputSection::scan_relocations() {
|
||||
rel_types[i] = R_SIZE;
|
||||
break;
|
||||
case R_X86_64_TLSDESC_CALL:
|
||||
if (config.relax && !config.shared)
|
||||
if (ctx.arg.relax && !ctx.arg.shared)
|
||||
rel_types[i] = R_TLSDESC_CALL_RELAX;
|
||||
else
|
||||
rel_types[i] = R_NONE;
|
||||
|
@ -134,10 +134,10 @@ static MemoryMappedFile *resolve_path(std::string_view tok, ReadContext &rctx) {
|
||||
std::string str(unquote(tok));
|
||||
|
||||
if (str.starts_with("/"))
|
||||
return MemoryMappedFile::must_open(config.sysroot + str);
|
||||
return MemoryMappedFile::must_open(ctx.arg.sysroot + str);
|
||||
|
||||
if (str.starts_with("-l"))
|
||||
return find_library(str.substr(2), config.library_paths, rctx);
|
||||
return find_library(str.substr(2), ctx.arg.library_paths, rctx);
|
||||
|
||||
if (std::string path = path_dirname(current_file->name) + "/";
|
||||
MemoryMappedFile *mb = MemoryMappedFile::open(path + str))
|
||||
@ -146,8 +146,8 @@ static MemoryMappedFile *resolve_path(std::string_view tok, ReadContext &rctx) {
|
||||
if (MemoryMappedFile *mb = MemoryMappedFile::open(str))
|
||||
return mb;
|
||||
|
||||
for (std::string_view dir : config.library_paths) {
|
||||
std::string root = dir.starts_with("/") ? config.sysroot : "";
|
||||
for (std::string_view dir : ctx.arg.library_paths) {
|
||||
std::string root = dir.starts_with("/") ? ctx.arg.sysroot : "";
|
||||
std::string path = root + std::string(dir) + "/" + str;
|
||||
if (MemoryMappedFile *mb = MemoryMappedFile::open(path))
|
||||
return mb;
|
||||
@ -235,9 +235,9 @@ static void parse_version_script_commands(std::span<std::string_view> &tok,
|
||||
}
|
||||
|
||||
if (tok[0] == "*")
|
||||
config.default_version = (is_global ? ver : VER_NDX_LOCAL);
|
||||
ctx.arg.default_version = (is_global ? ver : VER_NDX_LOCAL);
|
||||
else
|
||||
config.version_patterns.push_back({tok[0], ver, is_extern_cpp});
|
||||
ctx.arg.version_patterns.push_back({tok[0], ver, is_extern_cpp});
|
||||
tok = skip(tok.subspan(1), ";");
|
||||
}
|
||||
}
|
||||
@ -252,7 +252,7 @@ void parse_version_script(std::string path) {
|
||||
i16 ver = VER_NDX_GLOBAL;
|
||||
if (tok[0] != "{") {
|
||||
ver = next_ver++;
|
||||
config.version_definitions.push_back(tok[0]);
|
||||
ctx.arg.version_definitions.push_back(tok[0]);
|
||||
tok = tok.subspan(1);
|
||||
}
|
||||
|
||||
@ -288,9 +288,9 @@ void parse_dynamic_list(std::string path) {
|
||||
}
|
||||
|
||||
if (tok[0] == "*")
|
||||
config.default_version = ver;
|
||||
ctx.arg.default_version = ver;
|
||||
else
|
||||
config.version_patterns.push_back({tok[0], ver, false});
|
||||
ctx.arg.version_patterns.push_back({tok[0], ver, false});
|
||||
tok = skip(tok.subspan(1), ";");
|
||||
}
|
||||
|
||||
|
10
mapfile.cc
10
mapfile.cc
@ -10,7 +10,7 @@ static std::ofstream *open_output_file(std::string path) {
|
||||
std::ofstream *file = new std::ofstream;
|
||||
file->open(path.c_str());
|
||||
if (!file->is_open())
|
||||
Fatal() << "cannot open " << config.Map << ": " << strerror(errno);
|
||||
Fatal() << "cannot open " << ctx.arg.Map << ": " << strerror(errno);
|
||||
return file;
|
||||
}
|
||||
|
||||
@ -20,13 +20,13 @@ void print_map() {
|
||||
std::ostream *out = &std::cout;
|
||||
std::ofstream *file = nullptr;
|
||||
|
||||
if (!config.Map.empty())
|
||||
out = file = open_output_file(config.Map);
|
||||
if (!ctx.arg.Map.empty())
|
||||
out = file = open_output_file(ctx.arg.Map);
|
||||
|
||||
// Construct a section-to-symbol map.
|
||||
MapTy map;
|
||||
|
||||
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) {
|
||||
for (Symbol *sym : file->symbols) {
|
||||
if (sym->file == file && sym->input_section &&
|
||||
sym->get_type() != STT_SECTION) {
|
||||
@ -48,7 +48,7 @@ void print_map() {
|
||||
|
||||
*out << " VMA Size Align Out In Symbol\n";
|
||||
|
||||
for (OutputChunk *osec : out::chunks) {
|
||||
for (OutputChunk *osec : ctx.chunks) {
|
||||
*out << std::setw(16) << (u64)osec->shdr.sh_addr
|
||||
<< std::setw(11) << (u64)osec->shdr.sh_size
|
||||
<< std::setw(6) << (u64)osec->shdr.sh_addralign
|
||||
|
486
mold.h
486
mold.h
@ -51,168 +51,8 @@ class ReadContext;
|
||||
class SharedFile;
|
||||
class Symbol;
|
||||
|
||||
struct BuildId {
|
||||
i64 size() const;
|
||||
|
||||
enum { NONE, HEX, HASH, UUID } kind = NONE;
|
||||
std::vector<u8> value;
|
||||
i64 hash_size = 0;
|
||||
};
|
||||
|
||||
struct VersionPattern {
|
||||
std::string_view pattern;
|
||||
i16 ver_idx;
|
||||
bool is_extern_cpp;
|
||||
};
|
||||
|
||||
struct Config {
|
||||
BuildId build_id;
|
||||
bool Bsymbolic = false;
|
||||
bool Bsymbolic_functions = false;
|
||||
bool allow_multiple_definition = false;
|
||||
bool demangle = true;
|
||||
bool discard_all = false;
|
||||
bool discard_locals = false;
|
||||
bool eh_frame_hdr = true;
|
||||
bool export_dynamic = false;
|
||||
bool fatal_warnings = false;
|
||||
bool fork = true;
|
||||
bool gc_sections = false;
|
||||
bool hash_style_gnu = false;
|
||||
bool hash_style_sysv = true;
|
||||
bool icf = false;
|
||||
bool is_static = false;
|
||||
bool perf = false;
|
||||
bool pic = false;
|
||||
bool pie = false;
|
||||
bool preload = false;
|
||||
bool print_gc_sections = false;
|
||||
bool print_icf_sections = false;
|
||||
bool print_map = false;
|
||||
bool quick_exit = true;
|
||||
bool relax = true;
|
||||
bool shared = false;
|
||||
bool stats = false;
|
||||
bool strip_all = false;
|
||||
bool strip_debug = false;
|
||||
bool trace = false;
|
||||
bool warn_common = false;
|
||||
bool z_copyreloc = true;
|
||||
bool z_defs = false;
|
||||
bool z_delete = true;
|
||||
bool z_dlopen = true;
|
||||
bool z_execstack = false;
|
||||
bool z_now = false;
|
||||
bool z_relro = true;
|
||||
i16 default_version = VER_NDX_GLOBAL;
|
||||
std::vector<std::string_view> version_definitions;
|
||||
std::vector<VersionPattern> version_patterns;
|
||||
i64 filler = -1;
|
||||
i64 thread_count = -1;
|
||||
std::string Map;
|
||||
std::string dynamic_linker;
|
||||
std::string entry = "_start";
|
||||
std::string fini = "_fini";
|
||||
std::string init = "_init";
|
||||
std::string output;
|
||||
std::string rpaths;
|
||||
std::string soname;
|
||||
std::string sysroot;
|
||||
std::vector<std::string_view> auxiliary;
|
||||
std::vector<std::string_view> exclude_libs;
|
||||
std::vector<std::string_view> filter;
|
||||
std::vector<std::string_view> library_paths;
|
||||
std::vector<std::string_view> trace_symbol;
|
||||
std::vector<std::string_view> undefined;
|
||||
u64 image_base = 0x200000;
|
||||
};
|
||||
|
||||
inline Config config;
|
||||
|
||||
void cleanup();
|
||||
|
||||
class SyncOut {
|
||||
public:
|
||||
SyncOut(std::ostream &out = std::cout) : out(out) {}
|
||||
|
||||
~SyncOut() {
|
||||
static std::mutex mu;
|
||||
std::lock_guard lock(mu);
|
||||
out << ss.str() << "\n";
|
||||
}
|
||||
|
||||
template <class T> SyncOut &operator<<(T &&val) {
|
||||
ss << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream &out;
|
||||
std::stringstream ss;
|
||||
};
|
||||
|
||||
class Fatal {
|
||||
public:
|
||||
[[noreturn]] ~Fatal() {
|
||||
out.~SyncOut();
|
||||
cleanup();
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
template <class T> Fatal &operator<<(T &&val) {
|
||||
out << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
SyncOut out{std::cerr};
|
||||
};
|
||||
|
||||
class Error {
|
||||
public:
|
||||
Error() {
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
template <class T> Error &operator<<(T &&val) {
|
||||
out << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void checkpoint() {
|
||||
if (!has_error)
|
||||
return;
|
||||
cleanup();
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
static inline std::atomic_bool has_error = false;
|
||||
|
||||
private:
|
||||
SyncOut out{std::cerr};
|
||||
};
|
||||
|
||||
class Warn {
|
||||
public:
|
||||
Warn() {
|
||||
if (config.fatal_warnings)
|
||||
Error::has_error = true;
|
||||
}
|
||||
|
||||
template <class T> Warn &operator<<(T &&val) {
|
||||
out << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
SyncOut out{std::cerr};
|
||||
};
|
||||
|
||||
#define unreachable() \
|
||||
do { Fatal() << "internal error at " << __FILE__ << ":" << __LINE__; } while (0)
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const InputFile &file);
|
||||
|
||||
//
|
||||
// Interned string
|
||||
//
|
||||
@ -538,13 +378,7 @@ public:
|
||||
|
||||
class InterpSection : public OutputChunk {
|
||||
public:
|
||||
InterpSection() : OutputChunk(SYNTHETIC) {
|
||||
name = ".interp";
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_flags = SHF_ALLOC;
|
||||
shdr.sh_size = config.dynamic_linker.size() + 1;
|
||||
}
|
||||
|
||||
InterpSection();
|
||||
void copy_buf() override;
|
||||
};
|
||||
|
||||
@ -1075,11 +909,6 @@ private:
|
||||
const ElfShdr *symtab_sec;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, const InputSection &isec) {
|
||||
out << isec.file << ":(" << isec.name << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
//
|
||||
// archive_file.cc
|
||||
//
|
||||
@ -1244,6 +1073,149 @@ void parse_nonpositional_args(std::span<std::string_view> args,
|
||||
// main.cc
|
||||
//
|
||||
|
||||
struct BuildId {
|
||||
i64 size() const;
|
||||
|
||||
enum { NONE, HEX, HASH, UUID } kind = NONE;
|
||||
std::vector<u8> value;
|
||||
i64 hash_size = 0;
|
||||
};
|
||||
|
||||
struct VersionPattern {
|
||||
std::string_view pattern;
|
||||
i16 ver_idx;
|
||||
bool is_extern_cpp;
|
||||
};
|
||||
|
||||
struct Context {
|
||||
// Command-line arguments
|
||||
struct {
|
||||
BuildId build_id;
|
||||
bool Bsymbolic = false;
|
||||
bool Bsymbolic_functions = false;
|
||||
bool allow_multiple_definition = false;
|
||||
bool demangle = true;
|
||||
bool discard_all = false;
|
||||
bool discard_locals = false;
|
||||
bool eh_frame_hdr = true;
|
||||
bool export_dynamic = false;
|
||||
bool fatal_warnings = false;
|
||||
bool fork = true;
|
||||
bool gc_sections = false;
|
||||
bool hash_style_gnu = false;
|
||||
bool hash_style_sysv = true;
|
||||
bool icf = false;
|
||||
bool is_static = false;
|
||||
bool perf = false;
|
||||
bool pic = false;
|
||||
bool pie = false;
|
||||
bool preload = false;
|
||||
bool print_gc_sections = false;
|
||||
bool print_icf_sections = false;
|
||||
bool print_map = false;
|
||||
bool quick_exit = true;
|
||||
bool relax = true;
|
||||
bool shared = false;
|
||||
bool stats = false;
|
||||
bool strip_all = false;
|
||||
bool strip_debug = false;
|
||||
bool trace = false;
|
||||
bool warn_common = false;
|
||||
bool z_copyreloc = true;
|
||||
bool z_defs = false;
|
||||
bool z_delete = true;
|
||||
bool z_dlopen = true;
|
||||
bool z_execstack = false;
|
||||
bool z_now = false;
|
||||
bool z_relro = true;
|
||||
i16 default_version = VER_NDX_GLOBAL;
|
||||
std::vector<std::string_view> version_definitions;
|
||||
std::vector<VersionPattern> version_patterns;
|
||||
i64 filler = -1;
|
||||
i64 thread_count = -1;
|
||||
std::string Map;
|
||||
std::string dynamic_linker;
|
||||
std::string entry = "_start";
|
||||
std::string fini = "_fini";
|
||||
std::string init = "_init";
|
||||
std::string output;
|
||||
std::string rpaths;
|
||||
std::string soname;
|
||||
std::string sysroot;
|
||||
std::vector<std::string_view> auxiliary;
|
||||
std::vector<std::string_view> exclude_libs;
|
||||
std::vector<std::string_view> filter;
|
||||
std::vector<std::string_view> library_paths;
|
||||
std::vector<std::string_view> trace_symbol;
|
||||
std::vector<std::string_view> undefined;
|
||||
u64 image_base = 0x200000;
|
||||
} arg;
|
||||
|
||||
// Input files
|
||||
std::vector<ObjectFile *> objs;
|
||||
std::vector<SharedFile *> dsos;
|
||||
ObjectFile *internal_obj = nullptr;
|
||||
|
||||
// Output buffer
|
||||
u8 *buf;
|
||||
|
||||
std::vector<OutputChunk *> chunks;
|
||||
std::atomic_bool has_gottpoff = false;
|
||||
std::atomic_bool has_textrel = false;
|
||||
|
||||
// Output chunks
|
||||
OutputEhdr *ehdr = nullptr;
|
||||
OutputShdr *shdr = nullptr;
|
||||
OutputPhdr *phdr = nullptr;
|
||||
InterpSection *interp = nullptr;
|
||||
GotSection *got = nullptr;
|
||||
GotPltSection *gotplt = nullptr;
|
||||
RelPltSection *relplt = nullptr;
|
||||
RelDynSection *reldyn = nullptr;
|
||||
DynamicSection *dynamic = nullptr;
|
||||
StrtabSection *strtab = nullptr;
|
||||
DynstrSection *dynstr = nullptr;
|
||||
HashSection *hash = nullptr;
|
||||
GnuHashSection *gnu_hash = nullptr;
|
||||
ShstrtabSection *shstrtab = nullptr;
|
||||
PltSection *plt = nullptr;
|
||||
PltGotSection *pltgot = nullptr;
|
||||
SymtabSection *symtab = nullptr;
|
||||
DynsymSection *dynsym = nullptr;
|
||||
EhFrameSection *eh_frame = nullptr;
|
||||
EhFrameHdrSection *eh_frame_hdr = nullptr;
|
||||
DynbssSection *dynbss = nullptr;
|
||||
DynbssSection *dynbss_relro = nullptr;
|
||||
VersymSection *versym = nullptr;
|
||||
VerneedSection *verneed = nullptr;
|
||||
VerdefSection *verdef = nullptr;
|
||||
BuildIdSection *buildid = nullptr;
|
||||
|
||||
u64 tls_begin = -1;
|
||||
u64 tls_end = -1;
|
||||
|
||||
// Linker-synthesized symbols
|
||||
Symbol *__bss_start = nullptr;
|
||||
Symbol *__ehdr_start = nullptr;
|
||||
Symbol *__rela_iplt_start = nullptr;
|
||||
Symbol *__rela_iplt_end = nullptr;
|
||||
Symbol *__init_array_start = nullptr;
|
||||
Symbol *__init_array_end = nullptr;
|
||||
Symbol *__fini_array_start = nullptr;
|
||||
Symbol *__fini_array_end = nullptr;
|
||||
Symbol *__preinit_array_start = nullptr;
|
||||
Symbol *__preinit_array_end = nullptr;
|
||||
Symbol *_DYNAMIC = nullptr;
|
||||
Symbol *_GLOBAL_OFFSET_TABLE_ = nullptr;
|
||||
Symbol *__GNU_EH_FRAME_HDR = nullptr;
|
||||
Symbol *_end = nullptr;
|
||||
Symbol *_etext = nullptr;
|
||||
Symbol *_edata = nullptr;
|
||||
Symbol *__executable_start = nullptr;
|
||||
};
|
||||
|
||||
extern struct Context ctx;
|
||||
|
||||
class ReadContext {
|
||||
public:
|
||||
ReadContext(bool x) : is_preloading(x) {}
|
||||
@ -1251,7 +1223,7 @@ public:
|
||||
bool as_needed = false;
|
||||
bool whole_archive = false;
|
||||
bool is_preloading = false;
|
||||
bool is_static = config.is_static;
|
||||
bool is_static = ctx.arg.is_static;
|
||||
std::unordered_set<std::string_view> visited;
|
||||
tbb::task_group tg;
|
||||
};
|
||||
@ -1262,67 +1234,99 @@ MemoryMappedFile *find_library(std::string path,
|
||||
|
||||
void read_file(MemoryMappedFile *mb, ReadContext &ctx);
|
||||
|
||||
//
|
||||
// Error output
|
||||
//
|
||||
|
||||
class SyncOut {
|
||||
public:
|
||||
SyncOut(std::ostream &out = std::cout) : out(out) {}
|
||||
|
||||
~SyncOut() {
|
||||
static std::mutex mu;
|
||||
std::lock_guard lock(mu);
|
||||
out << ss.str() << "\n";
|
||||
}
|
||||
|
||||
template <class T> SyncOut &operator<<(T &&val) {
|
||||
ss << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream &out;
|
||||
std::stringstream ss;
|
||||
};
|
||||
|
||||
class Fatal {
|
||||
public:
|
||||
[[noreturn]] ~Fatal() {
|
||||
out.~SyncOut();
|
||||
cleanup();
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
template <class T> Fatal &operator<<(T &&val) {
|
||||
out << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
SyncOut out{std::cerr};
|
||||
};
|
||||
|
||||
class Error {
|
||||
public:
|
||||
Error() {
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
template <class T> Error &operator<<(T &&val) {
|
||||
out << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void checkpoint() {
|
||||
if (!has_error)
|
||||
return;
|
||||
cleanup();
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
static inline std::atomic_bool has_error = false;
|
||||
|
||||
private:
|
||||
SyncOut out{std::cerr};
|
||||
};
|
||||
|
||||
class Warn {
|
||||
public:
|
||||
Warn() {
|
||||
if (ctx.arg.fatal_warnings)
|
||||
Error::has_error = true;
|
||||
}
|
||||
|
||||
template <class T> Warn &operator<<(T &&val) {
|
||||
out << std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
SyncOut out{std::cerr};
|
||||
};
|
||||
|
||||
#define unreachable() \
|
||||
do { Fatal() << "internal error at " << __FILE__ << ":" << __LINE__; } while (0)
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const InputFile &file);
|
||||
|
||||
//
|
||||
// Inline objects and functions
|
||||
//
|
||||
|
||||
namespace out {
|
||||
inline u8 *buf;
|
||||
|
||||
inline std::vector<ObjectFile *> objs;
|
||||
inline std::vector<SharedFile *> dsos;
|
||||
inline std::vector<OutputChunk *> chunks;
|
||||
inline std::atomic_bool has_gottpoff = false;
|
||||
inline std::atomic_bool has_textrel = false;
|
||||
inline ObjectFile *internal_obj;
|
||||
|
||||
inline OutputEhdr *ehdr;
|
||||
inline OutputShdr *shdr;
|
||||
inline OutputPhdr *phdr;
|
||||
inline InterpSection *interp;
|
||||
inline GotSection *got;
|
||||
inline GotPltSection *gotplt;
|
||||
inline RelPltSection *relplt;
|
||||
inline RelDynSection *reldyn;
|
||||
inline DynamicSection *dynamic;
|
||||
inline StrtabSection *strtab;
|
||||
inline DynstrSection *dynstr;
|
||||
inline HashSection *hash;
|
||||
inline GnuHashSection *gnu_hash;
|
||||
inline ShstrtabSection *shstrtab;
|
||||
inline PltSection *plt;
|
||||
inline PltGotSection *pltgot;
|
||||
inline SymtabSection *symtab;
|
||||
inline DynsymSection *dynsym;
|
||||
inline EhFrameSection *eh_frame;
|
||||
inline EhFrameHdrSection *eh_frame_hdr;
|
||||
inline DynbssSection *dynbss;
|
||||
inline DynbssSection *dynbss_relro;
|
||||
inline VersymSection *versym;
|
||||
inline VerneedSection *verneed;
|
||||
inline VerdefSection *verdef;
|
||||
inline BuildIdSection *buildid;
|
||||
|
||||
inline u64 tls_begin;
|
||||
inline u64 tls_end;
|
||||
|
||||
inline Symbol *__bss_start;
|
||||
inline Symbol *__ehdr_start;
|
||||
inline Symbol *__rela_iplt_start;
|
||||
inline Symbol *__rela_iplt_end;
|
||||
inline Symbol *__init_array_start;
|
||||
inline Symbol *__init_array_end;
|
||||
inline Symbol *__fini_array_start;
|
||||
inline Symbol *__fini_array_end;
|
||||
inline Symbol *__preinit_array_start;
|
||||
inline Symbol *__preinit_array_end;
|
||||
inline Symbol *_DYNAMIC;
|
||||
inline Symbol *_GLOBAL_OFFSET_TABLE_;
|
||||
inline Symbol *__GNU_EH_FRAME_HDR;
|
||||
inline Symbol *_end;
|
||||
inline Symbol *_etext;
|
||||
inline Symbol *_edata;
|
||||
inline Symbol *__executable_start;
|
||||
inline std::ostream &operator<<(std::ostream &out, const InputSection &isec) {
|
||||
out << isec.file << ":(" << isec.name << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
inline u64 align_to(u64 val, u64 align) {
|
||||
@ -1348,7 +1352,7 @@ inline bool Symbol::is_alive() const {
|
||||
}
|
||||
|
||||
inline bool Symbol::is_absolute() const {
|
||||
if (file == out::internal_obj)
|
||||
if (file == ctx.internal_obj)
|
||||
return false;
|
||||
if (file->is_dso)
|
||||
return esym->is_abs();
|
||||
@ -1392,8 +1396,8 @@ inline u64 Symbol::get_addr() const {
|
||||
|
||||
if (has_copyrel) {
|
||||
return copyrel_readonly
|
||||
? out::dynbss_relro->shdr.sh_addr + value
|
||||
: out::dynbss->shdr.sh_addr + value;
|
||||
? ctx.dynbss_relro->shdr.sh_addr + value
|
||||
: ctx.dynbss->shdr.sh_addr + value;
|
||||
}
|
||||
|
||||
if (plt_idx != -1 && esym->st_type == STT_GNU_IFUNC)
|
||||
@ -1401,7 +1405,7 @@ inline u64 Symbol::get_addr() const {
|
||||
|
||||
if (input_section) {
|
||||
if (input_section->is_ehframe)
|
||||
return out::eh_frame->get_addr(*this);
|
||||
return ctx.eh_frame->get_addr(*this);
|
||||
|
||||
if (!input_section->is_alive) {
|
||||
// The control can reach here if there's a relocation that refers
|
||||
@ -1422,35 +1426,35 @@ inline u64 Symbol::get_addr() const {
|
||||
|
||||
inline u64 Symbol::get_got_addr() const {
|
||||
assert(got_idx != -1);
|
||||
return out::got->shdr.sh_addr + got_idx * GOT_SIZE;
|
||||
return ctx.got->shdr.sh_addr + got_idx * GOT_SIZE;
|
||||
}
|
||||
|
||||
inline u64 Symbol::get_gotplt_addr() const {
|
||||
assert(gotplt_idx != -1);
|
||||
return out::gotplt->shdr.sh_addr + gotplt_idx * GOT_SIZE;
|
||||
return ctx.gotplt->shdr.sh_addr + gotplt_idx * GOT_SIZE;
|
||||
}
|
||||
|
||||
inline u64 Symbol::get_gottpoff_addr() const {
|
||||
assert(gottpoff_idx != -1);
|
||||
return out::got->shdr.sh_addr + gottpoff_idx * GOT_SIZE;
|
||||
return ctx.got->shdr.sh_addr + gottpoff_idx * GOT_SIZE;
|
||||
}
|
||||
|
||||
inline u64 Symbol::get_tlsgd_addr() const {
|
||||
assert(tlsgd_idx != -1);
|
||||
return out::got->shdr.sh_addr + tlsgd_idx * GOT_SIZE;
|
||||
return ctx.got->shdr.sh_addr + tlsgd_idx * GOT_SIZE;
|
||||
}
|
||||
|
||||
inline u64 Symbol::get_tlsdesc_addr() const {
|
||||
assert(tlsdesc_idx != -1);
|
||||
return out::got->shdr.sh_addr + tlsdesc_idx * GOT_SIZE;
|
||||
return ctx.got->shdr.sh_addr + tlsdesc_idx * GOT_SIZE;
|
||||
}
|
||||
|
||||
inline u64 Symbol::get_plt_addr() const {
|
||||
assert(plt_idx != -1);
|
||||
|
||||
if (got_idx == -1)
|
||||
return out::plt->shdr.sh_addr + plt_idx * PLT_SIZE;
|
||||
return out::pltgot->shdr.sh_addr + plt_idx * PLT_GOT_SIZE;
|
||||
return ctx.plt->shdr.sh_addr + plt_idx * PLT_SIZE;
|
||||
return ctx.pltgot->shdr.sh_addr + plt_idx * PLT_GOT_SIZE;
|
||||
}
|
||||
|
||||
inline u64 SectionFragment::get_addr() const {
|
||||
|
@ -175,7 +175,7 @@ void ObjectFile::initialize_sections() {
|
||||
if (name == ".note.GNU-stack" || name == ".note.gnu.property")
|
||||
continue;
|
||||
|
||||
if ((config.strip_all || config.strip_debug) &&
|
||||
if ((ctx.arg.strip_all || ctx.arg.strip_debug) &&
|
||||
is_debug_section(shdr, name))
|
||||
continue;
|
||||
|
||||
@ -336,7 +336,7 @@ void ObjectFile::read_ehframe(InputSection &isec) {
|
||||
}
|
||||
|
||||
static bool should_write_to_local_symtab(Symbol &sym) {
|
||||
if (config.discard_all || config.strip_all)
|
||||
if (ctx.arg.discard_all || ctx.arg.strip_all)
|
||||
return false;
|
||||
if (sym.get_type() == STT_SECTION)
|
||||
return false;
|
||||
@ -348,7 +348,7 @@ static bool should_write_to_local_symtab(Symbol &sym) {
|
||||
// know the rationale. Anyway, this is the behavior of the
|
||||
// traditional linkers.
|
||||
if (sym.name.starts_with(".L")) {
|
||||
if (config.discard_locals)
|
||||
if (ctx.arg.discard_locals)
|
||||
return false;
|
||||
|
||||
if (InputSection *isec = sym.input_section)
|
||||
@ -643,7 +643,7 @@ void ObjectFile::maybe_override_symbol(Symbol &sym, i64 symidx) {
|
||||
} else {
|
||||
sym.value = esym.st_value;
|
||||
}
|
||||
sym.ver_idx = config.default_version;
|
||||
sym.ver_idx = ctx.arg.default_version;
|
||||
sym.esym = &esym;
|
||||
sym.is_lazy = false;
|
||||
sym.is_imported = false;
|
||||
@ -764,11 +764,11 @@ void ObjectFile::convert_undefined_weak_symbols() {
|
||||
sym.file = this;
|
||||
sym.input_section = nullptr;
|
||||
sym.value = 0;
|
||||
sym.ver_idx = config.default_version;
|
||||
sym.ver_idx = ctx.arg.default_version;
|
||||
sym.esym = &esym;
|
||||
sym.is_lazy = false;
|
||||
|
||||
if (config.shared)
|
||||
if (ctx.arg.shared)
|
||||
sym.is_imported = true;
|
||||
|
||||
if (sym.traced)
|
||||
@ -862,7 +862,7 @@ void ObjectFile::convert_common_symbols() {
|
||||
|
||||
Symbol *sym = symbols[i];
|
||||
if (sym->file != this) {
|
||||
if (config.warn_common)
|
||||
if (ctx.arg.warn_common)
|
||||
Warn() << *this << ": " << "multiple common symbols: " << *sym;
|
||||
continue;
|
||||
}
|
||||
@ -891,10 +891,10 @@ static bool should_write_to_global_symtab(Symbol &sym) {
|
||||
}
|
||||
|
||||
void ObjectFile::compute_symtab() {
|
||||
if (config.strip_all)
|
||||
if (ctx.arg.strip_all)
|
||||
return;
|
||||
|
||||
if (config.gc_sections && !config.discard_all) {
|
||||
if (ctx.arg.gc_sections && !ctx.arg.discard_all) {
|
||||
// Detect symbols pointing to sections discarded by -gc-sections
|
||||
// to not copy them to symtab.
|
||||
for (i64 i = 1; i < first_global; i++) {
|
||||
@ -921,8 +921,8 @@ void ObjectFile::compute_symtab() {
|
||||
}
|
||||
|
||||
void ObjectFile::write_symtab() {
|
||||
u8 *symtab_base = out::buf + out::symtab->shdr.sh_offset;
|
||||
u8 *strtab_base = out::buf + out::strtab->shdr.sh_offset;
|
||||
u8 *symtab_base = ctx.buf + ctx.symtab->shdr.sh_offset;
|
||||
u8 *strtab_base = ctx.buf + ctx.strtab->shdr.sh_offset;
|
||||
i64 strtab_off = strtab_offset;
|
||||
i64 symtab_off;
|
||||
|
||||
@ -935,7 +935,7 @@ void ObjectFile::write_symtab() {
|
||||
esym.st_name = strtab_off;
|
||||
|
||||
if (sym.get_type() == STT_TLS)
|
||||
esym.st_value = sym.get_addr() - out::tls_begin;
|
||||
esym.st_value = sym.get_addr() - ctx.tls_begin;
|
||||
else
|
||||
esym.st_value = sym.get_addr();
|
||||
|
||||
@ -989,27 +989,27 @@ ObjectFile::ObjectFile() {
|
||||
return sym;
|
||||
};
|
||||
|
||||
out::__ehdr_start = add("__ehdr_start", STV_HIDDEN);
|
||||
out::__rela_iplt_start = add("__rela_iplt_start", STV_HIDDEN);
|
||||
out::__rela_iplt_end = add("__rela_iplt_end", STV_HIDDEN);
|
||||
out::__init_array_start = add("__init_array_start", STV_HIDDEN);
|
||||
out::__init_array_end = add("__init_array_end", STV_HIDDEN);
|
||||
out::__fini_array_start = add("__fini_array_start", STV_HIDDEN);
|
||||
out::__fini_array_end = add("__fini_array_end", STV_HIDDEN);
|
||||
out::__preinit_array_start = add("__preinit_array_start", STV_HIDDEN);
|
||||
out::__preinit_array_end = add("__preinit_array_end", STV_HIDDEN);
|
||||
out::_DYNAMIC = add("_DYNAMIC", STV_HIDDEN);
|
||||
out::_GLOBAL_OFFSET_TABLE_ = add("_GLOBAL_OFFSET_TABLE_", STV_HIDDEN);
|
||||
out::__bss_start = add("__bss_start", STV_HIDDEN);
|
||||
out::_end = add("_end", STV_HIDDEN);
|
||||
out::_etext = add("_etext", STV_HIDDEN);
|
||||
out::_edata = add("_edata", STV_HIDDEN);
|
||||
out::__executable_start = add("__executable_start", STV_HIDDEN);
|
||||
ctx.__ehdr_start = add("__ehdr_start", STV_HIDDEN);
|
||||
ctx.__rela_iplt_start = add("__rela_iplt_start", STV_HIDDEN);
|
||||
ctx.__rela_iplt_end = add("__rela_iplt_end", STV_HIDDEN);
|
||||
ctx.__init_array_start = add("__init_array_start", STV_HIDDEN);
|
||||
ctx.__init_array_end = add("__init_array_end", STV_HIDDEN);
|
||||
ctx.__fini_array_start = add("__fini_array_start", STV_HIDDEN);
|
||||
ctx.__fini_array_end = add("__fini_array_end", STV_HIDDEN);
|
||||
ctx.__preinit_array_start = add("__preinit_array_start", STV_HIDDEN);
|
||||
ctx.__preinit_array_end = add("__preinit_array_end", STV_HIDDEN);
|
||||
ctx._DYNAMIC = add("_DYNAMIC", STV_HIDDEN);
|
||||
ctx._GLOBAL_OFFSET_TABLE_ = add("_GLOBAL_OFFSET_TABLE_", STV_HIDDEN);
|
||||
ctx.__bss_start = add("__bss_start", STV_HIDDEN);
|
||||
ctx._end = add("_end", STV_HIDDEN);
|
||||
ctx._etext = add("_etext", STV_HIDDEN);
|
||||
ctx._edata = add("_edata", STV_HIDDEN);
|
||||
ctx.__executable_start = add("__executable_start", STV_HIDDEN);
|
||||
|
||||
if (config.eh_frame_hdr)
|
||||
out::__GNU_EH_FRAME_HDR = add("__GNU_EH_FRAME_HDR", STV_HIDDEN);
|
||||
if (ctx.arg.eh_frame_hdr)
|
||||
ctx.__GNU_EH_FRAME_HDR = add("__GNU_EH_FRAME_HDR", STV_HIDDEN);
|
||||
|
||||
for (OutputChunk *chunk : out::chunks) {
|
||||
for (OutputChunk *chunk : ctx.chunks) {
|
||||
if (!is_c_identifier(chunk->name))
|
||||
continue;
|
||||
|
||||
|
435
output_chunks.cc
435
output_chunks.cc
@ -7,42 +7,42 @@
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
void OutputEhdr::copy_buf() {
|
||||
ElfEhdr &hdr = *(ElfEhdr *)(out::buf + shdr.sh_offset);
|
||||
ElfEhdr &hdr = *(ElfEhdr *)(ctx.buf + shdr.sh_offset);
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
|
||||
memcpy(&hdr.e_ident, "\177ELF", 4);
|
||||
hdr.e_ident[EI_CLASS] = ELFCLASS64;
|
||||
hdr.e_ident[EI_DATA] = ELFDATA2LSB;
|
||||
hdr.e_ident[EI_VERSION] = EV_CURRENT;
|
||||
hdr.e_type = config.pic ? ET_DYN : ET_EXEC;
|
||||
hdr.e_type = ctx.arg.pic ? ET_DYN : ET_EXEC;
|
||||
hdr.e_machine = EM_X86_64;
|
||||
hdr.e_version = EV_CURRENT;
|
||||
if (!config.entry.empty())
|
||||
hdr.e_entry = Symbol::intern(config.entry)->get_addr();
|
||||
hdr.e_phoff = out::phdr->shdr.sh_offset;
|
||||
hdr.e_shoff = out::shdr->shdr.sh_offset;
|
||||
if (!ctx.arg.entry.empty())
|
||||
hdr.e_entry = Symbol::intern(ctx.arg.entry)->get_addr();
|
||||
hdr.e_phoff = ctx.phdr->shdr.sh_offset;
|
||||
hdr.e_shoff = ctx.shdr->shdr.sh_offset;
|
||||
hdr.e_ehsize = sizeof(ElfEhdr);
|
||||
hdr.e_phentsize = sizeof(ElfPhdr);
|
||||
hdr.e_phnum = out::phdr->shdr.sh_size / sizeof(ElfPhdr);
|
||||
hdr.e_phnum = ctx.phdr->shdr.sh_size / sizeof(ElfPhdr);
|
||||
hdr.e_shentsize = sizeof(ElfShdr);
|
||||
hdr.e_shnum = out::shdr->shdr.sh_size / sizeof(ElfShdr);
|
||||
hdr.e_shstrndx = out::shstrtab->shndx;
|
||||
hdr.e_shnum = ctx.shdr->shdr.sh_size / sizeof(ElfShdr);
|
||||
hdr.e_shstrndx = ctx.shstrtab->shndx;
|
||||
}
|
||||
|
||||
void OutputShdr::update_shdr() {
|
||||
i64 n = 1;
|
||||
for (OutputChunk *chunk : out::chunks)
|
||||
for (OutputChunk *chunk : ctx.chunks)
|
||||
if (chunk->kind != OutputChunk::HEADER)
|
||||
n++;
|
||||
shdr.sh_size = n * sizeof(ElfShdr);
|
||||
}
|
||||
|
||||
void OutputShdr::copy_buf() {
|
||||
ElfShdr *hdr = (ElfShdr *)(out::buf + shdr.sh_offset);
|
||||
ElfShdr *hdr = (ElfShdr *)(ctx.buf + shdr.sh_offset);
|
||||
hdr[0] = {};
|
||||
|
||||
i64 i = 1;
|
||||
for (OutputChunk *chunk : out::chunks)
|
||||
for (OutputChunk *chunk : ctx.chunks)
|
||||
if (chunk->kind != OutputChunk::HEADER)
|
||||
hdr[i++] = chunk->shdr;
|
||||
}
|
||||
@ -63,7 +63,7 @@ bool is_relro(OutputChunk *chunk) {
|
||||
|
||||
bool match = (flags & SHF_TLS) || type == SHT_INIT_ARRAY ||
|
||||
type == SHT_FINI_ARRAY || type == SHT_PREINIT_ARRAY ||
|
||||
chunk == out::got || chunk == out::dynamic ||
|
||||
chunk == ctx.got || chunk == ctx.dynamic ||
|
||||
name.ends_with(".rel.ro");
|
||||
|
||||
return (flags & SHF_WRITE) && match;
|
||||
@ -100,16 +100,16 @@ std::vector<ElfPhdr> create_phdr() {
|
||||
};
|
||||
|
||||
// Create a PT_PHDR for the program header itself.
|
||||
define(PT_PHDR, PF_R, 8, out::phdr);
|
||||
define(PT_PHDR, PF_R, 8, ctx.phdr);
|
||||
|
||||
// Create a PT_INTERP.
|
||||
if (out::interp)
|
||||
define(PT_INTERP, PF_R, 1, out::interp);
|
||||
if (ctx.interp)
|
||||
define(PT_INTERP, PF_R, 1, ctx.interp);
|
||||
|
||||
// Create a PT_NOTE for each group of SHF_NOTE sections with the same
|
||||
// alignment requirement.
|
||||
for (i64 i = 0, end = out::chunks.size(); i < end;) {
|
||||
OutputChunk *first = out::chunks[i++];
|
||||
for (i64 i = 0, end = ctx.chunks.size(); i < end;) {
|
||||
OutputChunk *first = ctx.chunks[i++];
|
||||
if (first->shdr.sh_type != SHT_NOTE)
|
||||
continue;
|
||||
|
||||
@ -117,15 +117,15 @@ std::vector<ElfPhdr> create_phdr() {
|
||||
i64 alignment = first->shdr.sh_addralign;
|
||||
define(PT_NOTE, flags, alignment, first);
|
||||
|
||||
while (i < end && out::chunks[i]->shdr.sh_type == SHT_NOTE &&
|
||||
to_phdr_flags(out::chunks[i]) == flags &&
|
||||
out::chunks[i]->shdr.sh_addralign == alignment)
|
||||
append(out::chunks[i++]);
|
||||
while (i < end && ctx.chunks[i]->shdr.sh_type == SHT_NOTE &&
|
||||
to_phdr_flags(ctx.chunks[i]) == flags &&
|
||||
ctx.chunks[i]->shdr.sh_addralign == alignment)
|
||||
append(ctx.chunks[i++]);
|
||||
}
|
||||
|
||||
// Create PT_LOAD segments.
|
||||
for (i64 i = 0, end = out::chunks.size(); i < end;) {
|
||||
OutputChunk *first = out::chunks[i++];
|
||||
for (i64 i = 0, end = ctx.chunks.size(); i < end;) {
|
||||
OutputChunk *first = ctx.chunks[i++];
|
||||
if (!(first->shdr.sh_flags & SHF_ALLOC))
|
||||
break;
|
||||
|
||||
@ -134,53 +134,53 @@ std::vector<ElfPhdr> create_phdr() {
|
||||
first->new_page = true;
|
||||
|
||||
if (!is_bss(first))
|
||||
while (i < end && !is_bss(out::chunks[i]) &&
|
||||
to_phdr_flags(out::chunks[i]) == flags)
|
||||
append(out::chunks[i++]);
|
||||
while (i < end && !is_bss(ctx.chunks[i]) &&
|
||||
to_phdr_flags(ctx.chunks[i]) == flags)
|
||||
append(ctx.chunks[i++]);
|
||||
|
||||
while (i < end && is_bss(out::chunks[i]) &&
|
||||
to_phdr_flags(out::chunks[i]) == flags)
|
||||
append(out::chunks[i++]);
|
||||
while (i < end && is_bss(ctx.chunks[i]) &&
|
||||
to_phdr_flags(ctx.chunks[i]) == flags)
|
||||
append(ctx.chunks[i++]);
|
||||
}
|
||||
|
||||
// Create a PT_TLS.
|
||||
for (i64 i = 0; i < out::chunks.size(); i++) {
|
||||
if (!(out::chunks[i]->shdr.sh_flags & SHF_TLS))
|
||||
for (i64 i = 0; i < ctx.chunks.size(); i++) {
|
||||
if (!(ctx.chunks[i]->shdr.sh_flags & SHF_TLS))
|
||||
continue;
|
||||
|
||||
define(PT_TLS, to_phdr_flags(out::chunks[i]), 1, out::chunks[i]);
|
||||
define(PT_TLS, to_phdr_flags(ctx.chunks[i]), 1, ctx.chunks[i]);
|
||||
i++;
|
||||
while (i < out::chunks.size() && (out::chunks[i]->shdr.sh_flags & SHF_TLS))
|
||||
append(out::chunks[i++]);
|
||||
while (i < ctx.chunks.size() && (ctx.chunks[i]->shdr.sh_flags & SHF_TLS))
|
||||
append(ctx.chunks[i++]);
|
||||
}
|
||||
|
||||
// Add PT_DYNAMIC
|
||||
if (out::dynamic->shdr.sh_size)
|
||||
define(PT_DYNAMIC, PF_R | PF_W, 1, out::dynamic);
|
||||
if (ctx.dynamic->shdr.sh_size)
|
||||
define(PT_DYNAMIC, PF_R | PF_W, 1, ctx.dynamic);
|
||||
|
||||
// Add PT_GNU_EH_FRAME
|
||||
if (out::eh_frame_hdr)
|
||||
define(PT_GNU_EH_FRAME, PF_R, 1, out::eh_frame_hdr);
|
||||
if (ctx.eh_frame_hdr)
|
||||
define(PT_GNU_EH_FRAME, PF_R, 1, ctx.eh_frame_hdr);
|
||||
|
||||
// Add PT_GNU_STACK, which is a marker segment that doesn't really
|
||||
// contain any segments. It controls executable bit of stack area.
|
||||
vec.push_back({
|
||||
.p_type = PT_GNU_STACK,
|
||||
.p_flags = config.z_execstack ? (PF_R | PF_W | PF_X) : (PF_R | PF_W),
|
||||
.p_flags = ctx.arg.z_execstack ? (PF_R | PF_W | PF_X) : (PF_R | PF_W),
|
||||
});
|
||||
|
||||
// Create a PT_GNU_RELRO.
|
||||
if (config.z_relro) {
|
||||
for (i64 i = 0; i < out::chunks.size(); i++) {
|
||||
if (!is_relro(out::chunks[i]))
|
||||
if (ctx.arg.z_relro) {
|
||||
for (i64 i = 0; i < ctx.chunks.size(); i++) {
|
||||
if (!is_relro(ctx.chunks[i]))
|
||||
continue;
|
||||
|
||||
define(PT_GNU_RELRO, PF_R, 1, out::chunks[i]);
|
||||
out::chunks[i]->new_page = true;
|
||||
define(PT_GNU_RELRO, PF_R, 1, ctx.chunks[i]);
|
||||
ctx.chunks[i]->new_page = true;
|
||||
i++;
|
||||
while (i < out::chunks.size() && is_relro(out::chunks[i]))
|
||||
append(out::chunks[i++]);
|
||||
out::chunks[i - 1]->new_page_end = true;
|
||||
while (i < ctx.chunks.size() && is_relro(ctx.chunks[i]))
|
||||
append(ctx.chunks[i++]);
|
||||
ctx.chunks[i - 1]->new_page_end = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,20 +192,27 @@ void OutputPhdr::update_shdr() {
|
||||
}
|
||||
|
||||
void OutputPhdr::copy_buf() {
|
||||
write_vector(out::buf + shdr.sh_offset, create_phdr());
|
||||
write_vector(ctx.buf + shdr.sh_offset, create_phdr());
|
||||
}
|
||||
|
||||
InterpSection::InterpSection() : OutputChunk(SYNTHETIC) {
|
||||
name = ".interp";
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_flags = SHF_ALLOC;
|
||||
shdr.sh_size = ctx.arg.dynamic_linker.size() + 1;
|
||||
}
|
||||
|
||||
void InterpSection::copy_buf() {
|
||||
write_string(out::buf + shdr.sh_offset, config.dynamic_linker);
|
||||
write_string(ctx.buf + shdr.sh_offset, ctx.arg.dynamic_linker);
|
||||
}
|
||||
|
||||
void RelDynSection::update_shdr() {
|
||||
shdr.sh_link = out::dynsym->shndx;
|
||||
shdr.sh_link = ctx.dynsym->shndx;
|
||||
|
||||
// .rel.dyn contents are filled by GotSection::copy_buf() and
|
||||
// InputSection::apply_reloc_alloc().
|
||||
i64 offset = out::got->get_reldyn_size();
|
||||
for (ObjectFile *file : out::objs) {
|
||||
i64 offset = ctx.got->get_reldyn_size();
|
||||
for (ObjectFile *file : ctx.objs) {
|
||||
file->reldyn_offset = offset;
|
||||
offset += file->num_dynrel * sizeof(ElfRela);
|
||||
}
|
||||
@ -215,8 +222,8 @@ void RelDynSection::update_shdr() {
|
||||
void RelDynSection::sort() {
|
||||
Timer t("sort_dynamic_relocs");
|
||||
|
||||
ElfRela *begin = (ElfRela *)(out::buf + shdr.sh_offset);
|
||||
ElfRela *end = (ElfRela *)(out::buf + shdr.sh_offset + shdr.sh_size);
|
||||
ElfRela *begin = (ElfRela *)(ctx.buf + shdr.sh_offset);
|
||||
ElfRela *end = (ElfRela *)(ctx.buf + shdr.sh_offset + shdr.sh_size);
|
||||
|
||||
tbb::parallel_sort(begin, end, [](const ElfRela &a, const ElfRela &b) {
|
||||
return std::tuple(a.r_sym, a.r_offset) <
|
||||
@ -226,7 +233,7 @@ void RelDynSection::sort() {
|
||||
|
||||
void StrtabSection::update_shdr() {
|
||||
shdr.sh_size = 1;
|
||||
for (ObjectFile *file : out::objs) {
|
||||
for (ObjectFile *file : ctx.objs) {
|
||||
file->strtab_offset = shdr.sh_size;
|
||||
shdr.sh_size += file->strtab_size;
|
||||
}
|
||||
@ -234,7 +241,7 @@ void StrtabSection::update_shdr() {
|
||||
|
||||
void ShstrtabSection::update_shdr() {
|
||||
shdr.sh_size = 1;
|
||||
for (OutputChunk *chunk : out::chunks) {
|
||||
for (OutputChunk *chunk : ctx.chunks) {
|
||||
if (!chunk->name.empty()) {
|
||||
chunk->shdr.sh_name = shdr.sh_size;
|
||||
shdr.sh_size += chunk->name.size() + 1;
|
||||
@ -243,11 +250,11 @@ void ShstrtabSection::update_shdr() {
|
||||
}
|
||||
|
||||
void ShstrtabSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
base[0] = '\0';
|
||||
|
||||
i64 i = 1;
|
||||
for (OutputChunk *chunk : out::chunks) {
|
||||
for (OutputChunk *chunk : ctx.chunks) {
|
||||
if (!chunk->name.empty()) {
|
||||
write_string(base + i, chunk->name);
|
||||
i += chunk->name.size() + 1;
|
||||
@ -277,15 +284,15 @@ void DynstrSection::update_shdr() {
|
||||
}
|
||||
|
||||
void DynstrSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
base[0] = '\0';
|
||||
|
||||
for (std::pair<std::string_view, i64> pair : strings)
|
||||
write_string(base + pair.second, pair.first);
|
||||
|
||||
if (!out::dynsym->symbols.empty()) {
|
||||
if (!ctx.dynsym->symbols.empty()) {
|
||||
i64 offset = dynsym_offset;
|
||||
for (Symbol *sym : std::span(out::dynsym->symbols).subspan(1)) {
|
||||
for (Symbol *sym : std::span(ctx.dynsym->symbols).subspan(1)) {
|
||||
write_string(base + offset, sym->name);
|
||||
offset += sym->name.size() + 1;
|
||||
}
|
||||
@ -295,18 +302,18 @@ void DynstrSection::copy_buf() {
|
||||
void SymtabSection::update_shdr() {
|
||||
shdr.sh_size = sizeof(ElfSym);
|
||||
|
||||
for (ObjectFile *file : out::objs) {
|
||||
for (ObjectFile *file : ctx.objs) {
|
||||
file->local_symtab_offset = shdr.sh_size;
|
||||
shdr.sh_size += file->num_local_symtab * sizeof(ElfSym);
|
||||
}
|
||||
|
||||
for (ObjectFile *file : out::objs) {
|
||||
for (ObjectFile *file : ctx.objs) {
|
||||
file->global_symtab_offset = shdr.sh_size;
|
||||
shdr.sh_size += file->num_global_symtab * sizeof(ElfSym);
|
||||
}
|
||||
|
||||
shdr.sh_info = out::objs[0]->global_symtab_offset / sizeof(ElfSym);
|
||||
shdr.sh_link = out::strtab->shndx;
|
||||
shdr.sh_info = ctx.objs[0]->global_symtab_offset / sizeof(ElfSym);
|
||||
shdr.sh_link = ctx.strtab->shndx;
|
||||
|
||||
if (shdr.sh_size == sizeof(ElfSym))
|
||||
shdr.sh_size = 0;
|
||||
@ -316,23 +323,23 @@ void SymtabSection::update_shdr() {
|
||||
}
|
||||
|
||||
void SymtabSection::copy_buf() {
|
||||
memset(out::buf + shdr.sh_offset, 0, sizeof(ElfSym));
|
||||
out::buf[out::strtab->shdr.sh_offset] = '\0';
|
||||
memset(ctx.buf + shdr.sh_offset, 0, sizeof(ElfSym));
|
||||
ctx.buf[ctx.strtab->shdr.sh_offset] = '\0';
|
||||
|
||||
tbb::parallel_for_each(out::objs, [](ObjectFile *file) {
|
||||
tbb::parallel_for_each(ctx.objs, [](ObjectFile *file) {
|
||||
file->write_symtab();
|
||||
});
|
||||
}
|
||||
|
||||
static bool has_init_array() {
|
||||
for (OutputChunk *chunk : out::chunks)
|
||||
for (OutputChunk *chunk : ctx.chunks)
|
||||
if (chunk->shdr.sh_type == SHT_INIT_ARRAY)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool has_fini_array() {
|
||||
for (OutputChunk *chunk : out::chunks)
|
||||
for (OutputChunk *chunk : ctx.chunks)
|
||||
if (chunk->shdr.sh_type == SHT_FINI_ARRAY)
|
||||
return true;
|
||||
return false;
|
||||
@ -346,98 +353,98 @@ static std::vector<u64> create_dynamic_section() {
|
||||
vec.push_back(val);
|
||||
};
|
||||
|
||||
for (SharedFile *file : out::dsos)
|
||||
define(DT_NEEDED, out::dynstr->find_string(file->soname));
|
||||
for (SharedFile *file : ctx.dsos)
|
||||
define(DT_NEEDED, ctx.dynstr->find_string(file->soname));
|
||||
|
||||
if (!config.rpaths.empty())
|
||||
define(DT_RUNPATH, out::dynstr->find_string(config.rpaths));
|
||||
if (!ctx.arg.rpaths.empty())
|
||||
define(DT_RUNPATH, ctx.dynstr->find_string(ctx.arg.rpaths));
|
||||
|
||||
if (!config.soname.empty())
|
||||
define(DT_SONAME, out::dynstr->find_string(config.soname));
|
||||
if (!ctx.arg.soname.empty())
|
||||
define(DT_SONAME, ctx.dynstr->find_string(ctx.arg.soname));
|
||||
|
||||
for (std::string_view str : config.auxiliary)
|
||||
define(DT_AUXILIARY, out::dynstr->find_string(str));
|
||||
for (std::string_view str : ctx.arg.auxiliary)
|
||||
define(DT_AUXILIARY, ctx.dynstr->find_string(str));
|
||||
|
||||
for (std::string_view str : config.filter)
|
||||
define(DT_FILTER, out::dynstr->find_string(str));
|
||||
for (std::string_view str : ctx.arg.filter)
|
||||
define(DT_FILTER, ctx.dynstr->find_string(str));
|
||||
|
||||
if (out::reldyn->shdr.sh_size) {
|
||||
define(DT_RELA, out::reldyn->shdr.sh_addr);
|
||||
define(DT_RELASZ, out::reldyn->shdr.sh_size);
|
||||
if (ctx.reldyn->shdr.sh_size) {
|
||||
define(DT_RELA, ctx.reldyn->shdr.sh_addr);
|
||||
define(DT_RELASZ, ctx.reldyn->shdr.sh_size);
|
||||
define(DT_RELAENT, sizeof(ElfRela));
|
||||
}
|
||||
|
||||
if (out::relplt->shdr.sh_size) {
|
||||
define(DT_JMPREL, out::relplt->shdr.sh_addr);
|
||||
define(DT_PLTRELSZ, out::relplt->shdr.sh_size);
|
||||
if (ctx.relplt->shdr.sh_size) {
|
||||
define(DT_JMPREL, ctx.relplt->shdr.sh_addr);
|
||||
define(DT_PLTRELSZ, ctx.relplt->shdr.sh_size);
|
||||
define(DT_PLTREL, DT_RELA);
|
||||
}
|
||||
|
||||
if (out::gotplt->shdr.sh_size)
|
||||
define(DT_PLTGOT, out::gotplt->shdr.sh_addr);
|
||||
if (ctx.gotplt->shdr.sh_size)
|
||||
define(DT_PLTGOT, ctx.gotplt->shdr.sh_addr);
|
||||
|
||||
if (out::dynsym->shdr.sh_size) {
|
||||
define(DT_SYMTAB, out::dynsym->shdr.sh_addr);
|
||||
if (ctx.dynsym->shdr.sh_size) {
|
||||
define(DT_SYMTAB, ctx.dynsym->shdr.sh_addr);
|
||||
define(DT_SYMENT, sizeof(ElfSym));
|
||||
}
|
||||
|
||||
if (out::dynstr->shdr.sh_size) {
|
||||
define(DT_STRTAB, out::dynstr->shdr.sh_addr);
|
||||
define(DT_STRSZ, out::dynstr->shdr.sh_size);
|
||||
if (ctx.dynstr->shdr.sh_size) {
|
||||
define(DT_STRTAB, ctx.dynstr->shdr.sh_addr);
|
||||
define(DT_STRSZ, ctx.dynstr->shdr.sh_size);
|
||||
}
|
||||
|
||||
if (has_init_array()) {
|
||||
define(DT_INIT_ARRAY, out::__init_array_start->value);
|
||||
define(DT_INIT_ARRAY, ctx.__init_array_start->value);
|
||||
define(DT_INIT_ARRAYSZ,
|
||||
out::__init_array_end->value - out::__init_array_start->value);
|
||||
ctx.__init_array_end->value - ctx.__init_array_start->value);
|
||||
}
|
||||
|
||||
if (has_fini_array()) {
|
||||
define(DT_FINI_ARRAY, out::__fini_array_start->value);
|
||||
define(DT_FINI_ARRAY, ctx.__fini_array_start->value);
|
||||
define(DT_FINI_ARRAYSZ,
|
||||
out::__fini_array_end->value - out::__fini_array_start->value);
|
||||
ctx.__fini_array_end->value - ctx.__fini_array_start->value);
|
||||
}
|
||||
|
||||
if (out::versym->shdr.sh_size)
|
||||
define(DT_VERSYM, out::versym->shdr.sh_addr);
|
||||
if (ctx.versym->shdr.sh_size)
|
||||
define(DT_VERSYM, ctx.versym->shdr.sh_addr);
|
||||
|
||||
if (out::verneed->shdr.sh_size) {
|
||||
define(DT_VERNEED, out::verneed->shdr.sh_addr);
|
||||
define(DT_VERNEEDNUM, out::verneed->shdr.sh_info);
|
||||
if (ctx.verneed->shdr.sh_size) {
|
||||
define(DT_VERNEED, ctx.verneed->shdr.sh_addr);
|
||||
define(DT_VERNEEDNUM, ctx.verneed->shdr.sh_info);
|
||||
}
|
||||
|
||||
if (out::verdef) {
|
||||
define(DT_VERDEF, out::verdef->shdr.sh_addr);
|
||||
define(DT_VERDEFNUM, out::verdef->shdr.sh_info);
|
||||
if (ctx.verdef) {
|
||||
define(DT_VERDEF, ctx.verdef->shdr.sh_addr);
|
||||
define(DT_VERDEFNUM, ctx.verdef->shdr.sh_info);
|
||||
}
|
||||
|
||||
if (Symbol *sym = Symbol::intern(config.init); sym->file)
|
||||
if (Symbol *sym = Symbol::intern(ctx.arg.init); sym->file)
|
||||
define(DT_INIT, sym->get_addr());
|
||||
if (Symbol *sym = Symbol::intern(config.fini); sym->file)
|
||||
if (Symbol *sym = Symbol::intern(ctx.arg.fini); sym->file)
|
||||
define(DT_FINI, sym->get_addr());
|
||||
|
||||
if (out::hash)
|
||||
define(DT_HASH, out::hash->shdr.sh_addr);
|
||||
if (out::gnu_hash)
|
||||
define(DT_GNU_HASH, out::gnu_hash->shdr.sh_addr);
|
||||
if (ctx.hash)
|
||||
define(DT_HASH, ctx.hash->shdr.sh_addr);
|
||||
if (ctx.gnu_hash)
|
||||
define(DT_GNU_HASH, ctx.gnu_hash->shdr.sh_addr);
|
||||
|
||||
i64 flags = 0;
|
||||
i64 flags1 = 0;
|
||||
|
||||
if (config.pie)
|
||||
if (ctx.arg.pie)
|
||||
flags1 |= DF_1_PIE;
|
||||
|
||||
if (config.z_now) {
|
||||
if (ctx.arg.z_now) {
|
||||
flags |= DF_BIND_NOW;
|
||||
flags1 |= DF_1_NOW;
|
||||
}
|
||||
|
||||
if (!config.z_dlopen)
|
||||
if (!ctx.arg.z_dlopen)
|
||||
flags1 |= DF_1_NOOPEN;
|
||||
if (!config.z_delete)
|
||||
if (!ctx.arg.z_delete)
|
||||
flags1 |= DF_1_NODELETE;
|
||||
|
||||
if (out::has_gottpoff)
|
||||
if (ctx.has_gottpoff)
|
||||
flags |= DF_STATIC_TLS;
|
||||
|
||||
if (flags)
|
||||
@ -451,19 +458,19 @@ static std::vector<u64> create_dynamic_section() {
|
||||
}
|
||||
|
||||
void DynamicSection::update_shdr() {
|
||||
if (config.is_static)
|
||||
if (ctx.arg.is_static)
|
||||
return;
|
||||
if (!config.shared && out::dsos.empty())
|
||||
if (!ctx.arg.shared && ctx.dsos.empty())
|
||||
return;
|
||||
|
||||
shdr.sh_size = create_dynamic_section().size() * 8;
|
||||
shdr.sh_link = out::dynstr->shndx;
|
||||
shdr.sh_link = ctx.dynstr->shndx;
|
||||
}
|
||||
|
||||
void DynamicSection::copy_buf() {
|
||||
std::vector<u64> contents = create_dynamic_section();
|
||||
assert(shdr.sh_size == contents.size() * sizeof(contents[0]));
|
||||
write_vector(out::buf + shdr.sh_offset, contents);
|
||||
write_vector(ctx.buf + shdr.sh_offset, contents);
|
||||
}
|
||||
|
||||
static std::string_view get_output_name(std::string_view name) {
|
||||
@ -540,7 +547,7 @@ void OutputSection::copy_buf() {
|
||||
u64 this_end = isec.offset + isec.shdr.sh_size;
|
||||
u64 next_start = (i == members.size() - 1) ?
|
||||
shdr.sh_size : members[i + 1]->offset;
|
||||
memset(out::buf + shdr.sh_offset + this_end, 0, next_start - this_end);
|
||||
memset(ctx.buf + shdr.sh_offset + this_end, 0, next_start - this_end);
|
||||
});
|
||||
}
|
||||
|
||||
@ -551,7 +558,7 @@ void GotSection::add_got_symbol(Symbol *sym) {
|
||||
got_syms.push_back(sym);
|
||||
|
||||
if (sym->is_imported)
|
||||
out::dynsym->add_symbol(sym);
|
||||
ctx.dynsym->add_symbol(sym);
|
||||
}
|
||||
|
||||
void GotSection::add_gottpoff_symbol(Symbol *sym) {
|
||||
@ -561,7 +568,7 @@ void GotSection::add_gottpoff_symbol(Symbol *sym) {
|
||||
gottpoff_syms.push_back(sym);
|
||||
|
||||
if (sym->is_imported)
|
||||
out::dynsym->add_symbol(sym);
|
||||
ctx.dynsym->add_symbol(sym);
|
||||
}
|
||||
|
||||
void GotSection::add_tlsgd_symbol(Symbol *sym) {
|
||||
@ -569,7 +576,7 @@ void GotSection::add_tlsgd_symbol(Symbol *sym) {
|
||||
sym->tlsgd_idx = shdr.sh_size / GOT_SIZE;
|
||||
shdr.sh_size += GOT_SIZE * 2;
|
||||
tlsgd_syms.push_back(sym);
|
||||
out::dynsym->add_symbol(sym);
|
||||
ctx.dynsym->add_symbol(sym);
|
||||
}
|
||||
|
||||
void GotSection::add_tlsdesc_symbol(Symbol *sym) {
|
||||
@ -577,7 +584,7 @@ void GotSection::add_tlsdesc_symbol(Symbol *sym) {
|
||||
sym->tlsdesc_idx = shdr.sh_size / GOT_SIZE;
|
||||
shdr.sh_size += GOT_SIZE * 2;
|
||||
tlsdesc_syms.push_back(sym);
|
||||
out::dynsym->add_symbol(sym);
|
||||
ctx.dynsym->add_symbol(sym);
|
||||
}
|
||||
|
||||
void GotSection::add_tlsld() {
|
||||
@ -590,7 +597,7 @@ void GotSection::add_tlsld() {
|
||||
i64 GotSection::get_reldyn_size() const {
|
||||
i64 n = 0;
|
||||
for (Symbol *sym : got_syms)
|
||||
if (sym->is_imported || (config.pic && sym->is_relative()))
|
||||
if (sym->is_imported || (ctx.arg.pic && sym->is_relative()))
|
||||
n++;
|
||||
|
||||
n += tlsgd_syms.size() * 2;
|
||||
@ -603,18 +610,18 @@ i64 GotSection::get_reldyn_size() const {
|
||||
if (tlsld_idx != -1)
|
||||
n++;
|
||||
|
||||
n += out::dynbss->symbols.size();
|
||||
n += out::dynbss_relro->symbols.size();
|
||||
n += ctx.dynbss->symbols.size();
|
||||
n += ctx.dynbss_relro->symbols.size();
|
||||
|
||||
return n * sizeof(ElfRela);
|
||||
}
|
||||
|
||||
// Fill .got and .rel.dyn.
|
||||
void GotSection::copy_buf() {
|
||||
u64 *buf = (u64 *)(out::buf + shdr.sh_offset);
|
||||
u64 *buf = (u64 *)(ctx.buf + shdr.sh_offset);
|
||||
memset(buf, 0, shdr.sh_size);
|
||||
|
||||
ElfRela *rel = (ElfRela *)(out::buf + out::reldyn->shdr.sh_offset);
|
||||
ElfRela *rel = (ElfRela *)(ctx.buf + ctx.reldyn->shdr.sh_offset);
|
||||
|
||||
for (Symbol *sym : got_syms) {
|
||||
u64 addr = sym->get_got_addr();
|
||||
@ -622,7 +629,7 @@ void GotSection::copy_buf() {
|
||||
*rel++ = {addr, R_X86_64_GLOB_DAT, sym->dynsym_idx, 0};
|
||||
} else {
|
||||
buf[sym->got_idx] = sym->get_addr();
|
||||
if (config.pic && sym->is_relative())
|
||||
if (ctx.arg.pic && sym->is_relative())
|
||||
*rel++ = {addr, R_X86_64_RELATIVE, 0, (i64)sym->get_addr()};
|
||||
}
|
||||
}
|
||||
@ -640,30 +647,30 @@ void GotSection::copy_buf() {
|
||||
if (sym->is_imported)
|
||||
*rel++ = {sym->get_gottpoff_addr(), R_X86_64_TPOFF64, sym->dynsym_idx, 0};
|
||||
else
|
||||
buf[sym->gottpoff_idx] = sym->get_addr() - out::tls_end;
|
||||
buf[sym->gottpoff_idx] = sym->get_addr() - ctx.tls_end;
|
||||
}
|
||||
|
||||
if (tlsld_idx != -1)
|
||||
*rel++ = {get_tlsld_addr(), R_X86_64_DTPMOD64, 0, 0};
|
||||
|
||||
for (Symbol *sym : out::dynbss->symbols)
|
||||
for (Symbol *sym : ctx.dynbss->symbols)
|
||||
*rel++ = {sym->get_addr(), R_X86_64_COPY, sym->dynsym_idx, 0};
|
||||
|
||||
for (Symbol *sym : out::dynbss_relro->symbols)
|
||||
for (Symbol *sym : ctx.dynbss_relro->symbols)
|
||||
*rel++ = {sym->get_addr(), R_X86_64_COPY, sym->dynsym_idx, 0};
|
||||
}
|
||||
|
||||
void GotPltSection::copy_buf() {
|
||||
u64 *buf = (u64 *)(out::buf + shdr.sh_offset);
|
||||
u64 *buf = (u64 *)(ctx.buf + shdr.sh_offset);
|
||||
|
||||
// The first slot of .got.plt points to _DYNAMIC, as requested by
|
||||
// the x86-64 psABI. The second and the third slots are reserved by
|
||||
// the psABI.
|
||||
buf[0] = out::dynamic ? out::dynamic->shdr.sh_addr : 0;
|
||||
buf[0] = ctx.dynamic ? ctx.dynamic->shdr.sh_addr : 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
|
||||
for (Symbol *sym : out::plt->symbols)
|
||||
for (Symbol *sym : ctx.plt->symbols)
|
||||
if (sym->gotplt_idx != -1)
|
||||
buf[sym->gotplt_idx] = sym->get_plt_addr() + 6;
|
||||
}
|
||||
@ -674,21 +681,21 @@ void PltSection::add_symbol(Symbol *sym) {
|
||||
|
||||
if (shdr.sh_size == 0) {
|
||||
shdr.sh_size = PLT_SIZE;
|
||||
out::gotplt->shdr.sh_size = GOT_SIZE * 3;
|
||||
ctx.gotplt->shdr.sh_size = GOT_SIZE * 3;
|
||||
}
|
||||
|
||||
sym->plt_idx = shdr.sh_size / PLT_SIZE;
|
||||
shdr.sh_size += PLT_SIZE;
|
||||
symbols.push_back(sym);
|
||||
|
||||
sym->gotplt_idx = out::gotplt->shdr.sh_size / GOT_SIZE;
|
||||
out::gotplt->shdr.sh_size += GOT_SIZE;
|
||||
out::relplt->shdr.sh_size += sizeof(ElfRela);
|
||||
out::dynsym->add_symbol(sym);
|
||||
sym->gotplt_idx = ctx.gotplt->shdr.sh_size / GOT_SIZE;
|
||||
ctx.gotplt->shdr.sh_size += GOT_SIZE;
|
||||
ctx.relplt->shdr.sh_size += sizeof(ElfRela);
|
||||
ctx.dynsym->add_symbol(sym);
|
||||
}
|
||||
|
||||
void PltSection::copy_buf() {
|
||||
u8 *buf = out::buf + shdr.sh_offset;
|
||||
u8 *buf = ctx.buf + shdr.sh_offset;
|
||||
|
||||
static const u8 plt0[] = {
|
||||
0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip)
|
||||
@ -697,8 +704,8 @@ void PltSection::copy_buf() {
|
||||
};
|
||||
|
||||
memcpy(buf, plt0, sizeof(plt0));
|
||||
*(u32 *)(buf + 2) = out::gotplt->shdr.sh_addr - shdr.sh_addr + 2;
|
||||
*(u32 *)(buf + 8) = out::gotplt->shdr.sh_addr - shdr.sh_addr + 4;
|
||||
*(u32 *)(buf + 2) = ctx.gotplt->shdr.sh_addr - shdr.sh_addr + 2;
|
||||
*(u32 *)(buf + 8) = ctx.gotplt->shdr.sh_addr - shdr.sh_addr + 4;
|
||||
|
||||
i64 relplt_idx = 0;
|
||||
|
||||
@ -727,7 +734,7 @@ void PltGotSection::add_symbol(Symbol *sym) {
|
||||
}
|
||||
|
||||
void PltGotSection::copy_buf() {
|
||||
u8 *buf = out::buf + shdr.sh_offset;
|
||||
u8 *buf = ctx.buf + shdr.sh_offset;
|
||||
|
||||
static const u8 data[] = {
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
@ -742,16 +749,16 @@ void PltGotSection::copy_buf() {
|
||||
}
|
||||
|
||||
void RelPltSection::update_shdr() {
|
||||
shdr.sh_link = out::dynsym->shndx;
|
||||
shdr.sh_link = ctx.dynsym->shndx;
|
||||
}
|
||||
|
||||
void RelPltSection::copy_buf() {
|
||||
ElfRela *buf = (ElfRela *)(out::buf + shdr.sh_offset);
|
||||
ElfRela *buf = (ElfRela *)(ctx.buf + shdr.sh_offset);
|
||||
memset(buf, 0, shdr.sh_size);
|
||||
|
||||
i64 relplt_idx = 0;
|
||||
|
||||
for (Symbol *sym : out::plt->symbols) {
|
||||
for (Symbol *sym : ctx.plt->symbols) {
|
||||
ElfRela &rel = buf[relplt_idx++];
|
||||
memset(&rel, 0, sizeof(rel));
|
||||
rel.r_sym = sym->dynsym_idx;
|
||||
@ -810,13 +817,13 @@ void DynsymSection::sort_symbols() {
|
||||
|
||||
// If we have .gnu.hash section, it imposes more constraints
|
||||
// on the order of symbols.
|
||||
if (out::gnu_hash) {
|
||||
if (ctx.gnu_hash) {
|
||||
i64 num_globals = vec.end() - first_global;
|
||||
out::gnu_hash->num_buckets = num_globals / out::gnu_hash->LOAD_FACTOR + 1;
|
||||
out::gnu_hash->symoffset = first_global - vec.begin();
|
||||
ctx.gnu_hash->num_buckets = num_globals / ctx.gnu_hash->LOAD_FACTOR + 1;
|
||||
ctx.gnu_hash->symoffset = first_global - vec.begin();
|
||||
|
||||
tbb::parallel_for_each(first_global, vec.end(), [](T &x) {
|
||||
x.hash = gnu_hash(x.sym->name) % out::gnu_hash->num_buckets;
|
||||
x.hash = gnu_hash(x.sym->name) % ctx.gnu_hash->num_buckets;
|
||||
});
|
||||
|
||||
tbb::parallel_sort(first_global, vec.end(), [&](const T &a, const T &b) {
|
||||
@ -824,24 +831,24 @@ void DynsymSection::sort_symbols() {
|
||||
});
|
||||
}
|
||||
|
||||
out::dynstr->dynsym_offset = out::dynstr->shdr.sh_size;
|
||||
ctx.dynstr->dynsym_offset = ctx.dynstr->shdr.sh_size;
|
||||
|
||||
for (i64 i = 1; i < symbols.size(); i++) {
|
||||
symbols[i] = vec[i].sym;
|
||||
symbols[i]->dynsym_idx = i;
|
||||
out::dynstr->shdr.sh_size += symbols[i]->name.size() + 1;
|
||||
ctx.dynstr->shdr.sh_size += symbols[i]->name.size() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void DynsymSection::update_shdr() {
|
||||
shdr.sh_link = out::dynstr->shndx;
|
||||
shdr.sh_link = ctx.dynstr->shndx;
|
||||
shdr.sh_size = sizeof(ElfSym) * symbols.size();
|
||||
}
|
||||
|
||||
void DynsymSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
memset(base, 0, sizeof(ElfSym));
|
||||
i64 name_offset = out::dynstr->dynsym_offset;
|
||||
i64 name_offset = ctx.dynstr->dynsym_offset;
|
||||
|
||||
for (i64 i = 1; i < symbols.size(); i++) {
|
||||
Symbol &sym = *symbols[i];
|
||||
@ -863,12 +870,12 @@ void DynsymSection::copy_buf() {
|
||||
|
||||
if (sym.has_copyrel) {
|
||||
esym.st_shndx = sym.copyrel_readonly
|
||||
? out::dynbss_relro->shndx : out::dynbss->shndx;
|
||||
? ctx.dynbss_relro->shndx : ctx.dynbss->shndx;
|
||||
esym.st_value = sym.get_addr();
|
||||
} else if (sym.file->is_dso || sym.esym->is_undef()) {
|
||||
esym.st_shndx = SHN_UNDEF;
|
||||
esym.st_size = 0;
|
||||
if (!config.shared && sym.plt_idx != -1 && sym.got_idx == -1) {
|
||||
if (!ctx.arg.shared && sym.plt_idx != -1 && sym.got_idx == -1) {
|
||||
// Emit an address for a canonical PLT
|
||||
esym.st_value = sym.get_plt_addr();
|
||||
}
|
||||
@ -877,7 +884,7 @@ void DynsymSection::copy_buf() {
|
||||
esym.st_value = sym.get_addr();
|
||||
} else if (sym.get_type() == STT_TLS) {
|
||||
esym.st_shndx = sym.input_section->output_section->shndx;
|
||||
esym.st_value = sym.get_addr() - out::tls_begin;
|
||||
esym.st_value = sym.get_addr() - ctx.tls_begin;
|
||||
} else {
|
||||
esym.st_shndx = sym.input_section->output_section->shndx;
|
||||
esym.st_value = sym.get_addr();
|
||||
@ -886,28 +893,28 @@ void DynsymSection::copy_buf() {
|
||||
}
|
||||
|
||||
void HashSection::update_shdr() {
|
||||
if (out::dynsym->symbols.empty())
|
||||
if (ctx.dynsym->symbols.empty())
|
||||
return;
|
||||
|
||||
i64 header_size = 8;
|
||||
i64 num_slots = out::dynsym->symbols.size();
|
||||
i64 num_slots = ctx.dynsym->symbols.size();
|
||||
shdr.sh_size = header_size + num_slots * 8;
|
||||
shdr.sh_link = out::dynsym->shndx;
|
||||
shdr.sh_link = ctx.dynsym->shndx;
|
||||
}
|
||||
|
||||
void HashSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
memset(base, 0, shdr.sh_size);
|
||||
|
||||
i64 num_slots = out::dynsym->symbols.size();
|
||||
i64 num_slots = ctx.dynsym->symbols.size();
|
||||
u32 *hdr = (u32 *)base;
|
||||
u32 *buckets = (u32 *)(base + 8);
|
||||
u32 *chains = buckets + num_slots;
|
||||
|
||||
hdr[0] = hdr[1] = num_slots;
|
||||
|
||||
for (i64 i = 1; i < out::dynsym->symbols.size(); i++) {
|
||||
Symbol *sym = out::dynsym->symbols[i];
|
||||
for (i64 i = 1; i < ctx.dynsym->symbols.size(); i++) {
|
||||
Symbol *sym = ctx.dynsym->symbols[i];
|
||||
i64 idx = elf_hash(sym->name) % num_slots;
|
||||
chains[sym->dynsym_idx] = buckets[idx];
|
||||
buckets[idx] = sym->dynsym_idx;
|
||||
@ -915,18 +922,18 @@ void HashSection::copy_buf() {
|
||||
}
|
||||
|
||||
void GnuHashSection::update_shdr() {
|
||||
if (out::dynsym->symbols.empty())
|
||||
if (ctx.dynsym->symbols.empty())
|
||||
return;
|
||||
|
||||
shdr.sh_link = out::dynsym->shndx;
|
||||
shdr.sh_link = ctx.dynsym->shndx;
|
||||
|
||||
if (i64 num_symbols = out::dynsym->symbols.size() - symoffset) {
|
||||
if (i64 num_symbols = ctx.dynsym->symbols.size() - symoffset) {
|
||||
// We allocate 12 bits for each symbol in the bloom filter.
|
||||
i64 num_bits = num_symbols * 12;
|
||||
num_bloom = next_power_of_two(num_bits / ELFCLASS_BITS);
|
||||
}
|
||||
|
||||
i64 num_symbols = out::dynsym->symbols.size() - symoffset;
|
||||
i64 num_symbols = ctx.dynsym->symbols.size() - symoffset;
|
||||
|
||||
shdr.sh_size = HEADER_SIZE; // Header
|
||||
shdr.sh_size += num_bloom * ELFCLASS_BITS / 8; // Bloom filter
|
||||
@ -935,7 +942,7 @@ void GnuHashSection::update_shdr() {
|
||||
}
|
||||
|
||||
void GnuHashSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
memset(base, 0, shdr.sh_size);
|
||||
|
||||
*(u32 *)base = num_buckets;
|
||||
@ -944,7 +951,7 @@ void GnuHashSection::copy_buf() {
|
||||
*(u32 *)(base + 12) = BLOOM_SHIFT;
|
||||
|
||||
std::span<Symbol *> symbols =
|
||||
std::span(out::dynsym->symbols).subspan(symoffset);
|
||||
std::span(ctx.dynsym->symbols).subspan(symoffset);
|
||||
|
||||
std::vector<u32> hashes(symbols.size());
|
||||
for (i64 i = 0; i < symbols.size(); i++)
|
||||
@ -1084,7 +1091,7 @@ void MergedSection::assign_offsets() {
|
||||
}
|
||||
|
||||
void MergedSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
|
||||
tbb::parallel_for((i64)0, NUM_SHARDS, [&](i64 i) {
|
||||
memset(base + shard_offsets[i], 0, shard_offsets[i + 1] - shard_offsets[i]);
|
||||
@ -1098,8 +1105,8 @@ void MergedSection::copy_buf() {
|
||||
void EhFrameSection::construct() {
|
||||
// Remove dead FDEs and assign them offsets within their corresponding
|
||||
// CIE group.
|
||||
tbb::parallel_for((i64)0, (i64)out::objs.size(), [&](i64 i) {
|
||||
ObjectFile *file = out::objs[i];
|
||||
tbb::parallel_for((i64)0, (i64)ctx.objs.size(), [&](i64 i) {
|
||||
ObjectFile *file = ctx.objs[i];
|
||||
i64 count = 0;
|
||||
|
||||
for (CieRecord &cie : file->cies) {
|
||||
@ -1116,8 +1123,8 @@ void EhFrameSection::construct() {
|
||||
});
|
||||
|
||||
// Aggreagate CIEs.
|
||||
cies.reserve(out::objs.size());
|
||||
for (ObjectFile *file : out::objs)
|
||||
cies.reserve(ctx.objs.size());
|
||||
for (ObjectFile *file : ctx.objs)
|
||||
for (CieRecord &cie : file->cies)
|
||||
cies.push_back(&cie);
|
||||
|
||||
@ -1147,17 +1154,17 @@ void EhFrameSection::construct() {
|
||||
}
|
||||
shdr.sh_size = offset;
|
||||
|
||||
if (out::eh_frame_hdr)
|
||||
out::eh_frame_hdr->shdr.sh_size =
|
||||
out::eh_frame_hdr->HEADER_SIZE + num_fdes * 8;
|
||||
if (ctx.eh_frame_hdr)
|
||||
ctx.eh_frame_hdr->shdr.sh_size =
|
||||
ctx.eh_frame_hdr->HEADER_SIZE + num_fdes * 8;
|
||||
}
|
||||
|
||||
void EhFrameSection::copy_buf() {
|
||||
u8 *base = out::buf + shdr.sh_offset;
|
||||
u8 *base = ctx.buf + shdr.sh_offset;
|
||||
|
||||
u8 *hdr_base = nullptr;
|
||||
if (out::eh_frame_hdr)
|
||||
hdr_base = out::buf + out::eh_frame_hdr->shdr.sh_offset;
|
||||
if (ctx.eh_frame_hdr)
|
||||
hdr_base = ctx.buf + ctx.eh_frame_hdr->shdr.sh_offset;
|
||||
|
||||
auto apply_reloc = [&](EhReloc &rel, u64 loc, u64 val) {
|
||||
switch (rel.type) {
|
||||
@ -1187,8 +1194,8 @@ void EhFrameSection::copy_buf() {
|
||||
i64 cie_size = 0;
|
||||
|
||||
Entry *entry = nullptr;
|
||||
if (out::eh_frame_hdr)
|
||||
entry = (Entry *)(hdr_base + out::eh_frame_hdr->HEADER_SIZE) +
|
||||
if (ctx.eh_frame_hdr)
|
||||
entry = (Entry *)(hdr_base + ctx.eh_frame_hdr->HEADER_SIZE) +
|
||||
cie->fde_idx;
|
||||
|
||||
// Copy a CIE.
|
||||
@ -1219,18 +1226,18 @@ void EhFrameSection::copy_buf() {
|
||||
apply_reloc(rel, loc, val);
|
||||
|
||||
// Write to .eh_frame_hdr
|
||||
if (out::eh_frame_hdr && i == 0) {
|
||||
if (ctx.eh_frame_hdr && i == 0) {
|
||||
assert(rel.offset == 8);
|
||||
entry->init_addr = val - out::eh_frame_hdr->shdr.sh_addr;
|
||||
entry->init_addr = val - ctx.eh_frame_hdr->shdr.sh_addr;
|
||||
entry->fde_addr =
|
||||
shdr.sh_addr + fde_off - out::eh_frame_hdr->shdr.sh_addr;
|
||||
shdr.sh_addr + fde_off - ctx.eh_frame_hdr->shdr.sh_addr;
|
||||
entry++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (out::eh_frame_hdr) {
|
||||
if (ctx.eh_frame_hdr) {
|
||||
// Write .eh_frame_hdr header
|
||||
hdr_base[0] = 1;
|
||||
hdr_base[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
|
||||
@ -1238,11 +1245,11 @@ void EhFrameSection::copy_buf() {
|
||||
hdr_base[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
|
||||
|
||||
*(u32 *)(hdr_base + 4) =
|
||||
shdr.sh_addr - out::eh_frame_hdr->shdr.sh_addr - 4;
|
||||
shdr.sh_addr - ctx.eh_frame_hdr->shdr.sh_addr - 4;
|
||||
*(u32 *)(hdr_base + 8) = num_fdes;
|
||||
|
||||
// Sort .eh_frame_hdr contents
|
||||
Entry *begin = (Entry *)(hdr_base + out::eh_frame_hdr->HEADER_SIZE);
|
||||
Entry *begin = (Entry *)(hdr_base + ctx.eh_frame_hdr->HEADER_SIZE);
|
||||
Entry *end = begin + num_fdes;
|
||||
|
||||
tbb::parallel_sort(begin, end, [](const Entry &a, const Entry &b) {
|
||||
@ -1297,7 +1304,7 @@ void DynbssSection::add_symbol(Symbol *sym) {
|
||||
if (sym->has_copyrel)
|
||||
return;
|
||||
|
||||
assert(!config.shared);
|
||||
assert(!ctx.arg.shared);
|
||||
assert(sym->file->is_dso);
|
||||
|
||||
shdr.sh_size = align_to(shdr.sh_size, shdr.sh_addralign);
|
||||
@ -1305,45 +1312,45 @@ void DynbssSection::add_symbol(Symbol *sym) {
|
||||
sym->has_copyrel = true;
|
||||
shdr.sh_size += sym->esym->st_size;
|
||||
symbols.push_back(sym);
|
||||
out::dynsym->add_symbol(sym);
|
||||
ctx.dynsym->add_symbol(sym);
|
||||
}
|
||||
|
||||
void VersymSection::update_shdr() {
|
||||
shdr.sh_size = contents.size() * sizeof(contents[0]);
|
||||
shdr.sh_link = out::dynsym->shndx;
|
||||
shdr.sh_link = ctx.dynsym->shndx;
|
||||
}
|
||||
|
||||
void VersymSection::copy_buf() {
|
||||
write_vector(out::buf + shdr.sh_offset, contents);
|
||||
write_vector(ctx.buf + shdr.sh_offset, contents);
|
||||
}
|
||||
|
||||
void VerneedSection::update_shdr() {
|
||||
shdr.sh_size = contents.size();
|
||||
shdr.sh_link = out::dynstr->shndx;
|
||||
shdr.sh_link = ctx.dynstr->shndx;
|
||||
}
|
||||
|
||||
void VerneedSection::copy_buf() {
|
||||
write_vector(out::buf + shdr.sh_offset, contents);
|
||||
write_vector(ctx.buf + shdr.sh_offset, contents);
|
||||
}
|
||||
|
||||
void VerdefSection::update_shdr() {
|
||||
shdr.sh_size = contents.size();
|
||||
shdr.sh_link = out::dynstr->shndx;
|
||||
shdr.sh_link = ctx.dynstr->shndx;
|
||||
}
|
||||
|
||||
void VerdefSection::copy_buf() {
|
||||
write_vector(out::buf + shdr.sh_offset, contents);
|
||||
write_vector(ctx.buf + shdr.sh_offset, contents);
|
||||
}
|
||||
|
||||
void BuildIdSection::update_shdr() {
|
||||
shdr.sh_size = HEADER_SIZE + config.build_id.size();
|
||||
shdr.sh_size = HEADER_SIZE + ctx.arg.build_id.size();
|
||||
}
|
||||
|
||||
void BuildIdSection::copy_buf() {
|
||||
u32 *base = (u32 *)(out::buf + shdr.sh_offset);
|
||||
u32 *base = (u32 *)(ctx.buf + shdr.sh_offset);
|
||||
memset(base, 0, shdr.sh_size);
|
||||
base[0] = 4; // Name size
|
||||
base[1] = config.build_id.size(); // Hash size
|
||||
base[1] = ctx.arg.build_id.size(); // Hash size
|
||||
base[2] = NT_GNU_BUILD_ID; // Type
|
||||
memcpy(base + 3, "GNU", 4); // Name string
|
||||
}
|
||||
@ -1363,10 +1370,10 @@ static void compute_sha256(u8 *buf, i64 size, u8 *digest) {
|
||||
}
|
||||
|
||||
void BuildIdSection::write_buildid(i64 filesize) {
|
||||
switch (config.build_id.kind) {
|
||||
switch (ctx.arg.build_id.kind) {
|
||||
case BuildId::HEX:
|
||||
write_vector(out::buf + shdr.sh_offset + HEADER_SIZE,
|
||||
config.build_id.value);
|
||||
write_vector(ctx.buf + shdr.sh_offset + HEADER_SIZE,
|
||||
ctx.arg.build_id.value);
|
||||
return;
|
||||
case BuildId::HASH: {
|
||||
// Modern x86 processors have purpose-built instructions to accelerate
|
||||
@ -1374,15 +1381,15 @@ void BuildIdSection::write_buildid(i64 filesize) {
|
||||
// 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());
|
||||
assert(ctx.arg.build_id.size() <= SHA256_SIZE);
|
||||
compute_sha256(ctx.buf, filesize, digest);
|
||||
memcpy(ctx.buf + shdr.sh_offset + HEADER_SIZE, digest,
|
||||
ctx.arg.build_id.size());
|
||||
return;
|
||||
}
|
||||
case BuildId::UUID:
|
||||
if (!RAND_bytes(out::buf + shdr.sh_offset + HEADER_SIZE,
|
||||
config.build_id.size()))
|
||||
if (!RAND_bytes(ctx.buf + shdr.sh_offset + HEADER_SIZE,
|
||||
ctx.arg.build_id.size()))
|
||||
Fatal() << "RAND_bytes failed";
|
||||
return;
|
||||
}
|
||||
|
@ -16,22 +16,22 @@ class MemoryMappedOutputFile : public OutputFile {
|
||||
public:
|
||||
MemoryMappedOutputFile(std::string path, i64 filesize)
|
||||
: OutputFile(path, filesize) {
|
||||
std::string dir = dirname(strdup(config.output.c_str()));
|
||||
std::string dir = dirname(strdup(ctx.arg.output.c_str()));
|
||||
tmpfile = strdup((dir + "/.mold-XXXXXX").c_str());
|
||||
i64 fd = mkstemp(tmpfile);
|
||||
if (fd == -1)
|
||||
Fatal() << "cannot open " << tmpfile << ": " << strerror(errno);
|
||||
|
||||
if (rename(config.output.c_str(), tmpfile) == 0) {
|
||||
if (rename(ctx.arg.output.c_str(), tmpfile) == 0) {
|
||||
::close(fd);
|
||||
fd = ::open(tmpfile, O_RDWR | O_CREAT, 0777);
|
||||
if (fd == -1) {
|
||||
if (errno != ETXTBSY)
|
||||
Fatal() << "cannot open " << config.output << ": " << strerror(errno);
|
||||
Fatal() << "cannot open " << ctx.arg.output << ": " << strerror(errno);
|
||||
unlink(tmpfile);
|
||||
fd = ::open(tmpfile, O_RDWR | O_CREAT, 0777);
|
||||
if (fd == -1)
|
||||
Fatal() << "cannot open " << config.output << ": " << strerror(errno);
|
||||
Fatal() << "cannot open " << ctx.arg.output << ": " << strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,15 +43,15 @@ public:
|
||||
|
||||
buf = (u8 *)mmap(nullptr, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (buf == MAP_FAILED)
|
||||
Fatal() << config.output << ": mmap failed: " << strerror(errno);
|
||||
Fatal() << ctx.arg.output << ": mmap failed: " << strerror(errno);
|
||||
::close(fd);
|
||||
}
|
||||
|
||||
void close() override {
|
||||
Timer t("close_file");
|
||||
munmap(buf, filesize);
|
||||
if (rename(tmpfile, config.output.c_str()) == -1)
|
||||
Fatal() << config.output << ": rename filed: " << strerror(errno);
|
||||
if (rename(tmpfile, ctx.arg.output.c_str()) == -1)
|
||||
Fatal() << ctx.arg.output << ": rename filed: " << strerror(errno);
|
||||
tmpfile = nullptr;
|
||||
}
|
||||
};
|
||||
@ -70,7 +70,7 @@ public:
|
||||
Timer t("close_file");
|
||||
i64 fd = ::open(path.c_str(), O_RDWR | O_CREAT, 0777);
|
||||
if (fd == -1)
|
||||
Fatal() << "cannot open " << config.output << ": " << strerror(errno);
|
||||
Fatal() << "cannot open " << ctx.arg.output << ": " << strerror(errno);
|
||||
|
||||
FILE *fp = fdopen(fd, "w");
|
||||
fwrite(buf, filesize, 1, fp);
|
||||
@ -92,7 +92,7 @@ OutputFile *OutputFile::open(std::string path, u64 filesize) {
|
||||
else
|
||||
file = new MemoryMappedOutputFile(path, filesize);
|
||||
|
||||
if (config.filler != -1)
|
||||
memset(file->buf, config.filler, filesize);
|
||||
if (ctx.arg.filler != -1)
|
||||
memset(file->buf, ctx.arg.filler, filesize);
|
||||
return file;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ std::string_view Symbol::get_demangled_name() const {
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Symbol &sym) {
|
||||
if (config.demangle)
|
||||
if (ctx.arg.demangle)
|
||||
out << sym.get_demangled_name();
|
||||
else
|
||||
out << sym.name;
|
||||
|
Loading…
Reference in New Issue
Block a user