From b8bc50fbb6a1011c088cb13875e7d9cae173cf70 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sun, 15 Nov 2020 13:01:38 +0900 Subject: [PATCH] temporary --- main.cc | 178 ++++++++++++++++++++++++++++------------------- mold.h | 64 ++++++++++++++--- object_file.cc | 6 -- output_chunks.cc | 31 ++++++--- 4 files changed, 181 insertions(+), 98 deletions(-) diff --git a/main.cc b/main.cc index f62b8d82..cc6ff1d6 100644 --- a/main.cc +++ b/main.cc @@ -333,103 +333,144 @@ static void set_isec_offsets() { static void scan_rels(ArrayRef files) { MyTimer t("scan_rels", before_copy_timer); - tbb::parallel_for_each(files, [&](ObjectFile *file) { file->scan_relocations(); }); + tbb::parallel_for_each(files, [&](ObjectFile *file) { + for (InputSection *isec : file->sections) + if (isec) + isec->scan_relocations(); + }); + + tbb::parallel_for_each(files, [&](ObjectFile *file) { + for (Symbol *sym : file->symbols) { + if (sym->file != file) + continue; + + u8 rels = sym->rels.load(std::memory_order_relaxed); + + if (rels & Symbol::HAS_GOT_REL) { + sym->got_idx = file->num_got++; + file->num_reldyn++; + sym->needs_dynsym = true; + } + + if (rels & Symbol::HAS_PLT_REL) { + sym->plt_idx = file->num_plt++; + sym->needs_dynsym = true; + + if (sym->got_idx == -1) { + sym->gotplt_idx = file->num_gotplt++; + sym->relplt_idx = file->num_relplt++; + } + } + + if (rels & Symbol::HAS_GOTGD_REL) { + sym->gotgd_idx = file->num_got; + file->num_got += 2; + file->num_reldyn += 2; + sym->needs_dynsym = true; + } + + if (rels & Symbol::HAS_GOTLD_REL) { + sym->gotgd_idx = file->num_got++; + file->num_reldyn++; + sym->needs_dynsym = true; + } + + if (rels & Symbol::HAS_GOTTP_REL) + sym->gottp_idx = file->num_got++; + + if (sym->needs_dynsym) + file->num_dynsym++; + } + }); for (ObjectFile *file : files) { + file->got_offset = out::got->shdr.sh_size; out::got->shdr.sh_size += file->num_got * GOT_SIZE; file->gotplt_offset = out::gotplt->shdr.sh_size; - out::gotplt->shdr.sh_size += file->num_plt * GOT_SIZE; + out::gotplt->shdr.sh_size += file->num_gotplt * GOT_SIZE; file->plt_offset = out::plt->shdr.sh_size; out::plt->shdr.sh_size += file->num_plt * PLT_SIZE; file->relplt_offset = out::relplt->shdr.sh_size; - out::relplt->shdr.sh_size += file->num_plt * sizeof(ELF64LE::Rela); + out::relplt->shdr.sh_size += file->num_relplt * sizeof(ELF64LE::Rela); - if (out::dynsym) { - file->dynsym_offset = out::dynsym->shdr.sh_size; - out::dynsym->shdr.sh_size += file->num_dynsym * sizeof(ELF64LE::Sym); - } + file->reldyn_offset = out::reldyn->shdr.sh_size; + out::reldyn->shdr.sh_size += file->num_reldyn * sizeof(ELF64LE::Rela); - if (out::dynstr) { - file->dynstr_offset = out::dynstr->shdr.sh_size; - out::dynstr->shdr.sh_size += file->dynstr_size; - } + file->dynsym_offset = out::dynsym->shdr.sh_size; + out::dynsym->shdr.sh_size += file->num_dynsym * sizeof(ELF64LE::Sym); + + file->dynstr_offset = out::dynstr->shdr.sh_size; + out::dynstr->shdr.sh_size += file->dynstr_size; } } -static void assign_got_offsets(ArrayRef files) { - MyTimer t("assign_got_offsets", before_copy_timer); - - tbb::parallel_for_each(files, [&](ObjectFile *file) { - u32 got_offset = file->got_offset; - u32 gotplt_offset = file->gotplt_offset; - u32 plt_offset = file->plt_offset; - u32 relplt_offset = file->relplt_offset; - u32 dynsym_offset = file->dynsym_offset; - - for (Symbol *sym : file->symbols) { - if (sym->file != file) - continue; - - u8 flags = sym->flags.load(std::memory_order_relaxed); - - if (flags & Symbol::NEEDS_GOT) { - sym->got_offset = got_offset; - got_offset += GOT_SIZE; - } - - if (flags & Symbol::NEEDS_GOTTP) { - sym->gottp_offset = got_offset; - got_offset += GOT_SIZE; - } - - if (flags & Symbol::NEEDS_PLT) { - sym->gotplt_offset = gotplt_offset; - gotplt_offset += GOT_SIZE; - - sym->plt_offset = plt_offset; - plt_offset += PLT_SIZE; - - sym->relplt_offset = relplt_offset; - relplt_offset += sizeof(ELF64LE::Rela); - } - - if (flags & Symbol::NEEDS_DYNSYM) { - sym->dynsym_offset = dynsym_offset; - dynsym_offset += sizeof(ELF64LE::Sym); - } - } - }); +static void write_dynamic_rel(u8 *buf, u8 type, u64 offset, u64 addend) { + ELF64LE::Rela *rel = (ELF64LE::Rela *)buf; + memset(rel, 0, sizeof(*rel)); + rel->setType(type, false); + rel->r_offset = offset; + rel->r_addend = addend; } static void write_got(u8 *buf, ArrayRef files) { MyTimer t("write_synthetic", copy_timer); - u8 *got_buf = buf + out::got->shdr.sh_offset; - u8 *gotplt_buf = buf + out::gotplt->shdr.sh_offset; - u8 *relplt_buf = buf + out::relplt->shdr.sh_offset; - u8 *dynsym_buf = buf + out::dynsym->shdr.sh_offset; - u8 *dynstr_buf = buf + out::dynstr->shdr.sh_offset; - tbb::parallel_for_each(files, [&](ObjectFile *file) { - u32 dynstr_offset = file->dynstr_offset; + u8 *got_buf = buf + out::got->shdr.sh_offset + file->got_offset; + u8 *gotplt_buf = buf + out::gotplt->shdr.sh_offset + file->gotplt_offset; + u8 *plt_buf = buf + out::plt->shdr.sh_offset + file->plt_offset; + u8 *relplt_buf = buf + out::relplt->shdr.sh_offset + file->relplt_offset; + u8 *reldyn_buf = buf + out::reldyn->shdr.sh_offset + file->reldyn_offset; + u8 *dynsym_buf = buf + out::dynsym->shdr.sh_offset + file->dynsym_offset; + u8 *dynstr_buf = buf + out::dynstr->shdr.sh_offset + file->dynstr_offset; + + int reldyn_idx = 0; for (Symbol *sym : file->symbols) { if (sym->file != file) continue; - u8 flags = sym->flags.load(std::memory_order_relaxed); + if (got_idx != -1) { + *(u64 *)(got_buf + sym->got_idx * GOT_SIZE) = sym->get_addr(); + write_dynamic_rel(reldyn_buf + reldyn_idx++ * sizeof(ELF64LE::Rela), + R_X86_64_GLOB_DAT, sym->get_got_addr(), 0); + } - if (flags & Symbol::NEEDS_GOT) + if (sym->gottp_idx != -1) + *(u64 *)(got_buf + sym->gottp_idx * GOT_SIZE) = sym->get_addr() - out::tls_end; + + if (sym->gotgd_idx != -1) + error("unimplemented"); + + if (sym->gotld_idx != -1) + error("unimplemented"); + + if (sym->plt_idx != -1) + out::plt->write_entry(buf, sym); + + if (sym->relplt_idx != -1) { + if (sym->type == STT_GNU_IFUNC) + write_dynamic_rel(relplt_buf + sym->relplt_idx * sizeof(ELF64LE::Rela), + R_X86_64_IRELATIVE, sym->get_plt_addr(), 0); + else + write_dynamic_rel(relplt_buf + sym->relplt_idx * sizeof(ELF64LE::Rela), + R_X86_64_JUMP_SLOT, sym->get_plt_addr(), 0); + } + + + if (rels & Symbol::NEEDS_GOT) *(u64 *)(got_buf + sym->got_offset) = sym->get_addr(); - if (flags & Symbol::NEEDS_GOTTP) - *(u64 *)(got_buf + sym->gottp_offset) = sym->get_addr() - out::tls_end; + if (rels & Symbol::NEEDS_GOTTP) - if (flags & Symbol::NEEDS_PLT) { + + + + if (rels & Symbol::NEEDS_PLT) { // Write a .plt entry u64 S = out::gotplt->shdr.sh_addr + sym->gotplt_offset; u64 P = out::plt->shdr.sh_addr + sym->plt_offset; @@ -451,7 +492,7 @@ static void write_got(u8 *buf, ArrayRef files) { } } - if (flags & Symbol::NEEDS_DYNSYM) { + if (rels & Symbol::NEEDS_DYNSYM) { // Write to .dynsym auto &esym = *(ELF64LE::Sym *)(dynsym_buf + sym->dynsym_offset); memset(&esym, 0, sizeof(esym)); @@ -1134,9 +1175,6 @@ int main(int argc, char **argv) { // Assign offsets to output sections u64 filesize = set_osec_offsets(chunks); - // Assign symbols to GOT offsets - assign_got_offsets(files); - // Fix linker-synthesized symbol addresses. fix_synthetic_symbols(chunks); diff --git a/mold.h b/mold.h index 0ee70219..18f327fd 100644 --- a/mold.h +++ b/mold.h @@ -187,6 +187,12 @@ public: } inline u64 get_addr() const; + inline u64 get_got_addr() const; + inline u64 get_gotplt_addr() const; + inline u64 get_gottp_addr() const; + inline u64 get_gotgd_addr() const; + inline u64 get_gotld_addr() const; + inline u64 get_plt_addr() const; StringRef name; ObjectFile *file = nullptr; @@ -194,12 +200,15 @@ public: StringPieceRef piece_ref; u64 value = 0; - u32 got_offset = 0; - u32 gotplt_offset = 0; - u32 gottp_offset = 0; - u32 plt_offset = 0; - u32 relplt_offset = 0; - u32 dynsym_offset = 0; + u32 got_idx = -1; + u32 gotplt_idx = -1; + u32 gottp_idx = -1; + u32 gotgd_idx = -1; + u32 gotld_idx = -1; + u32 plt_idx = -1; + u32 relplt_idx = -1; + u32 dynsym_offset = -1; + bool needs_dynsym = false; u32 shndx = 0; @@ -528,6 +537,36 @@ inline u64 Symbol::get_addr() const { return value; } +inline u64 Symbol::get_got_addr() const { + assert(got_idx != -1); + return out::got->shdr.sh_addr + sym->file->got_offset + got_idx * GOT_SIZE; +} + +inline u64 Symbol::get_gotplt_addr() const { + assert(gotplt_idx != -1); + return out::gotplt->shdr.sh_addr + sym->file->gotplt_offset + gotplt_idx * GOT_SIZE; +} + +inline u64 Symbol::get_gottp_addr() const { + assert(gottp_idx != -1); + return out::got->shdr.sh_addr + sym->file->got_offset + gottp_idx * GOT_SIZE; +} + +inline u64 Symbol::get_gotgd_addr() const { + assert(gotgd_idx != -1); + return out::got->shdr.sh_addr + sym->file->got_offset + gotgd_idx * GOT_SIZE; +} + +inline u64 Symbol::get_gotld_addr() const { + assert(gotld_idx != -1); + return out::got->shdr.sh_addr + sym->file->got_offset + gotld_idx * GOT_SIZE; +} + +inline u64 Symbol::get_plt_addr() const { + assert(plt_idx != -1); + return out::plt->shdr.sh_addr + sym->file->plt_offset + plt_idx * PLT_SIZE; +} + inline u64 StringPiece::get_addr() const { MergeableSection *is = isec.load(); return is->parent.shdr.sh_addr + is->offset + output_offset; @@ -565,7 +604,6 @@ public: void eliminate_duplicate_comdat_groups(); void assign_mergeable_string_offsets(); void convert_common_symbols(); - void scan_relocations(); void compute_symtab(); void write_local_symtab(u8 *buf, u64 symtab_off, u64 strtab_off); @@ -591,15 +629,19 @@ public: u64 global_symtab_size = 0; u64 global_strtab_size = 0; - std::atomic_uint32_t num_got = ATOMIC_VAR_INIT(0); - std::atomic_uint32_t num_plt = ATOMIC_VAR_INIT(0); - std::atomic_uint32_t num_dynsym = ATOMIC_VAR_INIT(0); - std::atomic_uint32_t dynstr_size = ATOMIC_VAR_INIT(0); + u32 num_got = 0; + u32 num_gotplt = 0; + u32 num_plt = 0; + u32 num_relplt = 0; + u32 num_reldyn = 0; + u32 num_dynsym = 0; + u32 dynstr_size = 0; u32 got_offset = 0; u32 gotplt_offset = 0; u32 plt_offset = 0; u32 relplt_offset = 0; + u32 reldyn_offset = 0; u32 dynsym_offset = 0; u32 dynstr_offset = 0; diff --git a/object_file.cc b/object_file.cc index e62108bb..6278f5a1 100644 --- a/object_file.cc +++ b/object_file.cc @@ -473,12 +473,6 @@ void ObjectFile::convert_common_symbols() { } } -void ObjectFile::scan_relocations() { - for (InputSection *isec : sections) - if (isec) - isec->scan_relocations(); -} - void ObjectFile::compute_symtab() { for (int i = first_global; i < elf_syms.size(); i++) { const ELF64LE::Sym &esym = elf_syms[i]; diff --git a/output_chunks.cc b/output_chunks.cc index e3f51b83..98da22f2 100644 --- a/output_chunks.cc +++ b/output_chunks.cc @@ -92,19 +92,28 @@ void PltSection::initialize(u8 *buf) { } void PltSection::write_entry(u8 *buf, Symbol *sym) { - const u8 data[] = { - 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT - 0x68, 0, 0, 0, 0, // push $index_in_relplt - 0xe9, 0, 0, 0, 0, // jmp PLT[0] - }; + if (sym->got_idx == -1) { + const u8 data[] = { + 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT + 0x68, 0, 0, 0, 0, // push $index_in_relplt + 0xe9, 0, 0, 0, 0, // jmp PLT[0] + }; - u64 entry_addr = shdr.sh_addr + sym->plt_offset; + u8 *base = buf + shdr.sh_offset + sym->plt_offset; + memcpy(base, data, sizeof(data)); + *(u32 *)(base + 2) = sym->get_gotplt_addr() - sym->get_plt_addr() - 6; + *(u32 *)(base + 7) = sym->relplt_idx; + *(u32 *)(base + 12) = shdr.sh_addr - sym->get_plt_addr() - 16; + } else { + const u8 data[] = { + 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT + 0x66, 0x66, 0x66, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nop + }; - u8 *base = buf + shdr.sh_offset + sym->plt_offset; - memcpy(base, data, sizeof(data)); - *(u32 *)(base + 2) = out::gotplt->shdr.sh_addr + sym->gotplt_offset - entry_addr - 6; - *(u32 *)(base + 7) = sym->plt_offset / PLT_SIZE; - *(u32 *)(base + 12) = shdr.sh_addr - entry_addr - 16; + u8 *base = buf + shdr.sh_offset + sym->plt_offset; + memcpy(base, data, sizeof(data)); + *(u32 *)(base + 2) = sym->get_got_addr() - sym->get_plt_addr() - 6; + } } MergedSection *