diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2024-02-15 18:11:57 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2024-02-15 18:11:57 +0100 |
| commit | c5a6875de940f296932154be434d2864e0652da8 (patch) | |
| tree | 278a857811a6bf1d82c945ec647f6846f4a8e029 /src/elfs | |
| parent | 549e042e678e0909c1a79325fb406fb0081ccac7 (diff) | |
| download | box64-c5a6875de940f296932154be434d2864e0652da8.tar.gz box64-c5a6875de940f296932154be434d2864e0652da8.zip | |
[ELFLOADER] Huge refactor of elfloader and symbol resolution. Some more cleaning need to be done, but that's a first step (should help #422, #360, #1046 and probably others)
Diffstat (limited to 'src/elfs')
| -rw-r--r-- | src/elfs/elfhash.c | 354 | ||||
| -rw-r--r-- | src/elfs/elfload_dump.c | 5 | ||||
| -rw-r--r-- | src/elfs/elfloader.c | 706 | ||||
| -rw-r--r-- | src/elfs/elfloader_private.h | 24 | ||||
| -rw-r--r-- | src/elfs/elfparser.c | 128 |
5 files changed, 622 insertions, 595 deletions
diff --git a/src/elfs/elfhash.c b/src/elfs/elfhash.c new file mode 100644 index 00000000..6c602617 --- /dev/null +++ b/src/elfs/elfhash.c @@ -0,0 +1,354 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <elf.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <sys/types.h> +#include <link.h> +#include <unistd.h> +#include <errno.h> + +#include "custommem.h" +#include "box64version.h" +#include "elfloader.h" +#include "debug.h" +#include "elfload_dump.h" +#include "elfloader_private.h" + +const char* GetSymbolVersion(elfheader_t* h, int version) +{ + if(version<2) + return NULL; + /*if(version==1) + return "*";*/ + if(h->VerNeed) { + Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); + while(ver) { + Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux); + for(int j=0; j<ver->vn_cnt; ++j) { + if(aux->vna_other==version) + return h->DynStr+aux->vna_name; + aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next); + } + ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + } + return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead +} + +const char* GetParentSymbolVersion(elfheader_t* h, int index) +{ + if(!h->VerDef || (index<1)) + return NULL; + Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta); + while(def) { + if(def->vd_ndx==index) { + if(def->vd_cnt<1) + return NULL; + /*if(def->vd_flags&VER_FLG_BASE) + return NULL;*/ + Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux); + return h->DynStr+aux->vda_name; // return Parent, so 1st aux + } + def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL; + } + return NULL; +} + +Elf64_Half GetParentSymbolVersionFlag(elfheader_t* h, int index) +{ + if(!h->VerDef || (index<1)) + return (Elf64_Half)-1; + Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta); + while(def) { + if(def->vd_ndx==index) { + return def->vd_flags; + } + def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL; + } + return (Elf64_Half)-1; +} +Elf64_Half GetSymbolVersionFlag(elfheader_t* h, int version) +{ + if(version<2) + return (Elf64_Half)-1; + if(h->VerNeed) { + Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); + while(ver) { + Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux); + for(int j=0; j<ver->vn_cnt; ++j) { + if(aux->vna_other==version) + return aux->vna_flags; + aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next); + } + ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + } + return GetParentSymbolVersionFlag(h, version); // if symbol is "internal", use Def table instead +} + + +int GetVersionIndice(elfheader_t* h, const char* vername) +{ + if(!vername) + return 0; + if(h->VerDef) { + Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta); + while(def) { + Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux); + if(!strcmp(h->DynStr+aux->vda_name, vername)) + return def->vd_ndx; + def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL; + } + } + return 0; +} + +int GetNeededVersionCnt(elfheader_t* h, const char* libname) +{ + if(!libname) + return 0; + if(h->VerNeed) { + Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); + while(ver) { + char *filename = h->DynStr + ver->vn_file; + if(!strcmp(filename, libname)) + return ver->vn_cnt; + ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + } + return 0; +} + +const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx) +{ + if(!libname) + return 0; + if(h->VerNeed) { + Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); + while(ver) { + char *filename = h->DynStr + ver->vn_file; + Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux); + if(!strcmp(filename, libname)) { + for(int j=0; j<ver->vn_cnt; ++j) { + if(j==idx) + return h->DynStr+aux->vna_name; + aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next); + } + return NULL; // idx out of bound, return NULL... + } + ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; + } + } + return NULL; +} + +int GetNeededVersionForLib(elfheader_t* h, const char* libname, const char* ver) +{ + if(!libname || !ver) + return 0; + int n = GetNeededVersionCnt(h, libname); + if(!n) + return 0; + for(int i=0; i<n; ++i) { + const char* vername = GetNeededVersionString(h, libname, i); + if(vername && !strcmp(ver, vername)) + return 1; + } + return 0; +} + +static int SymbolMatch(elfheader_t* h, uint32_t i, int ver, const char* vername, int local, int veropt) +{ + int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1; + if(version!=-1) version &=0x7fff; + const char* symvername = GetSymbolVersion(h, version); + Elf64_Half flags = GetSymbolVersionFlag(h, version); + if(ver==-1 || version==-1) + return 1; + if(version==0 && !local) + return 0; + if(version<2 && ver>1 && veropt) + return 1; + if(ver==0 && version<2) + return 1; + if(ver==1 && version<2) + return 1; + if(ver<2 && version>2 && flags==0) // flag is not WEAK, so global works + return 1; + if(ver<2 || !symvername) + return 0; + return strcmp(vername, symvername)?0:1; +} + +uint32_t old_elf_hash(const char* name) +{ + uint32_t h = 0, g; + for (unsigned char c = *name; c; c = *++name) { + h = (h << 4) + c; + if (g = h & 0xf0000000) { + h ^= g >> 24; + } + h &= ~g; + } + return h; +} + +Elf64_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt) +{ + // Prepare hash table + const uint32_t *hashtab = (uint32_t*)(h->hash + h->delta); + const uint32_t nbuckets = hashtab[0]; + const uint32_t nchains = hashtab[1]; + const uint32_t *buckets = &hashtab[2]; + const uint32_t *chains = &buckets[nbuckets]; + // get hash from symname to lookup + const uint32_t hash = old_elf_hash(symname); + // Search for it + for (uint32_t i = buckets[hash % nbuckets]; i; i = chains[i]) { + const char* name = h->DynStr + h->DynSym[i].st_name; + if (!strcmp(symname, name) && SymbolMatch(h, i, ver, vername, local, veropt)) { + return &h->DynSym[i]; + } + } + return NULL; +} + + +void old_elf_hash_dump(elfheader_t* h) +{ + // Prepare hash table + const uint32_t *hashtab = (uint32_t*)(h->hash + h->delta); + const uint32_t nbuckets = hashtab[0]; + const uint32_t nchains = hashtab[1]; + const uint32_t *buckets = &hashtab[2]; + const uint32_t *chains = &buckets[nbuckets]; + printf_log(LOG_NONE, "------------ Dump HASH from %s\n", h->name); + printf_log(LOG_NONE, "Buckets[%d] = \n", nbuckets); + for(uint32_t i=0; i<nbuckets; ++i) { + const char* name = h->DynStr + h->DynSym[buckets[i]].st_name; + printf_log(LOG_NONE, "%d: %s\n", buckets[i], name); + } + printf_log(LOG_NONE,"Chains[%d] = ", nchains); + for (uint32_t i = 0; i<nchains; ++i) + printf_log(LOG_NONE, "%d ", chains[i]); + printf_log(LOG_NONE, "\n------------\n"); +} + +uint32_t new_elf_hash(const char *name) +{ + uint32_t h = 5381; + for (unsigned char c = *name; c; c = *++name) + h = h * 33 + c; + return h; +} + +Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt) +{ + // Prepare hash table + const uint32_t *hashtab = (uint32_t*)(h->gnu_hash + h->delta); + const uint32_t nbuckets = hashtab[0]; + const uint32_t symoffset = hashtab[1]; + const uint32_t bloom_size = hashtab[2]; + const uint32_t bloom_shift = hashtab[3]; + const uint64_t *blooms = (uint64_t*)&hashtab[4]; + const uint32_t *buckets = (uint32_t*)&blooms[bloom_size]; + const uint32_t *chains = &buckets[nbuckets]; + // get hash from symname to lookup + const uint32_t hash = new_elf_hash(symname); + // early check with bloom: if at least one bit is not set, a symbol is surely missing. + uint64_t word = blooms[(hash/64)%bloom_size]; + uint64_t mask = 0 + | 1LL << (hash%64) + | 1LL << ((hash>>bloom_shift)%64); + if ((word & mask) != mask) { + return NULL; + } + // now look at the bucket chain for the symbol + uint32_t symidx = buckets[hash%nbuckets]; + if (symidx < symoffset) + return NULL; + while(1) { + const char* name = h->DynStr + h->DynSym[symidx].st_name; + const uint32_t symhash = chains[symidx-symoffset]; + if ((hash|1) == (symhash|1) && !strcmp(name, symname) && SymbolMatch(h, symidx, ver, vername, local, veropt)) { + return &h->DynSym[symidx]; + } + if(symhash&1) + return NULL; + symidx++; + } +} + +void new_elf_hash_dump(elfheader_t* h) +{ + // Prepare hash table + const uint32_t *hashtab = (uint32_t*)(h->gnu_hash + h->delta); + const uint32_t nbuckets = hashtab[0]; + const uint32_t symoffset = hashtab[1]; + const uint32_t bloom_size = hashtab[2]; + const uint32_t bloom_shift = hashtab[3]; + const uint64_t *blooms = (uint64_t*)&hashtab[4]; + const uint32_t *buckets = (uint32_t*)&blooms[bloom_size]; + const uint32_t *chains = &buckets[nbuckets]; + printf_log(LOG_NONE, "===============Dump GNU_HASH from %s\n", h->name); + printf_log(LOG_NONE, "Bloom: size=%d, shift=%d\n", bloom_size, bloom_shift); + printf_log(LOG_NONE, "Buckets[%d] offset=%d = \n", nbuckets, symoffset); + for(uint32_t i=0; i<nbuckets; ++i) { + uint32_t symidx = buckets[i]; + printf_log(LOG_NONE, "%d:", symidx); + while(symidx>=symoffset) { + const char* name = h->DynStr + h->DynSym[symidx].st_name; + const uint32_t hash = chains[symidx-symoffset]; + if(hash&1) + symidx=0; + else + symidx++; + printf_log(LOG_NONE, " %s (%x) -> %d", name, hash, symidx); + } + printf_log(LOG_NONE, "\n"); + } + printf_log(LOG_NONE, "\n===============\n"); +} + +Elf64_Sym* ElfLookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt) +{ + if(h->gnu_hash) + return new_elf_lookup(h, symname, ver, vername, local, veropt); + return old_elf_lookup(h, symname, ver, vername, local, veropt); +} + +Elf64_Sym* ElfSymTabLookup(elfheader_t* h, const char* symname) +{ + if(!h->SymTab) + return 0; + for(int i=0; i<h->numSymTab; ++i) { + Elf64_Sym* sym = &h->SymTab[i]; + int type = ELF64_ST_TYPE(sym->st_info); + if(type==STT_FUNC || type==STT_TLS || type==STT_OBJECT) { + const char * name = h->StrTab+sym->st_name; + if(name && !strcmp(symname, name)) + return sym; + } + } + return NULL; +} + +Elf64_Sym* ElfDynSymLookup(elfheader_t* h, const char* symname) +{ + if(!h->DynSym) + return 0; + for(int i=0; i<h->numDynSym; ++i) { + Elf64_Sym* sym = &h->DynSym[i]; + int type = ELF64_ST_TYPE(sym->st_info); + if(type==STT_FUNC || type==STT_TLS || type==STT_OBJECT) { + const char * name = h->DynStr+sym->st_name; + if(name && !strcmp(symname, name)) + return sym; + } + } + return NULL; +} diff --git a/src/elfs/elfload_dump.c b/src/elfs/elfload_dump.c index 1730967f..4c9cf228 100644 --- a/src/elfs/elfload_dump.c +++ b/src/elfs/elfload_dump.c @@ -231,10 +231,11 @@ const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version) { static char buff[4096]; const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version))); + int veropt = GetSymbolVersionFlag(h, version)?0:1; memset(buff, 0, sizeof(buff)); - sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d (ver=%d/%s)", + sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d (%sver=%d/%s)", h->DynStr+sym->st_name, (void*)sym->st_value, sym->st_size, - sym->st_info, sym->st_other, sym->st_shndx, version, vername); + sym->st_info, sym->st_other, sym->st_shndx, veropt?"opt":"", version, vername); return buff; } diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c index 8d8500d7..8845444a 100644 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -64,11 +64,6 @@ elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec) h->path[0] = '\0'; } - h->mapsymbols = NewMapSymbols(); - h->weaksymbols = NewMapSymbols(); - h->localsymbols = NewMapSymbols(); - h->globaldefver = NewDefaultVersion(); - h->weakdefver = NewDefaultVersion(); h->refcnt = 1; h->file = f; @@ -94,12 +89,6 @@ void FreeElfHeader(elfheader_t** head) box_free(h->SymTab); box_free(h->DynSym); - FreeMapSymbols(&h->mapsymbols); - FreeMapSymbols(&h->weaksymbols); - FreeMapSymbols(&h->localsymbols); - FreeDefaultVersion(&h->globaldefver); - FreeDefaultVersion(&h->weakdefver); - FreeElfMemory(h); box_free(h->name); @@ -259,7 +248,7 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin) try_mmap = 0; if(e->p_offset&(box64_pagesize-1)) try_mmap = 0; - if(e->p_memsz-e->p_filesz>(box64_pagesize-1)) + if(ALIGN(e->p_memsz)!=ALIGN(e->p_filesz)) try_mmap = 0; if(!e->p_filesz) try_mmap = 0; @@ -279,8 +268,8 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin) try_mmap = 0; printf_dump(log_level, "Mapping failed, using regular mmap+read"); } else { - /*if(e->p_memsz>e->p_filesz) - memset((void*)((uintptr_t)p + e->p_filesz), 0, e->p_memsz-e->p_filesz);*/ // already zero'd by the mmap + if(e->p_memsz>e->p_filesz && (prot&PROT_WRITE)) + memset((void*)((uintptr_t)p + e->p_filesz), 0, e->p_memsz-e->p_filesz); setProtection_elf((uintptr_t)p, head->multiblocks[n].asize, prot); head->multiblocks[n].p = p; @@ -418,7 +407,29 @@ int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verne return 1; } -int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, size_t size, int version, const char* vername) +static int IsSymInElfSpace(const elfheader_t* h, Elf64_Sym* sym) +{ + if(!h || !sym) + return 0; + uintptr_t addr = (uintptr_t)sym; + if(h->SymTab && addr>=(uintptr_t)h->SymTab && addr<(uintptr_t)&h->SymTab[h->numSymTab]) + return 1; + if(h->DynSym && addr>=(uintptr_t)h->DynSym && addr<(uintptr_t)&h->DynSym[h->numDynSym]) + return 1; + return 0; +} +static elfheader_t* FindElfSymbol(box64context_t *context, Elf64_Sym* sym) +{ + if(!sym) + return NULL; + for (int i=0; i<context->elfsize; ++i) + if(IsSymInElfSpace(context->elfs[i], sym)) + return context->elfs[i]; + + return NULL; +} + +int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, size_t size, int version, const char* vername, int veropt) { if(!h) return 0; @@ -435,7 +446,9 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** if(version2!=-1) version2 &= 0x7fff; if(version && !version2) version2=-1; // match a versioned symbol against a global "local" symbol const char* vername2 = GetSymbolVersion(h, version2); - if(SameVersionedSymbol(name, version, vername, symname, version2, vername2)) { + Elf64_Half flags = GetSymbolVersionFlag(h, version2); + int veropt2 = flags?0:1; + if(SameVersionedSymbol(name, version, vername, veropt, symname, version2, vername2, veropt2)) { if(offs) *offs = sym->st_value + h->delta; if(p) *p = (uint64_t*)(rela[i].r_offset + h->delta + rela[i].r_addend); return 1; @@ -447,184 +460,8 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf64_Rel *rel) { - int ret_ok = 0; - for (int i=0; i<cnt; ++i) { - int t = ELF64_R_TYPE(rel[i].r_info); - Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rel[i].r_info)]; - int bind = ELF64_ST_BIND(sym->st_info); - const char* symname = SymName(head, sym); - //uint64_t ndx = sym->st_shndx; - uint64_t *p = (uint64_t*)(rel[i].r_offset + head->delta); - uintptr_t offs = 0; - uintptr_t end = 0; - size_t size = sym->st_size; - //uintptr_t tmp = 0; - int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rel[i].r_info)]:-1; - if(version!=-1) version &=0x7fff; - const char* vername = GetSymbolVersion(head, version); - const char* globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(maplib, local_maplib, 0, deepbind, symname); - const char* weakdefver = (bind==STB_WEAK || !globdefver)?GetMaplibDefaultVersion(maplib, local_maplib, 1, deepbind, symname):NULL; - if(bind==STB_LOCAL) { - if(!symname || !symname[0]) { - offs = sym->st_value + head->delta; - end = offs + sym->st_size; - } else { - if(!offs && !end && local_maplib && deepbind) - GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end) - GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end && local_maplib && !deepbind) - GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - } - } else { - // this is probably very very wrong. A proprer way to get reloc need to be written, but this hack seems ok for now - // at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight... - /*if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_X86_64_GLOB_DAT) { - offs = sym->st_value + head->delta; - end = offs + sym->st_size; - }*/ - // so weak symbol are the one left - if(bind==STB_WEAK) { - if(!offs && !end) { - if(!offs && !end && local_maplib && deepbind) - GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end) - GetGlobalWeakSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end && local_maplib && !deepbind) - GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - } - } else { - if(!offs && !end) { - if(!offs && !end && local_maplib && deepbind) - GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end) - GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end && local_maplib && !deepbind) - GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - } - } - } - uintptr_t globoffs, globend; - uint64_t* globp; - switch(t) { - case R_X86_64_NONE: - // can be ignored - printf_dump(LOG_NEVER, "Ignoring %s @%p (%p)\n", DumpRelType(t), p, (void*)(p?(*p):0)); - break; - case R_X86_64_PC32: - if (!offs) { - printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_X86_64_PC32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name); - ret_ok = 1; - } - offs = (offs - (uintptr_t)p); - if(!offs) - printf_dump(LOG_NEVER, "Apply %s R_X86_64_PC32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(*(uintptr_t*)p+offs)); - *p += offs; - break; - case R_X86_64_GLOB_DAT: - if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername, globdefver) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) { - // set global offs / size for the symbol - offs = sym->st_value; - end = offs + sym->st_size; - if(sym->st_size && offs) { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%ld on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)(offs + head->delta), (void*)globoffs, sym->st_size, symname); - memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf - AddUniqueSymbol(GetGlobalData(maplib), symname, globoffs, sym->st_size, version, vername); - AddUniqueSymbol(my_context->globdata, symname, offs + head->delta, sym->st_size, version, vername); - } else { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname); - } - *p = globoffs; - } else { - if((size==0) && GetSymbolStartEnd(GetGlobalData(maplib), symname, &globoffs, &globend, version, vername, 0, globdefver)) { - offs = globoffs; - } - if (!offs) { - if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start") && strcmp(symname, "collector_func_load")) - printf_log(LOG_NONE, "%s: Global Symbol %s (ver=%d/%s) not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, version, vername?vername:"(none)", p, *(void**)p, head->name); - } else { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)"); - *p = offs; - } - } - break; - case R_X86_64_COPY: - if(offs) { - uintptr_t old_offs = offs; - uintptr_t old_end = end; - offs = 0; - GetSizedSymbolStartEnd(my_context->globdata, symname, &offs, &end, size, version, vername, 1, globdefver); // try globaldata symbols first - if(offs==0) { - GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver); // get original copy if any - if(!offs && local_maplib) - GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver); - } - if(!offs) { - offs = old_offs; - end = old_end; - } - printf_dump(LOG_NEVER, "Apply %s R_X86_64_COPY @%p with sym=%s, @%p size=%ld (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size); - memmove(p, (void*)offs, sym->st_size); - if(box64_dump) { - uint64_t *k = (uint64_t*)p; - for (unsigned j=0; j<((sym->st_size>128u)?128u:sym->st_size); j+=8, ++k) - printf_dump(LOG_NEVER, "%s0x%016lX", j?" ":"", *k); - printf_dump(LOG_NEVER, "%s)\n", (sym->st_size>128u)?" ...":""); - } - } else { - printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_X86_64_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name); - } - break; - case R_X86_64_RELATIVE: - printf_dump(LOG_NEVER, "Apply %s R_X86_64_RELATIVE @%p (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, *(void**)p, (void*)((*p)+head->delta)); - *p += head->delta; - break; - case R_X86_64_64: - if (!offs) { - printf_log(LOG_NONE, "%s: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", (bind==STB_GLOBAL)?"Error":"Warning", symname, p, *(void**)p, head->name); - if(bind==STB_GLOBAL) - ret_ok = 1; - // return -1; - } else { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_64 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+*(uint64_t*)p)); - *p += offs; - } - break; - #if 0 - case R_X86_64_JUMP_SLOT: - // apply immediatly for gobject closure marshal or for LOCAL binding. Also, apply immediatly if it doesn't jump in the got - tmp = (uintptr_t)(*p); - if (bind==STB_LOCAL - || ((symname && strstr(symname, "g_cclosure_marshal_")==symname)) - || !tmp - || !((tmp>=head->plt && tmp<head->plt_end) || (tmp>=head->gotplt && tmp<head->gotplt_end)) - ) { - if (!offs) { - if(bind==STB_WEAK) { - printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_X86_64_JUMP_SLOT @%p (%p)\n", symname, p, *(void**)p); - } else { - printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_X86_64_JUMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, head->name); - } - // return -1; - } else { - if(p) { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_JUMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs); - *p = offs; - } else { - printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname); - } - } - } else { - printf_dump(LOG_NEVER, "Preparing (if needed) %s R_X86_64_JUMP_SLOT @%p (0x%lx->0x%0lx) with sym=%s to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname); - *p += head->delta; - } - break; - #endif - default: - printf_log(LOG_INFO, "Warning, don't know how to handle rel #%d %s (%p)\n", i, DumpRelType(ELF64_R_TYPE(rel[i].r_info)), p); - } - } - return bindnow?ret_ok:0; + printf_log(LOG_NONE, "Error: REL type of Relocation unsupported (only RELA)\n"); + return 1; } struct tlsdesc @@ -640,17 +477,32 @@ EXPORT uintptr_t _dl_tlsdesc_undefweak(x64emu_t* emu) return td->arg; } +void GrabX64CopyMainElfReloc(elfheader_t* head) +{ + if(head->rela) { + int cnt = head->relasz / head->relaent; + Elf64_Rela* rela = (Elf64_Rela *)(head->rela + head->delta); + printf_dump(LOG_DEBUG, "Grabbing R_X86_64_COPY Relocation(s) in advance for %s\n", head->name); + for (int i=0; i<cnt; ++i) { + int t = ELF64_R_TYPE(rela[i].r_info); + if(t == R_X86_64_COPY) { + Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rela[i].r_info)]; + const char* symname = SymName(head, sym); + int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; + if(version!=-1) version &=0x7fff; + const char* vername = GetSymbolVersion(head, version); + Elf64_Half flags = GetSymbolVersionFlag(head, version); + int veropt = flags?0:1; + uintptr_t offs = sym->st_value + head->delta; + AddUniqueSymbol(my_context->globdata, symname, offs, sym->st_size, version, vername, veropt); + } + } + } +} int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf64_Rela *rela, int* need_resolv) { int ret_ok = 0; - const char* old_globdefver = NULL; - const char* old_weakdefver = NULL; - int old_bind = -1; - const char* old_symname = NULL; - uintptr_t old_offs = 0; - uintptr_t old_end = 0; - int old_version = -1; for (int i=0; i<cnt; ++i) { int t = ELF64_R_TYPE(rela[i].r_info); Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rela[i].r_info)]; @@ -661,74 +513,51 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin uintptr_t offs = 0; uintptr_t end = 0; size_t size = sym->st_size; - elfheader_t* h_tls = NULL;//head; + elfheader_t* sym_elf = NULL; int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; if(version!=-1) version &=0x7fff; const char* vername = GetSymbolVersion(head, version); - const char* globdefver = NULL; - const char* weakdefver = NULL; - if(old_bind==bind && old_symname==symname) { - globdefver = old_globdefver; - weakdefver = old_weakdefver; + Elf64_Half flags = GetSymbolVersionFlag(head, version); + int veropt = flags?0:1; + Elf64_Sym* elfsym = NULL; + int vis = ELF64_ST_VISIBILITY(sym->st_other); + if(vis==STV_PROTECTED) { + elfsym = ElfDynSymLookup(head, symname); + printf_log(LOG_INFO, "Symbol %s from %s is PROTECTED\n", symname, head); } else { - old_globdefver = globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(maplib, local_maplib, 0, deepbind, symname); - old_weakdefver = weakdefver = (bind==STB_WEAK || !globdefver)?GetMaplibDefaultVersion(maplib, local_maplib, 1, deepbind, symname):NULL; - } - if(bind==STB_LOCAL) { - if(!symname || !symname[0]) { - offs = sym->st_value + head->delta; - end = offs + sym->st_size; - } else { - if(old_version==version && old_bind==bind && old_symname==symname) { - offs = old_offs; - end = old_end; - } else { - if(local_maplib && deepbind) - GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end) - GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end && local_maplib && !deepbind) - GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - } - } - } else { - // this is probably very very wrong. A proprer way to get reloc need to be written, but this hack seems ok for now - // at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight... - /*if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_X86_64_GLOB_DAT) { - offs = sym->st_value + head->delta; - end = offs + sym->st_size; - }*/ - // so weak symbol are the one left - if(bind==STB_WEAK) { - if(old_version==version && old_bind==bind && old_symname==symname) { - offs = old_offs; - end = old_end; - } else { - if(local_maplib && deepbind) - GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - else - GetGlobalWeakSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - if(!offs && !end && local_maplib && !deepbind) - GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); - } - } else { - if(old_version==version && old_bind==bind && old_symname==symname) { - offs = old_offs; - end = old_end; + if(bind==STB_GNU_UNIQUE) { + GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); + } else if(bind==STB_LOCAL) { + if(!symname || !symname[0]) { + offs = sym->st_value + head->delta; + end = offs + sym->st_size; } else { + elfsym = ElfDynSymLookup(head, symname); + if(elfsym && elfsym->st_shndx) { + offs = elfsym->st_value + head->delta; + end = offs + elfsym->st_size; + } if(!offs && !end && local_maplib && deepbind) - GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); if(!offs && !end) - GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); + GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); if(!offs && !end && local_maplib && !deepbind) - GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver); + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); } + } else { + if(!offs && !end && local_maplib && deepbind) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); + if(!offs && !end) + GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); } } - old_bind = bind; - old_symname = symname; - old_offs = offs; - old_end = end; + sym_elf = FindElfSymbol(my_context, elfsym); + if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) + offs = elfsym->st_value; uintptr_t globoffs, globend; uint64_t* globp; uintptr_t tmp = 0; @@ -741,14 +570,14 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin // can be ignored break; case R_X86_64_RELATIVE: - printf_dump(LOG_NEVER, "Apply %s R_X86_64_RELATIVE @%p (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, *(void**)p, (void*)(head->delta+ rela[i].r_addend)); + printf_dump(LOG_NEVER, "Apply %s R_X86_64_RELATIVE @%p (%p -> %p)\n", BindSym(bind), p, *(void**)p, (void*)(head->delta+ rela[i].r_addend)); *p = head->delta+ rela[i].r_addend; break; case R_X86_64_IRELATIVE: { x64emu_t* emu = thread_get_emu(); EmuCall(emu, head->delta+rela[i].r_addend); - printf_dump(LOG_NEVER, "Apply %s R_X86_64_IRELATIVE @%p (%p -> %p()=%p)\n", (bind==STB_LOCAL)?"Local":"Global", p, *(void**)p, (void*)(head->delta+ rela[i].r_addend), (void*)(R_RAX)); + printf_dump(LOG_NEVER, "Apply %s R_X86_64_IRELATIVE @%p (%p -> %p()=%p)\n", BindSym(bind), p, *(void**)p, (void*)(head->delta+ rela[i].r_addend), (void*)(R_RAX)); *p = R_RAX; } break; @@ -756,15 +585,16 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin globoffs = offs; globend = end; offs = end = 0; - GetSizedSymbolStartEnd(my_context->globdata, symname, &offs, &end, size, version, vername, 1, globdefver); // try globaldata symbols first - if(!offs && local_maplib) - GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver); + if(!offs && local_maplib && deepbind) + GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL); if(!offs) - GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver); + GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL); + if(!offs && local_maplib && !deepbind) + GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL); if(!offs) {offs = globoffs; end = globend;} if(offs) { // add r_addend to p? - printf_dump(LOG_NEVER, "Apply R_X86_64_COPY @%p with sym=%s (ver=%d/%s), @%p+0x%lx size=%ld\n", p, symname, version, vername?vername:"(none)", (void*)offs, rela[i].r_addend, sym->st_size); + printf_dump(LOG_NEVER, "Apply R_X86_64_COPY @%p with sym=%s (%sver=%d/%s), @%p+0x%lx size=%ld\n", p, symname, veropt?"opt":"", version, vername?vername:"(none)", (void*)offs, rela[i].r_addend, sym->st_size); if(p!=(void*)(offs+rela[i].r_addend)) memmove(p, (void*)(offs+rela[i].r_addend), sym->st_size); } else { @@ -772,33 +602,20 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin } break; case R_X86_64_GLOB_DAT: - if((head!=my_context->elfs[0]) && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername, globdefver) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) { - // set global offs / size for the symbol - offs = sym->st_value + head->delta; - end = offs + sym->st_size; - if(sym->st_size && offs) { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%zd on sym=%s (ver=%d/%s) \n", - (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), - (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname, version, vername?vername:"(none)"); - //memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf - AddUniqueSymbol(GetGlobalData(maplib), symname, globoffs, sym->st_size, version, vername); - AddUniqueSymbol(my_context->globdata, symname, offs, sym->st_size, version, vername); - } else { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s (ver=%d/%s)\n", - (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), - (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname, version, vername?vername:"(none)"); - } + if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { + globp = (uint64_t*)globoffs; + printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%zd on sym=%s (%sver=%d/%s) \n", + BindSym(bind), p, globp, (void*)(p?(*p):0), + (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname, veropt?"opt":"", version, vername?vername:"(none)"); + sym_elf = my_context->elfs[0]; *p = globoffs; } else { - if((size==0) && GetSymbolStartEnd(GetGlobalData(maplib), symname, &globoffs, &globend, version, vername, 0, globdefver)) { - offs = globoffs; - } if (!offs) { if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start") && strcmp(symname, "collector_func_load")) - printf_log((bind==STB_WEAK)?LOG_INFO:LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name); + printf_log((bind==STB_WEAK)?LOG_DEBUG:LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name); } else { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)"); - *p = offs/* + rela[i].r_addend*/; // not addend it seems + printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, (void*)(p?(*p):0), (void*)(offs + rela[i].r_addend), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)"); + *p = offs + rela[i].r_addend; } } break; @@ -823,8 +640,9 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin // return -1; } else { if(p) { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_JUMP_SLOT @%p with sym=%s (%p -> %p)\n", - (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+rela[i].r_addend)); + elfheader_t* sym_elf = FindElfAddress(my_context, offs); + printf_dump(LOG_NEVER, "Apply %s R_X86_64_JUMP_SLOT @%p with sym=%s (%p -> %p / %s (%sver=%d / %s))\n", + BindSym(bind), p, symname, *(void**)p, (void*)(offs+rela[i].r_addend), sym_elf?sym_elf->name:"native", veropt?"opt":"", version, vername?vername:"(none)"); *p = offs + rela[i].r_addend; } else { printf_log(LOG_INFO, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname); @@ -832,13 +650,13 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin } } else { printf_dump(LOG_NEVER, "Preparing (if needed) %s R_X86_64_JUMP_SLOT @%p (0x%lx->0x%0lx) with sym=%s to be apply later (addend=%ld)\n", - (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname, rela[i].r_addend); + BindSym(bind), p, *p, *p+head->delta, symname, rela[i].r_addend); *p += head->delta; *need_resolv = 1; } break; case R_X86_64_64: - if (!offs) { + if (!offs && !elfsym) { if(symname && !strcmp(symname, "__gxx_personality_v0")) { printf_dump(LOG_NEVER, "Warning: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", symname, p, *(void**)p, head->name); } else { @@ -848,8 +666,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin // return -1; } } else { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_64 @%p with sym=%s (ver=%d/%s) addend=0x%lx (%p -> %p)\n", - (bind==STB_LOCAL)?"Local":"Global", p, symname, version, vername?vername:"(none)", rela[i].r_addend, *(void**)p, (void*)(offs+rela[i].r_addend/*+*(uint64_t*)p*/)); + printf_dump(LOG_NEVER, "Apply %s R_X86_64_64 @%p with sym=%s (%sver=%d/%s) addend=0x%lx (%p -> %p)\n", + BindSym(bind), p, symname, veropt?"opt":"", version, vername?vername:"(none)", rela[i].r_addend, *(void**)p, (void*)(offs+rela[i].r_addend/*+*(uint64_t*)p*/)); *p /*+*/= offs+rela[i].r_addend; } break; @@ -857,21 +675,15 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin // Negated offset in static TLS block { if(!symname || !symname[0]) { - h_tls = head; + sym_elf = head; offs = sym->st_value; - } else { - h_tls = NULL; - if(local_maplib) - h_tls = GetGlobalSymbolElf(local_maplib, symname, version, vername); - if(!h_tls) - h_tls = GetGlobalSymbolElf(maplib, symname, version, vername); } - if(h_tls) { + if(sym_elf) { delta = *(int64_t*)p; - printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%ld -> %ld+%ld+%ld, size=%ld)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, h_tls->tlsbase, (int64_t)offs, rela[i].r_addend, end-offs); - *p = (uintptr_t)((int64_t)offs + rela[i].r_addend + h_tls->tlsbase); + printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%ld -> %ld+%ld+%ld, size=%ld)\n", BindSym(bind), DumpRelType(t), symname, p, delta, sym_elf->tlsbase, (int64_t)offs, rela[i].r_addend, end-offs); + *p = (uintptr_t)((int64_t)offs + rela[i].r_addend + sym_elf->tlsbase); } else { - printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%ld), no elf_header found\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, (int64_t)offs); + printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%ld), no elf_header found\n", BindSym(bind), DumpRelType(t), symname, p, (int64_t)offs); } } break; @@ -880,16 +692,10 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin if(!symname || symname[0]=='\0' || bind==STB_LOCAL) offs = getElfIndex(my_context, head); else { - if(!h_tls) { - if(local_maplib) - h_tls = GetGlobalSymbolElf(local_maplib, symname, version, vername); - if(!h_tls) - h_tls = GetGlobalSymbolElf(maplib, symname, version, vername); - } - offs = getElfIndex(my_context, h_tls); + offs = getElfIndex(my_context, sym_elf); } if(p) { - printf_dump(LOG_NEVER, "Apply %s %s @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", "R_X86_64_DTPMOD64", p, symname, *(void**)p, (void*)offs); + printf_dump(LOG_NEVER, "Apply %s %s @%p with sym=%s (%p -> %p)\n", BindSym(bind), "R_X86_64_DTPMOD64", p, symname, *(void**)p, (void*)offs); *p = offs; } else { printf_log(LOG_INFO, "Warning, Symbol %s or Elf not found, but R_X86_64_DTPMOD64 Slot Offset is NULL \n", symname); @@ -897,7 +703,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin break; case R_X86_64_DTPOFF64: // Offset in TLS block - if (!offs && !end) { + if (!offs && !sym_elf) { if(bind==STB_WEAK) { printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_X86_64_DTPOFF64 @%p (%p)\n", symname, p, *(void**)p); } else { @@ -908,8 +714,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin if(!symname || symname[0]=='\0') offs = sym->st_value; if(p) { - int64_t tlsoffset = offs; // it's not an offset in elf memory - printf_dump(LOG_NEVER, "Apply %s R_X86_64_DTPOFF64 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)tlsoffset, (void*)offs); + int64_t tlsoffset = (int64_t)offs; // it's not an offset in elf memory + printf_dump(LOG_NEVER, "Apply %s R_X86_64_DTPOFF64 @%p with sym=%s (%p -> %p)\n", BindSym(bind), p, symname, (void*)tlsoffset, (void*)offs); *p = tlsoffset; } else { printf_log(LOG_INFO, "Warning, Symbol %s found, but R_X86_64_DTPOFF64 Slot Offset is NULL \n", symname); @@ -918,7 +724,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin break; case R_X86_64_TLSDESC: if(!symname || !symname[0]) { - printf_dump(LOG_NEVER, "Apply %s R_X86_64_TLSDESC @%p with addend=%zu\n", (bind==STB_LOCAL)?"Local":"Global", p, rela[i].r_addend); + printf_dump(LOG_NEVER, "Apply %s R_X86_64_TLSDESC @%p with addend=%zu\n", BindSym(bind), p, rela[i].r_addend); struct tlsdesc volatile *td = (struct tlsdesc volatile *)p; if(!tlsdescUndefweak) tlsdescUndefweak = AddBridge(my_context->system, pFE, _dl_tlsdesc_undefweak, 0, "_dl_tlsdesc_undefweak"); @@ -1067,93 +873,13 @@ uintptr_t GetLastByte(elfheader_t* h) #endif void checkHookedSymbols(elfheader_t* h); // in mallochook.c -void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h) +void AddSymbols(lib_t *maplib, elfheader_t* h) { + //if(box64_dump && h->hash) old_elf_hash_dump(h); + //if(box64_dump && h->gnu_hash) new_elf_hash_dump(h); if(box64_dump && h->DynSym) DumpDynSym(h); - printf_dump(LOG_NEVER, "Will look for Symbol to add in SymTable(%zu)\n", h->numSymTab); - for (size_t i=0; i<h->numSymTab; ++i) { - const char * symname = h->StrTab+h->SymTab[i].st_name; - int bind = ELF64_ST_BIND(h->SymTab[i].st_info); - int type = ELF64_ST_TYPE(h->SymTab[i].st_info); - int vis = h->SymTab[i].st_other&0x3; - size_t sz = h->SymTab[i].st_size; - if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE) - && (vis==STV_DEFAULT || vis==STV_PROTECTED || (vis==STV_HIDDEN && bind==STB_LOCAL)) && (h->SymTab[i].st_shndx!=0)) { - if(sz && strstr(symname, "@@")) { - char symnameversioned[strlen(symname)+1]; - strcpy(symnameversioned, symname); - // extact symname@@vername - char* p = strchr(symnameversioned, '@'); - *p=0; - p+=2; - symname = AddDictionnary(my_context->versym, symnameversioned); - const char* vername = AddDictionnary(my_context->versym, p); - AddDefaultVersion((bind==STB_WEAK)?h->weakdefver:h->globaldefver, symname, vername); - if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, 2, p)) - continue; - uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta); - printf_dump(LOG_NEVER, "Adding Default Versioned Symbol(bind=%s) \"%s@%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, vername, (void*)offs, sz); - if(bind==STB_LOCAL) - AddSymbol(localsymbols, symname, offs, sz, 2, vername); - else // add in local and global map - if(bind==STB_WEAK) { - AddSymbol(weaksymbols, symname, offs, sz, 2, vername); - } else { - AddSymbol(mapsymbols, symname, offs, sz, 2, vername); - } - } else { - int to_add = 1; - if(!to_add || (bind==STB_GNU_UNIQUE && FindGlobalSymbol(maplib, symname, -1, NULL))) - continue; - uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta); - printf_dump(LOG_NEVER, "Adding Symbol(bind=%s) \"%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, (void*)offs, sz); - if(bind==STB_LOCAL) - AddSymbol(localsymbols, symname, offs, sz, 1, NULL); - else // add in local and global map - if(bind==STB_WEAK) { - AddSymbol(weaksymbols, symname, offs, sz, 1, NULL); - } else { - AddSymbol(mapsymbols, symname, offs, sz, 1, NULL); - } - } - } - } - - int deepbind = 0; - if(h && h->lib) - deepbind = GetDeepBind(h->lib); - printf_dump(LOG_NEVER, "Will look for Symbol to add in DynSym (%zu)\n", h->numDynSym); - for (size_t i=0; i<h->numDynSym; ++i) { - const char * symname = h->DynStr+h->DynSym[i].st_name; - int bind = ELF64_ST_BIND(h->DynSym[i].st_info); - int type = ELF64_ST_TYPE(h->DynSym[i].st_info); - int vis = h->DynSym[i].st_other&0x3; - if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE) - && (vis==STV_DEFAULT || vis==STV_PROTECTED || (vis==STV_HIDDEN && bind==STB_LOCAL)) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) { - uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta); - size_t sz = h->DynSym[i].st_size; - int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1; - int add_default = (version!=-1 && (version&0x7fff)>1 && !(version&0x8000) && !GetMaplibDefaultVersion(my_context->maplib, (maplib==my_context->maplib)?NULL:maplib, (bind==STB_WEAK)?1:0, deepbind, symname))?1:0; - if(version!=-1) version &= 0x7fff; - const char* vername = GetSymbolVersion(h, version); - if(add_default) { - AddDefaultVersion((bind==STB_WEAK)?h->weakdefver:h->globaldefver, symname, vername); - printf_dump(LOG_NEVER, "Adding Default Version \"%s\" for Symbol\"%s\"\n", vername, symname); - } - int to_add = 1; - if(!to_add || (bind==STB_GNU_UNIQUE && FindGlobalSymbol(maplib, symname, version, vername))) - continue; - printf_dump(LOG_NEVER, "Adding Versioned Symbol(bind=%s) \"%s\" (ver=%d/%s) with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, version, vername?vername:"(none)", (void*)offs, sz); - if(bind==STB_LOCAL) - AddSymbol(localsymbols, symname, offs, sz, version, vername); - else // add in local and global map - if(bind==STB_WEAK) { - AddSymbol(weaksymbols, symname, offs, sz, version, vername); - } else { - AddSymbol(mapsymbols, symname, offs, sz, version?version:1, vername); - } - } - } + if(h==my_context->elfs[0]) + GrabX64CopyMainElfReloc(h); checkHookedSymbols(h); } @@ -1297,39 +1023,6 @@ void MarkElfInitDone(elfheader_t* h) h->init_done = 1; } void startMallocHook(); -void RunElfInitPltResolver(elfheader_t* h, x64emu_t *emu) -{ - if(!h || h->init_done) - return; - uintptr_t p = h->initentry + h->delta; - h->init_done = 1; - for(int i=0; i<h->needed->size; ++i) { - library_t *lib = h->needed->libs[i]; - elfheader_t *lib_elf = GetElf(lib); - if(lib_elf) - RunElfInitPltResolver(lib_elf, emu); - } - printf_dump(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p); - if(h->initentry) - RunSafeFunction(p, 3, my_context->argc, my_context->argv, my_context->envv); - printf_dump(LOG_DEBUG, "Done Init for %s\n", ElfName(h)); - // and check init array now - Elf64_Addr *addr = (Elf64_Addr*)(h->initarray + h->delta); - for (size_t i=0; i<h->initarray_sz; ++i) { - if(addr[i]) { - printf_dump(LOG_DEBUG, "Calling Init[%zu] for %s @%p\n", i, ElfName(h), (void*)addr[i]); - RunSafeFunction((uintptr_t)addr[i], 3, my_context->argc, my_context->argv, my_context->envv); - } - } - - if(h->malloc_hook_2) - startMallocHook(); - - h->fini_done = 0; // can be fini'd now (in case it was re-inited) - printf_dump(LOG_DEBUG, "All Init Done for %s\n", ElfName(h)); - return; -} - void RunElfInit(elfheader_t* h, x64emu_t *emu) { if(!h || h->init_done) @@ -1551,7 +1244,7 @@ const char* VersionedName(const char* name, int ver, const char* vername) return AddDictionnary(my_context->versym, buf); } -int SameVersionedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2) +int SameVersionedSymbol(const char* name1, int ver1, const char* vername1, int veropt1, const char* name2, int ver2, const char* vername2, int veropt2) { if(strcmp(name1, name2)) //name are different, no need to go further return 0; @@ -1563,6 +1256,10 @@ int SameVersionedSymbol(const char* name1, int ver1, const char* vername1, const return 0; if(ver1==1 || ver2==1) // one if global, ok return 1; + if(ver1<2 && ver2>1 && veropt2) + return 1; + if(ver2<2 && ver1>1 && veropt1) + return 1; if(!strcmp(vername1, vername2)) // same vername return 1; return 0; @@ -1783,23 +1480,70 @@ void ElfAttachLib(elfheader_t* head, library_t* lib) head->lib = lib; } -kh_mapsymbols_t* GetMapSymbols(elfheader_t* h) +Elf64_Sym* ElfLocateSymbol(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) { - if(!h) + Elf64_Sym* sym = ElfLookup(head, symname, *ver, *vername, local, *veropt); + if(!sym) return NULL; + if(head->VerSym && !*veropt) { + int idx = ((uintptr_t)sym - (uintptr_t)head->DynSym)/sizeof(Elf64_Sym); + int version = ((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[idx]; + if(version!=-1) version &=0x7fff; + const char* symvername = GetSymbolVersion(head, version); + Elf64_Half flags = GetSymbolVersionFlag(head, version); + if(version>1 && *ver<2 && (flags==0)) { + *ver = version; + *vername = symvername; + *veropt = 1; + } else if(flags==0 && !*veropt && version>1 && *ver>1 && !strcmp(symvername, *vername)) { + *veropt = 1; + } + } + if(!sym->st_shndx) return NULL; + int vis = ELF64_ST_VISIBILITY(sym->st_other); + if(vis==STV_HIDDEN && !local) return NULL; - return h->mapsymbols; + return sym; } -kh_mapsymbols_t* GetWeakSymbols(elfheader_t* h) + +void* ElfGetLocalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) { - if(!h) - return NULL; - return h->weaksymbols; + Elf64_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt); + if(!sym) return NULL; + int bind = ELF64_ST_BIND(sym->st_info); + if(bind!=STB_LOCAL) return 0; + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return sym; } -kh_mapsymbols_t* GetLocalSymbols(elfheader_t* h) +void* ElfGetGlobalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) { - if(!h) - return NULL; - return h->localsymbols; + Elf64_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt); + if(!sym) return NULL; + int bind = ELF64_ST_BIND(sym->st_info); + if(bind!=STB_GLOBAL && bind!=STB_GNU_UNIQUE) return 0; + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return sym; +} +void* ElfGetWeakSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) +{ + Elf64_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt); + if(!sym) return NULL; + int bind = ELF64_ST_BIND(sym->st_info); + if(bind!=STB_WEAK) return 0; + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return sym; +} +int ElfGetSymTabStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname) +{ + Elf64_Sym* sym = ElfSymTabLookup(head, symname); + if(!sym) return 0; + if(!sym->st_shndx) return 0; + if(!sym->st_size) return 0; //needed? + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return 1; } typedef struct search_symbol_s{ @@ -1873,23 +1617,16 @@ void* GetNativeSymbolUnversioned(void* lib, const char* name) return s.addr; } -kh_defaultversion_t* GetGlobalDefaultVersion(elfheader_t* h) -{ - return h?h->globaldefver:NULL; -} -kh_defaultversion_t* GetWeakDefaultVersion(elfheader_t* h) -{ - return h?h->weakdefver:NULL; -} - - uintptr_t pltResolver = ~0LL; EXPORT void PltResolver(x64emu_t* emu) { uintptr_t addr = Pop64(emu); int slot = (int)Pop64(emu); elfheader_t *h = (elfheader_t*)addr; - printf_dump(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s (VerSym=%p)\n", (void*)addr, slot, *(void**)(R_RSP), h->name, h->VerSym); + library_t* lib = h->lib; + lib_t* local_maplib = GetMaplib(lib); + int deepbind = GetDeepBind(lib); + printf_dump(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p(%s): elf is %s (VerSym=%p, deepbind=%d, local_maplib=%p) func param: %p, %p...\n", (void*)addr, slot, *(void**)(R_RSP), getAddrFunctionName(*(uintptr_t*)R_RSP),h->name, h->VerSym, deepbind, local_maplib, (void*)R_RDI, (void*)R_RSI); Elf64_Rela * rel = (Elf64_Rela *)(h->jmprel + h->delta) + slot; @@ -1899,42 +1636,53 @@ EXPORT void PltResolver(x64emu_t* emu) int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rel->r_info)]:-1; if(version!=-1) version &= 0x7fff; const char* vername = GetSymbolVersion(h, version); + Elf64_Half flags = GetSymbolVersionFlag(h, version); + int veropt = flags?0:1; uint64_t *p = (uint64_t*)(rel->r_offset + h->delta); uintptr_t offs = 0; uintptr_t end = 0; - library_t* lib = h->lib; - lib_t* local_maplib = GetMaplib(lib); - int deepbind = GetDeepBind(lib); - const char* globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(my_context->maplib, (my_context->maplib==local_maplib)?NULL:local_maplib, 0, deepbind, symname); - const char* weakdefver = (bind==STB_WEAK)?GetMaplibDefaultVersion(my_context->maplib, (my_context->maplib==local_maplib)?NULL:local_maplib, 1, deepbind, symname):NULL; - if(!offs && !end && local_maplib && deepbind) - GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, globdefver, weakdefver); - else - GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, globdefver, weakdefver); - if(!offs && !end && local_maplib && !deepbind) { - GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, globdefver, weakdefver); + Elf64_Sym *elfsym = NULL; + if(bind==STB_LOCAL) { + elfsym = ElfDynSymLookup(h, symname); + if(elfsym && elfsym->st_shndx) { + offs = elfsym->st_value + h->delta; + end = offs + elfsym->st_size; + } + if(!offs && !end && local_maplib && deepbind) + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end) + GetLocalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + } else if(bind==STB_WEAK) { + if(local_maplib && deepbind) + GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + else + GetGlobalWeakSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + } else { + if(!offs && !end && local_maplib && deepbind) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end) + GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); } - if(!offs && !end && !version) - GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, -1, NULL, globdefver, weakdefver); - if (!offs) { - printf_log(LOG_NONE, "Error: PltResolver: Symbol %s(ver %d: %s%s%s) not found, cannot apply R_X86_64_JUMP_SLOT %p (%p) in %s\n", symname, version, symname, vername?"@":"", vername?vername:"", p, *(void**)p, h->name); + printf_log(LOG_NONE, "Error: PltResolver: Symbol %s(%sver %d: %s%s%s) not found, cannot apply R_X86_64_JUMP_SLOT %p (%p) in %s\n", symname, veropt?"opt":"", version, symname, vername?"@":"", vername?vername:"", p, *(void**)p, h->name); emu->quit = 1; return; } else { - elfheader_t* sym_elf = FindElfAddress(my_context, offs); - if(sym_elf && sym_elf!=my_context->elfs[0] && !sym_elf->init_done) { - printf_dump(LOG_DEBUG, "symbol %s from %s but elf not initialized yet, run Init now (from %s)\n", symname, ElfName(sym_elf), ElfName(h)); - RunElfInitPltResolver(sym_elf, emu); - } + elfheader_t* sym_elf = FindElfSymbol(my_context, elfsym); offs = (uintptr_t)getAlternate((void*)offs); if(p) { - printf_dump(LOG_DEBUG, " Apply %s R_X86_64_JUMP_SLOT %p with sym=%s(ver %d: %s%s%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, version, symname, vername?"@":"", vername?vername:"",*(void**)p, (void*)offs, ElfName(sym_elf)); + printf_dump(LOG_DEBUG, " Apply %s R_X86_64_JUMP_SLOT %p with sym=%s(%sver %d: %s%s%s) (%p -> %p / %s)\n", BindSym(bind), p, symname, veropt?"opt":"", version, symname, vername?"@":"", vername?vername:"",*(void**)p, (void*)offs, ElfName(sym_elf)); *p = offs; } else { - printf_log(LOG_NONE, "PltResolver: Warning, Symbol %s(ver %d: %s%s%s) found, but Jump Slot Offset is NULL \n", symname, version, symname, vername?"@":"", vername?vername:""); + printf_log(LOG_NONE, "PltResolver: Warning, Symbol %s(%sver %d: %s%s%s) found, but Jump Slot Offset is NULL \n", symname, veropt?"opt":"", version, symname, vername?"@":"", vername?vername:""); } } diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h index f13be551..7da8d6e5 100644 --- a/src/elfs/elfloader_private.h +++ b/src/elfs/elfloader_private.h @@ -3,8 +3,6 @@ typedef struct library_s library_t; typedef struct needed_libs_s needed_libs_t; -typedef struct kh_mapsymbols_s kh_mapsymbols_t; -typedef struct kh_defaultversion_s kh_defaultversion_t; typedef struct cleanup_s cleanup_t; #include <elf.h> @@ -48,6 +46,8 @@ typedef struct elfheader_s { int szVerDef; int e_type; uint32_t flags; + uintptr_t hash; + uintptr_t gnu_hash; intptr_t delta; // should be 0 void* image; // base of the elf image @@ -117,11 +117,6 @@ typedef struct elfheader_s { int clean_sz; int clean_cap; - kh_mapsymbols_t *mapsymbols; - kh_mapsymbols_t *weaksymbols; - kh_mapsymbols_t *localsymbols; - kh_defaultversion_t *globaldefver; // the global default version for symbols (the XXX@@vvvv of symbols) - kh_defaultversion_t *weakdefver; // the weak default version for symbols (the XXX@@vvvv of symbols) } elfheader_t; #define R_X86_64_NONE 0 /* No reloc */ @@ -171,4 +166,19 @@ typedef struct elfheader_s { elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec); +const char* BindSym(int bind); + +Elf64_Half GetSymbolVersionFlag(elfheader_t* h, int index); + +uint32_t old_elf_hash(const char* name); +Elf64_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt); +void old_elf_hash_dump(elfheader_t* h); +uint32_t new_elf_hash(const char *name); +Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt); +void new_elf_hash_dump(elfheader_t* h); + +Elf64_Sym* ElfLookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt); +Elf64_Sym* ElfSymTabLookup(elfheader_t* h, const char* symname); +Elf64_Sym* ElfDynSymLookup(elfheader_t* h, const char* symname); + #endif //__ELFLOADER_PRIVATE_H_ diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c index f9a3e844..803f7dce 100644 --- a/src/elfs/elfparser.c +++ b/src/elfs/elfparser.c @@ -13,6 +13,9 @@ #ifndef PN_XNUM #define PN_XNUM (0xffff) #endif +#ifndef DT_GNU_HASH +#define DT_GNU_HASH 0x6ffffef5 +#endif int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type) { @@ -284,6 +287,14 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec) h->flags = val; printf_dump(LOG_DEBUG, "The DT_FLAGS is 0x%x\n", h->flags); break; + case DT_HASH: + h->hash = ptr; + printf_dump(LOG_DEBUG, "The DT_HASH is at address %p\n", (void*)h->hash); + break; + case DT_GNU_HASH: + h->gnu_hash = ptr; + printf_dump(LOG_DEBUG, "The DT_GNU_HASH is at address %p\n", (void*)h->gnu_hash); + break; } } if(h->rel) { @@ -374,112 +385,15 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec) return h; } -const char* GetSymbolVersion(elfheader_t* h, int version) +const char* BindSym(int bind) { - if(version<2) - return NULL; - /*if(version==1) - return "*";*/ - if(h->VerNeed) { - Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); - while(ver) { - Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux); - for(int j=0; j<ver->vn_cnt; ++j) { - if(aux->vna_other==version) - return h->DynStr+aux->vna_name; - aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next); - } - ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; - } + switch(bind) { + case STB_GLOBAL: return "STB_GLOBAL"; + case STB_WEAK: return "STB_WEAK"; + case STB_LOCAL: return "STB_LOCAL"; + case STB_GNU_UNIQUE: return "STB_GNU_UNIQUE"; } - return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead -} - -const char* GetParentSymbolVersion(elfheader_t* h, int index) -{ - if(!h->VerDef || (index<1)) - return NULL; - Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta); - while(def) { - if(def->vd_ndx==index) { - if(def->vd_cnt<1) - return NULL; - /*if(def->vd_flags&VER_FLG_BASE) - return NULL;*/ - Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux); - return h->DynStr+aux->vda_name; // return Parent, so 1st aux - } - def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL; - } - return NULL; -} - -int GetVersionIndice(elfheader_t* h, const char* vername) -{ - if(!vername) - return 0; - if(h->VerDef) { - Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta); - while(def) { - Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux); - if(!strcmp(h->DynStr+aux->vda_name, vername)) - return def->vd_ndx; - def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL; - } - } - return 0; -} - -int GetNeededVersionCnt(elfheader_t* h, const char* libname) -{ - if(!libname) - return 0; - if(h->VerNeed) { - Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); - while(ver) { - char *filename = h->DynStr + ver->vn_file; - if(!strcmp(filename, libname)) - return ver->vn_cnt; - ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; - } - } - return 0; -} - -const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx) -{ - if(!libname) - return 0; - if(h->VerNeed) { - Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta); - while(ver) { - char *filename = h->DynStr + ver->vn_file; - Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux); - if(!strcmp(filename, libname)) { - for(int j=0; j<ver->vn_cnt; ++j) { - if(j==idx) - return h->DynStr+aux->vna_name; - aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next); - } - return NULL; // idx out of bound, return NULL... - } - ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL; - } - } - return NULL; -} - -int GetNeededVersionForLib(elfheader_t* h, const char* libname, const char* ver) -{ - if(!libname || !ver) - return 0; - int n = GetNeededVersionCnt(h, libname); - if(!n) - return 0; - for(int i=0; i<n; ++i) { - const char* vername = GetNeededVersionString(h, libname, i); - if(vername && !strcmp(ver, vername)) - return 1; - } - return 0; -} + static char tmp[50]; + sprintf(tmp, "??? 0x%x", bind); + return tmp; +} \ No newline at end of file |