mirror of
https://github.com/rui314/mold.git
synced 2024-12-26 18:02:30 +03:00
temporary
This commit is contained in:
parent
1e469bfb10
commit
b8bc50fbb6
178
main.cc
178
main.cc
@ -333,103 +333,144 @@ static void set_isec_offsets() {
|
||||
static void scan_rels(ArrayRef<ObjectFile *> 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<ObjectFile *> 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<ObjectFile *> 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<ObjectFile *> 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);
|
||||
|
||||
|
64
mold.h
64
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;
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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 *
|
||||
|
Loading…
Reference in New Issue
Block a user