1
1
mirror of https://github.com/rui314/mold.git synced 2024-12-27 10:23:41 +03:00

temporary

This commit is contained in:
Rui Ueyama 2020-11-15 13:01:38 +09:00
parent 1e469bfb10
commit b8bc50fbb6
4 changed files with 181 additions and 98 deletions

170
main.cc
View File

@ -333,103 +333,144 @@ static void set_isec_offsets() {
static void scan_rels(ArrayRef<ObjectFile *> files) { static void scan_rels(ArrayRef<ObjectFile *> files) {
MyTimer t("scan_rels", before_copy_timer); 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) { for (ObjectFile *file : files) {
file->got_offset = out::got->shdr.sh_size; file->got_offset = out::got->shdr.sh_size;
out::got->shdr.sh_size += file->num_got * GOT_SIZE; out::got->shdr.sh_size += file->num_got * GOT_SIZE;
file->gotplt_offset = out::gotplt->shdr.sh_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; file->plt_offset = out::plt->shdr.sh_size;
out::plt->shdr.sh_size += file->num_plt * PLT_SIZE; out::plt->shdr.sh_size += file->num_plt * PLT_SIZE;
file->relplt_offset = out::relplt->shdr.sh_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);
file->reldyn_offset = out::reldyn->shdr.sh_size;
out::reldyn->shdr.sh_size += file->num_reldyn * sizeof(ELF64LE::Rela);
if (out::dynsym) {
file->dynsym_offset = out::dynsym->shdr.sh_size; file->dynsym_offset = out::dynsym->shdr.sh_size;
out::dynsym->shdr.sh_size += file->num_dynsym * sizeof(ELF64LE::Sym); out::dynsym->shdr.sh_size += file->num_dynsym * sizeof(ELF64LE::Sym);
}
if (out::dynstr) {
file->dynstr_offset = out::dynstr->shdr.sh_size; file->dynstr_offset = out::dynstr->shdr.sh_size;
out::dynstr->shdr.sh_size += file->dynstr_size; out::dynstr->shdr.sh_size += file->dynstr_size;
} }
} }
}
static void assign_got_offsets(ArrayRef<ObjectFile *> files) { static void write_dynamic_rel(u8 *buf, u8 type, u64 offset, u64 addend) {
MyTimer t("assign_got_offsets", before_copy_timer); ELF64LE::Rela *rel = (ELF64LE::Rela *)buf;
memset(rel, 0, sizeof(*rel));
tbb::parallel_for_each(files, [&](ObjectFile *file) { rel->setType(type, false);
u32 got_offset = file->got_offset; rel->r_offset = offset;
u32 gotplt_offset = file->gotplt_offset; rel->r_addend = addend;
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_got(u8 *buf, ArrayRef<ObjectFile *> files) { static void write_got(u8 *buf, ArrayRef<ObjectFile *> files) {
MyTimer t("write_synthetic", copy_timer); 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) { 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) { for (Symbol *sym : file->symbols) {
if (sym->file != file) if (sym->file != file)
continue; 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(); *(u64 *)(got_buf + sym->got_offset) = sym->get_addr();
if (flags & Symbol::NEEDS_GOTTP) if (rels & Symbol::NEEDS_GOTTP)
*(u64 *)(got_buf + sym->gottp_offset) = sym->get_addr() - out::tls_end;
if (flags & Symbol::NEEDS_PLT) {
if (rels & Symbol::NEEDS_PLT) {
// Write a .plt entry // Write a .plt entry
u64 S = out::gotplt->shdr.sh_addr + sym->gotplt_offset; u64 S = out::gotplt->shdr.sh_addr + sym->gotplt_offset;
u64 P = out::plt->shdr.sh_addr + sym->plt_offset; u64 P = out::plt->shdr.sh_addr + sym->plt_offset;
@ -451,7 +492,7 @@ static void write_got(u8 *buf, ArrayRef<ObjectFile *> files) {
} }
} }
if (flags & Symbol::NEEDS_DYNSYM) { if (rels & Symbol::NEEDS_DYNSYM) {
// Write to .dynsym // Write to .dynsym
auto &esym = *(ELF64LE::Sym *)(dynsym_buf + sym->dynsym_offset); auto &esym = *(ELF64LE::Sym *)(dynsym_buf + sym->dynsym_offset);
memset(&esym, 0, sizeof(esym)); memset(&esym, 0, sizeof(esym));
@ -1134,9 +1175,6 @@ int main(int argc, char **argv) {
// Assign offsets to output sections // Assign offsets to output sections
u64 filesize = set_osec_offsets(chunks); u64 filesize = set_osec_offsets(chunks);
// Assign symbols to GOT offsets
assign_got_offsets(files);
// Fix linker-synthesized symbol addresses. // Fix linker-synthesized symbol addresses.
fix_synthetic_symbols(chunks); fix_synthetic_symbols(chunks);

64
mold.h
View File

@ -187,6 +187,12 @@ public:
} }
inline u64 get_addr() const; 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; StringRef name;
ObjectFile *file = nullptr; ObjectFile *file = nullptr;
@ -194,12 +200,15 @@ public:
StringPieceRef piece_ref; StringPieceRef piece_ref;
u64 value = 0; u64 value = 0;
u32 got_offset = 0; u32 got_idx = -1;
u32 gotplt_offset = 0; u32 gotplt_idx = -1;
u32 gottp_offset = 0; u32 gottp_idx = -1;
u32 plt_offset = 0; u32 gotgd_idx = -1;
u32 relplt_offset = 0; u32 gotld_idx = -1;
u32 dynsym_offset = 0; u32 plt_idx = -1;
u32 relplt_idx = -1;
u32 dynsym_offset = -1;
bool needs_dynsym = false;
u32 shndx = 0; u32 shndx = 0;
@ -528,6 +537,36 @@ inline u64 Symbol::get_addr() const {
return value; 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 { inline u64 StringPiece::get_addr() const {
MergeableSection *is = isec.load(); MergeableSection *is = isec.load();
return is->parent.shdr.sh_addr + is->offset + output_offset; return is->parent.shdr.sh_addr + is->offset + output_offset;
@ -565,7 +604,6 @@ public:
void eliminate_duplicate_comdat_groups(); void eliminate_duplicate_comdat_groups();
void assign_mergeable_string_offsets(); void assign_mergeable_string_offsets();
void convert_common_symbols(); void convert_common_symbols();
void scan_relocations();
void compute_symtab(); void compute_symtab();
void write_local_symtab(u8 *buf, u64 symtab_off, u64 strtab_off); void write_local_symtab(u8 *buf, u64 symtab_off, u64 strtab_off);
@ -591,15 +629,19 @@ public:
u64 global_symtab_size = 0; u64 global_symtab_size = 0;
u64 global_strtab_size = 0; u64 global_strtab_size = 0;
std::atomic_uint32_t num_got = ATOMIC_VAR_INIT(0); u32 num_got = 0;
std::atomic_uint32_t num_plt = ATOMIC_VAR_INIT(0); u32 num_gotplt = 0;
std::atomic_uint32_t num_dynsym = ATOMIC_VAR_INIT(0); u32 num_plt = 0;
std::atomic_uint32_t dynstr_size = ATOMIC_VAR_INIT(0); u32 num_relplt = 0;
u32 num_reldyn = 0;
u32 num_dynsym = 0;
u32 dynstr_size = 0;
u32 got_offset = 0; u32 got_offset = 0;
u32 gotplt_offset = 0; u32 gotplt_offset = 0;
u32 plt_offset = 0; u32 plt_offset = 0;
u32 relplt_offset = 0; u32 relplt_offset = 0;
u32 reldyn_offset = 0;
u32 dynsym_offset = 0; u32 dynsym_offset = 0;
u32 dynstr_offset = 0; u32 dynstr_offset = 0;

View File

@ -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() { void ObjectFile::compute_symtab() {
for (int i = first_global; i < elf_syms.size(); i++) { for (int i = first_global; i < elf_syms.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i]; const ELF64LE::Sym &esym = elf_syms[i];

View File

@ -92,19 +92,28 @@ void PltSection::initialize(u8 *buf) {
} }
void PltSection::write_entry(u8 *buf, Symbol *sym) { void PltSection::write_entry(u8 *buf, Symbol *sym) {
if (sym->got_idx == -1) {
const u8 data[] = { const u8 data[] = {
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT
0x68, 0, 0, 0, 0, // push $index_in_relplt 0x68, 0, 0, 0, 0, // push $index_in_relplt
0xe9, 0, 0, 0, 0, // jmp PLT[0] 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; u8 *base = buf + shdr.sh_offset + sym->plt_offset;
memcpy(base, data, sizeof(data)); memcpy(base, data, sizeof(data));
*(u32 *)(base + 2) = out::gotplt->shdr.sh_addr + sym->gotplt_offset - entry_addr - 6; *(u32 *)(base + 2) = sym->get_got_addr() - sym->get_plt_addr() - 6;
*(u32 *)(base + 7) = sym->plt_offset / PLT_SIZE; }
*(u32 *)(base + 12) = shdr.sh_addr - entry_addr - 16;
} }
MergedSection * MergedSection *