1
1
mirror of https://github.com/rui314/mold.git synced 2024-09-22 02:20:51 +03:00
This commit is contained in:
Rui Ueyama 2021-03-29 13:20:51 +09:00
parent 48759ed6b5
commit 244cc6cb28
12 changed files with 889 additions and 877 deletions

View File

@ -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";
}

View File

@ -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
View File

@ -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;

View File

@ -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;

View File

@ -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), ";");
}

419
main.cc

File diff suppressed because it is too large Load Diff

View File

@ -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
View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View 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;