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) {
|
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);
|
||||||
|
|
||||||
if (out::dynsym) {
|
file->reldyn_offset = out::reldyn->shdr.sh_size;
|
||||||
file->dynsym_offset = out::dynsym->shdr.sh_size;
|
out::reldyn->shdr.sh_size += file->num_reldyn * sizeof(ELF64LE::Rela);
|
||||||
out::dynsym->shdr.sh_size += file->num_dynsym * sizeof(ELF64LE::Sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out::dynstr) {
|
file->dynsym_offset = out::dynsym->shdr.sh_size;
|
||||||
file->dynstr_offset = out::dynstr->shdr.sh_size;
|
out::dynsym->shdr.sh_size += file->num_dynsym * sizeof(ELF64LE::Sym);
|
||||||
out::dynstr->shdr.sh_size += file->dynstr_size;
|
|
||||||
}
|
file->dynstr_offset = out::dynstr->shdr.sh_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
64
mold.h
@ -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;
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
@ -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) {
|
||||||
const u8 data[] = {
|
if (sym->got_idx == -1) {
|
||||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT
|
const u8 data[] = {
|
||||||
0x68, 0, 0, 0, 0, // push $index_in_relplt
|
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOTPLT
|
||||||
0xe9, 0, 0, 0, 0, // jmp PLT[0]
|
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;
|
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 *
|
||||||
|
Loading…
Reference in New Issue
Block a user