Skip to content
Snippets Groups Projects
Commit 6ee61fd8 authored by Avi Kivity's avatar Avi Kivity
Browse files

elf: add lazy dynamic resolution of functions

parent 882cfc17
No related branches found
No related tags found
No related merge requests found
......@@ -29,6 +29,7 @@ objects += arch/x64/entry.o
objects += mutex.o
objects += pthread.o
objects += mempool.o
objects += arch/x64/elf-dl.o
libc = libc/string/strcmp.o
......
......@@ -348,13 +348,14 @@ namespace elf {
}
}
extern "C" { void __elf_resolve_pltgot(void); }
void elf_object::relocate_pltgot()
{
auto rel = dynamic_ptr<Elf64_Rela>(DT_JMPREL);
auto nrel = dynamic_val(DT_PLTRELSZ) / sizeof(*rel);
for (auto p = rel; p < rel + nrel; ++p) {
auto info = p->r_info;
u32 sym = info >> 32;
u32 type = info & 0xffffffff;
assert(type = R_X86_64_JUMP_SLOT);
void *addr = _base + p->r_offset;
......@@ -362,6 +363,25 @@ namespace elf {
// make sure it is relocated relative to the object base.
*static_cast<u64*>(addr) += reinterpret_cast<u64>(_base);
}
auto pltgot = dynamic_ptr<void*>(DT_PLTGOT);
// PLTGOT resolution has a special calling convention, with the symbol
// index and some word pushed on the stack, so we need an assembly
// stub to convert it back to the standard calling convention.
pltgot[1] = this;
pltgot[2] = reinterpret_cast<void*>(__elf_resolve_pltgot);
}
void* elf_object::resolve_pltgot(unsigned index)
{
auto rel = dynamic_ptr<Elf64_Rela>(DT_JMPREL);
auto slot = rel[index];
auto info = slot.r_info;
u32 sym = info >> 32;
u32 type = info & 0xffffffff;
assert(type == R_X86_64_JUMP_SLOT);
void *addr = _base + slot.r_offset;
auto ret = *static_cast<u64*>(addr) = symbol(sym).symbol->st_value;
return reinterpret_cast<void*>(ret);
}
void elf_object::relocate()
......@@ -640,3 +660,9 @@ namespace elf {
}
extern "C" { void* elf_resolve_pltgot(unsigned long index, elf::elf_object* obj); }
void* elf_resolve_pltgot(unsigned long index, elf::elf_object* obj)
{
obj->resolve_pltgot(index);
}
......@@ -256,6 +256,7 @@ namespace elf {
void* end() const;
Elf64_Sym* lookup_symbol(const char* name);
void load_segments();
void* resolve_pltgot(unsigned index);
protected:
virtual void load_segment(const Elf64_Phdr& segment) = 0;
private:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment