From c845d0cf81a259e0d21be46841dc41a0f0ba5b0e Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Sat, 17 Aug 2024 15:59:09 +0200 Subject: [BOX32] Added 32bits elf alloc and load --- src/elfs/elfloader32.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/elfs/elfloader32.c (limited to 'src/elfs/elfloader32.c') diff --git a/src/elfs/elfloader32.c b/src/elfs/elfloader32.c new file mode 100644 index 00000000..1da3fc3b --- /dev/null +++ b/src/elfs/elfloader32.c @@ -0,0 +1,249 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _DLFCN_H +#include +#endif + +#include "custommem.h" +#include "box64version.h" +#include "elfloader.h" +#include "debug.h" +#include "elfload_dump.h" +#include "elfloader_private.h" +#include "librarian.h" +#include "x64run.h" +#include "bridge.h" +#include "wrapper.h" +#include "box64context.h" +#include "library.h" +#include "x64emu.h" +#include "box64stack.h" +#include "callback.h" +#include "box64stack.h" +#include "wine_tools.h" +#include "dictionnary.h" +#include "symbols.h" +#ifdef DYNAREC +#include "dynablock.h" +#endif +#include "../emu/x64emu_private.h" +#include "../emu/x64run_private.h" +#include "../tools/bridge_private.h" +#include "x64tls.h" +#include "box32.h" + +int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin) +{ + ptr_t offs = 0; + loadProtectionFromMap(); + int log_level = box64_load_addr?LOG_INFO:LOG_DEBUG; + + head->multiblock_n = 0; // count PHEntrie with LOAD + uintptr_t max_align = (box64_pagesize-1); + for (size_t i=0; inumPHEntries; ++i) + if(head->PHEntries._32[i].p_type == PT_LOAD && head->PHEntries._32[i].p_flags) { + ++head->multiblock_n; + } + + if(!head->vaddr && box64_load_addr) { + offs = to_ptrv(find31bitBlockNearHint((void*)box64_load_addr, head->memsz, max_align)); + box64_load_addr = offs + head->memsz; + box64_load_addr = (box64_load_addr+0x10ffffff)&~0xffffff; + } + if(!offs && !head->vaddr) + offs = (uintptr_t)find31bitBlockElf(head->memsz, mainbin, max_align); + // prereserve the whole elf image, without populating + size_t sz = head->memsz; + void* raw = NULL; + void* image = NULL; + if(!head->vaddr) { + sz += head->align; + raw = mmap64(from_ptrv(offs), sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); + image = (void*)(((uintptr_t)raw+max_align)&~max_align); + } else { + image = raw = mmap64(from_ptrv(head->vaddr), sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); + } + if(image!=MAP_FAILED && !head->vaddr && image!=from_ptrv(offs)) { + printf_log(LOG_INFO, "%s: Mmap64 for (@%p 0x%zx) for elf \"%s\" returned %p(%p/0x%zx) instead\n", (((uintptr_t)image)&max_align)?"Error":"Warning", from_ptrv(head->vaddr?head->vaddr:offs), head->memsz, head->name, image, raw, head->align); + offs = to_ptrv(image); + if(((uintptr_t)image)&max_align) { + munmap(raw, sz); + return 1; // that's an error, alocated memory is not aligned properly + } + } + if(image==MAP_FAILED || image!=from_ptrv(head->vaddr?head->vaddr:offs)) { + printf_log(LOG_NONE, "%s cannot create memory map (@%p 0x%zx) for elf \"%s\"", (image==MAP_FAILED)?"Error:":"Warning:", from_ptrv(head->vaddr?head->vaddr:offs), head->memsz, head->name); + if(image==MAP_FAILED) { + printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno)); + } else { + printf_log(LOG_NONE, " got %p\n", image); + } + if(image==MAP_FAILED) + return 1; + offs = to_ptrv(image)-head->vaddr; + } + printf_dump(log_level, "Pre-allocated 0x%zx byte at %p for %s\n", head->memsz, image, head->name); + head->delta = offs; + printf_dump(log_level, "Delta of %p (vaddr=%p) for Elf \"%s\"\n", from_ptrv(offs), from_ptrv(head->vaddr), head->name); + + head->image = image; + head->raw = raw; + head->raw_size = sz; + setProtection_elf((uintptr_t)raw, sz, 0); + + head->multiblocks = (multiblock_t*)box_calloc(head->multiblock_n, sizeof(multiblock_t)); + head->tlsbase = AddTLSPartition(context, head->tlssize); + // and now, create all individual blocks + head->memory = (char*)0xffffffff; + int n = 0; + for (size_t i=0; inumPHEntries; ++i) { + if(head->PHEntries._32[i].p_type == PT_LOAD && head->PHEntries._32[i].p_flags) { + Elf32_Phdr * e = &head->PHEntries._32[i]; + + head->multiblocks[n].flags = e->p_flags; + head->multiblocks[n].offs = e->p_offset; + head->multiblocks[n].paddr = e->p_paddr + offs; + head->multiblocks[n].size = e->p_filesz; + head->multiblocks[n].align = e->p_align; + uint8_t prot = PROT_READ|PROT_WRITE|((e->p_flags & PF_X)?PROT_EXEC:0); + // check if alignment is correct + uintptr_t balign = head->multiblocks[n].align-1; + if(balign<4095) balign = 4095; + head->multiblocks[n].asize = (e->p_memsz+(e->p_paddr&balign)+4095)&~4095; + int try_mmap = 1; + if(e->p_paddr&balign) + try_mmap = 0; + if(e->p_offset&(box64_pagesize-1)) + try_mmap = 0; + if(ALIGN(e->p_memsz)!=ALIGN(e->p_filesz)) + try_mmap = 0; + if(!e->p_filesz) + try_mmap = 0; + if(e->p_alignmultiblocks[n].size, head->multiblocks[n].asize, (void*)head->multiblocks[n].paddr, head->name); + void* p = mmap64( + (void*)head->multiblocks[n].paddr, + head->multiblocks[n].size, + prot, + MAP_PRIVATE|MAP_FIXED, //((prot&PROT_WRITE)?MAP_SHARED:MAP_PRIVATE)|MAP_FIXED, + head->fileno, + e->p_offset + ); + if(p==MAP_FAILED || p!=(void*)head->multiblocks[n].paddr) { + try_mmap = 0; + printf_dump(log_level, "Mapping failed, using regular mmap+read"); + } else { + 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; + + } + } + if(!try_mmap) { + uintptr_t paddr = head->multiblocks[n].paddr&~balign; + size_t asize = head->multiblocks[n].asize; + void* p = MAP_FAILED; + if(paddr==(paddr&~(box64_pagesize-1)) && (asize==ALIGN(asize))) { + printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", asize, e->p_memsz, (void*)paddr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name); + p = mmap64( + (void*)paddr, + asize, + prot|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, + -1, + 0 + ); + } else { + // difference in pagesize, so need to mmap only what needed to be... + //check startint point + uintptr_t new_addr = paddr; + ssize_t new_size = asize; + while(getProtection(new_addr) && (new_size>0)) { + new_size -= ALIGN(new_addr) - new_addr; + new_addr = ALIGN(new_addr); + } + if(new_size>0) { + printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", ALIGN(new_size), e->p_memsz, (void*)new_addr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name); + p = mmap64( + (void*)new_addr, + ALIGN(new_size), + prot|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, + -1, + 0 + ); + if(p==(void*)new_addr) + p = (void*)paddr; + } else { + p = (void*)paddr; + printf_dump(log_level, "Will read 0x%zx @%p for Elf \"%s\"\n", e->p_filesz, (void*)head->multiblocks[n].paddr, head->name); + } + } + if(p==MAP_FAILED || p!=(void*)paddr) { + printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%zx/0x%zx) for elf \"%s\"", (void*)paddr, asize, balign, head->name); + if(p==MAP_FAILED) { + printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno)); + } else { + printf_log(LOG_NONE, " got %p\n", p); + } + return 1; + } + setProtection_elf((uintptr_t)p, asize, prot); + head->multiblocks[n].p = p; + if(e->p_filesz) { + fseeko64(head->file, head->multiblocks[n].offs, SEEK_SET); + if(fread((void*)head->multiblocks[n].paddr, head->multiblocks[n].size, 1, head->file)!=1) { + printf_log(LOG_NONE, "Cannot read elf block (@%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)head->multiblocks[n].offs, head->multiblocks[n].asize, balign, head->name); + return 1; + } + } + if(!(prot&PROT_WRITE) && (paddr==(paddr&(box64_pagesize-1)) && (asize==ALIGN(asize)))) + mprotect((void*)paddr, asize, prot); + } +#ifdef DYNAREC + if(box64_dynarec && (e->p_flags & PF_X)) { + dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", head->multiblocks[n].p, (void*)head->multiblocks[n].asize); + addDBFromAddressRange((uintptr_t)head->multiblocks[n].p, head->multiblocks[n].asize); + } +#endif + if((uintptr_t)head->memory>(uintptr_t)head->multiblocks[n].p) + head->memory = (char*)head->multiblocks[n].p; + ++n; + } + if(head->PHEntries._32[i].p_type == PT_TLS) { + Elf32_Phdr * e = &head->PHEntries._32[i]; + char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase); + printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz); + if(e->p_filesz) { + fseeko64(head->file, e->p_offset, SEEK_SET); + if(fread(dest, e->p_filesz, 1, head->file)!=1) { + printf_log(LOG_NONE, "Fail to read PT_TLS part #%zu (size=%zd)\n", i, e->p_filesz); + return 1; + } + } + // zero'd difference between filesz and memsz + if(e->p_filesz != e->p_memsz) + memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz); + } + } + + // can close the elf file now! + fclose(head->file); + head->file = NULL; + head->fileno = -1; + + return 0; +} -- cgit 1.4.1 From 683e44baf97e9d58de60c90fa8c54d15142e0d18 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Sat, 17 Aug 2024 16:59:55 +0200 Subject: [BOX32] Added 32bits elf reloc type rel handling --- CMakeLists.txt | 1 + src/elfs/elfhash.c | 5 + src/elfs/elfhash32.c | 190 ++++++++++++++++++++++ src/elfs/elfloader.c | 43 ++--- src/elfs/elfloader32.c | 377 +++++++++++++++++++++++++++++++++++++++++++ src/elfs/elfloader_private.h | 6 +- src/include/elfloader.h | 1 - 7 files changed, 591 insertions(+), 32 deletions(-) create mode 100644 src/elfs/elfhash32.c (limited to 'src/elfs/elfloader32.c') diff --git a/CMakeLists.txt b/CMakeLists.txt index 62ee961c..1715d9fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -365,6 +365,7 @@ if(NOT STATICBUILD) endif() if(BOX32) list(APPEND ELFLOADER_SRC + "${BOX64_ROOT}/src/elfs/elfhash32.c" "${BOX64_ROOT}/src/elfs/elfloader32.c" "${BOX64_ROOT}/src/elfs/elfparser32.c" "${BOX64_ROOT}/src/elfs/elfload_dump32.c" diff --git a/src/elfs/elfhash.c b/src/elfs/elfhash.c index a20c31d9..966a18b7 100644 --- a/src/elfs/elfhash.c +++ b/src/elfs/elfhash.c @@ -374,6 +374,11 @@ static void new_elf_hash_dump(elfheader_t* h) printf_log(LOG_NONE, "\n===============\n"); } +#ifndef BOX32 +Elf32_Sym* ElfLookup32(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt) { return NULL; } +Elf32_Sym* ElfSymTabLookup32(elfheader_t* h, const char* symname) { return NULL; } +Elf32_Sym* ElfDynSymLookup32(elfheader_t* h, const char* symname) { return NULL; } +#endif Elf64_Sym* ElfLookup64(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt) { if(h->gnu_hash) diff --git a/src/elfs/elfhash32.c b/src/elfs/elfhash32.c new file mode 100644 index 00000000..00423b0a --- /dev/null +++ b/src/elfs/elfhash32.c @@ -0,0 +1,190 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "custommem.h" +#include "box64version.h" +#include "elfloader.h" +#include "debug.h" +#include "elfload_dump.h" +#include "elfloader_private.h" + +static int SymbolMatch(elfheader_t* h, uint32_t i, int ver, const char* vername, int local, int veropt) +{ + int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1; + if(version!=-1) version &=0x7fff; + const char* symvername = GetSymbolVersion(h, version); + Elf32_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>1 && flags==0) // flag is not WEAK, so global works + return 1; + if(ver<2 || !symvername) + return 0; + return strcmp(vername, symvername)?0:1; +} + +static Elf32_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._32[i].st_name; + if (!strcmp(symname, name) && SymbolMatch(h, i, ver, vername, local, veropt)) { + return &h->DynSym._32[i]; + } + } + return NULL; +} + + +static 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; iDynStr + h->DynSym._32[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; ignu_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._32[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._32[symidx]; + } + if(symhash&1) + return NULL; + symidx++; + } +} + +static 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=symoffset) { + const char* name = h->DynStr + h->DynSym._32[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"); +} + +Elf32_Sym* ElfLookup32(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); +} + +Elf32_Sym* ElfSymTabLookup32(elfheader_t* h, const char* symname) +{ + if(!h->SymTab._32) + return 0; + for(size_t i=0; inumSymTab; ++i) { + Elf32_Sym* sym = &h->SymTab._32[i]; + int type = ELF32_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; +} + +Elf32_Sym* ElfDynSymLookup32(elfheader_t* h, const char* symname) +{ + if(!h->DynSym._32) + return 0; + for(size_t i=0; inumDynSym; ++i) { + Elf32_Sym* sym = &h->DynSym._32[i]; + int type = ELF32_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/elfloader.c b/src/elfs/elfloader.c index e206fcc6..248c4282 100644 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -46,7 +46,7 @@ void* my__IO_2_1_stdin_ = NULL; void* my__IO_2_1_stdout_ = NULL; // return the index of header (-1 if it doesn't exist) -int getElfIndex(box64context_t* ctx, elfheader_t* head) { +static int getElfIndex(box64context_t* ctx, elfheader_t* head) { for (int i=0; ielfsize; ++i) if(ctx->elfs[i]==head) return i; @@ -463,17 +463,10 @@ static int IsSymInElfSpace(const elfheader_t* h, Elf64_Sym* sym) if(!h || !sym) return 0; uintptr_t addr = (uintptr_t)sym; - if(box64_is32bits) { - if(h->SymTab._32 && addr>=(uintptr_t)h->SymTab._32 && addr<(uintptr_t)&h->SymTab._32[h->numSymTab]) - return 1; - if(h->DynSym._32 && addr>=(uintptr_t)h->DynSym._32 && addr<(uintptr_t)&h->DynSym._32[h->numDynSym]) - return 1; - } else { - if(h->SymTab._64 && addr>=(uintptr_t)h->SymTab._64 && addr<(uintptr_t)&h->SymTab._64[h->numSymTab]) - return 1; - if(h->DynSym._64 && addr>=(uintptr_t)h->DynSym._64 && addr<(uintptr_t)&h->DynSym._64[h->numDynSym]) - return 1; - } + if(h->SymTab._64 && addr>=(uintptr_t)h->SymTab._64 && addr<(uintptr_t)&h->SymTab._64[h->numSymTab]) + return 1; + if(h->DynSym._64 && addr>=(uintptr_t)h->DynSym._64 && addr<(uintptr_t)&h->DynSym._64[h->numDynSym]) + return 1; return 0; } static elfheader_t* FindElfSymbol(box64context_t *context, Elf64_Sym* sym) @@ -487,7 +480,7 @@ static elfheader_t* FindElfSymbol(box64context_t *context, Elf64_Sym* sym) 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) +static 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; @@ -535,7 +528,7 @@ EXPORT uintptr_t my__dl_tlsdesc_undefweak(x64emu_t* emu) return td->arg; } -void GrabX64CopyMainElfReloc(elfheader_t* head) +static void GrabX64CopyMainElfReloc(elfheader_t* head) { if(head->rela) { int cnt = head->relasz / head->relaent; @@ -557,21 +550,6 @@ void GrabX64CopyMainElfReloc(elfheader_t* head) } } } -void CheckGNUUniqueBindings(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, "Checking for symbol with STB_GNU_UNIQUE bindingsfor %s\n", head->name); - for (int i=0; ignuunique = 1; - return; // can stop searching - } - } - } -} static elfheader_t* checkElfLib(elfheader_t* h, library_t* lib) { @@ -857,7 +835,12 @@ static int RelocateElfRELR(elfheader_t *head, int cnt, Elf64_Relr *relr) { return 0; } -int RelocateElf32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head) { /* TODO */ return -1; } +int RelocateElf32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head) +#ifndef BOX32 +{ return -1; } +#else + ; +#endif int RelocateElf64(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head) { if((head->flags&DF_BIND_NOW) && !bindnow) { diff --git a/src/elfs/elfloader32.c b/src/elfs/elfloader32.c index 1da3fc3b..3b30bc07 100644 --- a/src/elfs/elfloader32.c +++ b/src/elfs/elfloader32.c @@ -42,6 +42,24 @@ #include "x64tls.h" #include "box32.h" +// return the index of header (-1 if it doesn't exist) +static int getElfIndex(box64context_t* ctx, elfheader_t* head) { + for (int i=0; ielfsize; ++i) + if(ctx->elfs[i]==head) + return i; + return -1; +} + +static elfheader_t* checkElfLib(elfheader_t* h, library_t* lib) +{ + if(h && lib) { + if(!h->needed) + h->needed = new_neededlib(1); + add1libref_neededlib(h->needed, lib); + } + return h; +} + int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin) { ptr_t offs = 0; @@ -247,3 +265,362 @@ int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin return 0; } + +static int IsSymInElfSpace(const elfheader_t* h, Elf32_Sym* sym) +{ + if(!h || !sym) + return 0; + uintptr_t addr = (uintptr_t)sym; + if(h->SymTab._32 && addr>=(uintptr_t)h->SymTab._32 && addr<(uintptr_t)&h->SymTab._32[h->numSymTab]) + return 1; + if(h->DynSym._32 && addr>=(uintptr_t)h->DynSym._32 && addr<(uintptr_t)&h->DynSym._32[h->numDynSym]) + return 1; + return 0; +} +static elfheader_t* FindElfSymbol(box64context_t *context, Elf32_Sym* sym) +{ + if(!sym) + return NULL; + for (int i=0; ielfsize; ++i) + if(IsSymInElfSpace(context->elfs[i], sym)) + return context->elfs[i]; + + return NULL; +} + +void GrabR386CopyMainElfReloc(elfheader_t* head) +{ + if(head->rela) { + int cnt = head->relasz / head->relaent; + Elf32_Rel* rel = (Elf32_Rel *)(head->rela + head->delta); + printf_dump(LOG_DEBUG, "Grabbing R_386_COPY Relocation(s) in advance for %s\n", head->name); + for (int i=0; iDynSym._32[ELF32_R_SYM(rel[i].r_info)]; + const char* symname = SymName32(head, sym); + int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:-1; + if(version!=-1) version &=0x7fff; + const char* vername = GetSymbolVersion(head, version); + Elf32_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); + } + } + } +} + + +static int FindR386COPYRel(elfheader_t* h, const char* name, ptr_t *offs, uint32_t** p, size_t size, int version, const char* vername, int veropt) +{ + if(!h) + return 0; + if(!h->rel) + return 0; + if(h->relent) { + Elf32_Rel * rel = (Elf32_Rel *)(h->rel + h->delta); + int cnt = h->relsz / h->relent; + for (int i=0; iDynSym._32[ELF32_R_SYM(rel[i].r_info)]; + const char* symname = SymName32(h, sym); + if((t==R_386_COPY) && symname && !strcmp(symname, name) && (sym->st_size==size)) { + int version2 = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[ELF32_R_SYM(rel[i].r_info)]:-1; + if(version2!=-1) version2 &= 0x7fff; + if(version && !version2) version2=-1; // match a versionned symbol against a global "local" symbol + const char* vername2 = GetSymbolVersion(h, version2); + Elf32_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 = (uint32_t*)(rel[i].r_offset + h->delta); + return 1; + } + } + } + } + return 0; +} + +static int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf32_Rel *rel, int* need_resolv) +{ + int ret_ok = 0; + for (int i=0; iDynSym._32[ELF32_R_SYM(rel[i].r_info)]; + int bind = ELF32_ST_BIND(sym->st_info); + //uint32_t ndx = sym->st_shndx; + const char* symname = SymName32(head, sym); + uint32_t *p = (uint32_t*)(rel[i].r_offset + head->delta); + uintptr_t offs = 0; + uintptr_t end = 0; + size_t size = sym->st_size; + elfheader_t* sym_elf = NULL; + elfheader_t* last_elf = NULL; + int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:-1; + if(version!=-1) version &=0x7fff; + const char* vername = GetSymbolVersion(head, version); + Elf32_Half flags = GetSymbolVersionFlag(head, version); + int veropt = flags?0:1; + Elf32_Sym* elfsym = NULL; + int vis = ELF64_ST_VISIBILITY(sym->st_other); + if(vis==STV_PROTECTED) { + elfsym = ElfDynSymLookup32(head, symname); + printf_log(LOG_DEBUG, "Symbol %s from %s is PROTECTED\n", symname, head->name); + } else { + 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 = ElfDynSymLookup32(head, symname); + if(elfsym && elfsym->st_shndx) { + offs = elfsym->st_value + head->delta; + end = offs + elfsym->st_size; + } + if(!offs && !end && local_maplib && deepbind) + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); + if(!offs && !end) + GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + 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); + } + } + sym_elf = FindElfSymbol(my_context, elfsym); + if(elfsym && (ELF32_ST_TYPE(elfsym->st_info)==STT_TLS)) + offs = elfsym->st_value; + uintptr_t globoffs, globend; + uint32_t* globp; + uintptr_t tmp = 0; + intptr_t delta; + switch(t) { + case R_386_NONE: + // can be ignored + printf_dump(LOG_NEVER, "Ignoring [%d] %s %p (%p)\n", i, DumpRelType32(t), p, from_ptrv(p?(*p):0)); + break; + case R_386_PC32: + if (!offs) { + printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_PC32 %p (%p) in %s\n", symname, p, from_ptrv(*p), head->name); + ret_ok = 1; + } + if(offs) + printf_dump(LOG_NEVER, "Apply [%d] %s R_386_PC32 %p with sym=%s (ver=%d/%s), (%p -> %p/%p)\n", i, (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, vername?vername:"(none)", from_ptrv(*(ptr_t*)p), from_ptrv(*(ptr_t*)p+(offs-to_ptrv(p))), from_ptrv(offs)); + offs = (offs - to_ptrv(p)); + *p += offs; + break; + case R_386_RELATIVE: + printf_dump(LOG_NEVER, "Apply [%d] %s R_386_RELATIVE %p (%p -> %p)\n", i, (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, from_ptrv(*p), (void*)((*p)+head->delta)); + *p += head->delta; + break; + case R_386_COPY: + globoffs = offs; + globend = end; + offs = end = 0; + 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, 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_386_COPY @%p with sym=%s (%sver=%d/%s), @%p size=%ld\n", p, symname, veropt?"opt":"", version, vername?vername:"(none)", from_ptrv(offs), sym->st_size); + if(p!=from_ptrv(offs)) + memmove(p, from_ptrv(offs), sym->st_size); + sym_elf = FindElfAddress(my_context, offs); + if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); + } else { + printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply REL R_386_COPY @%p (%p) in %s\n", symname, p, from_ptrv(*p), head->name); + } + break; + case R_386_GLOB_DAT: + if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { + globp = (uint32_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, from_ptrv(p?(*p):0), + from_ptrv(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 (!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_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 (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, from_ptrv(p?(*p):0), from_ptrv(offs), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)"); + *p = offs; + if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); + } + } + break; + case R_386_JMP_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)) + || ((symname && strstr(symname, "__pthread_unwind_next")==symname)) + || !tmp + || !((tmp>=head->plt && tmpplt_end) || (tmp>=head->gotplt && tmpgotplt_end)) + || !need_resolv + || bindnow + ) { + if (!offs) { + if(bind==STB_WEAK) { + printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_JMP_SLOT %p (%p)\n", symname, p, from_ptrv(*p)); + } else { + printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT %p (%p) in %s\n", symname, p, from_ptrv(*p), head->name); + ret_ok = 1; + } + } else { + if(p) { + printf_dump(LOG_NEVER, "Apply %s R_386_JMP_SLOT %p with sym=%s(%s%s%s) (%p -> %p)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, symname, vername?"@":"", vername?vername:"", from_ptrv(*p), from_ptrv(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_386_JMP_SLOT %p (0x%x->0x%0x) with sym=%s(%s%s%s/version %d) to be apply later\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, *p, *p+head->delta, symname, symname, vername?"@":"", vername?vername:"", version); + *p += head->delta; + *need_resolv = 1; + } + break; + case R_386_32: + if (!offs) { + if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start")) { + printf_log(LOG_NONE, "Error: Symbol sym=%s(%s%s%s/version %d) not found, cannot apply R_386_32 %p (%p) in %s\n", symname, symname, vername?"@":"", vername?vername:"", version, p, from_ptrv(*p), head->name); + ret_ok = 1; + } + } else { + printf_dump(LOG_NEVER, "Apply %s R_386_32 %p with sym=%s (ver=%d/%s) (%p -> %p)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, vername?vername:"(none)", from_ptrv(*p), from_ptrv(offs+*p)); + *p += offs; + } + break; + case R_386_TLS_TPOFF: + // Negated offset in static TLS block + { + if(!symname || !symname[0]) { + sym_elf = head; + offs = sym->st_value; + } + if(sym_elf) { + delta = *(int32_t*)p; + printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, delta, sym_elf->tlsbase, (int32_t)offs, end-offs); + *p = (uintptr_t)((int32_t)offs + sym_elf->tlsbase); + } else { + printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, (int32_t)offs); + } + } + break; + case R_386_TLS_TPOFF32: + // Non-negated offset in static TLS block??? + { + if(!symname || !symname[0]) { + sym_elf = head; + offs = sym->st_value; + } + if(sym_elf) { + delta = *(int32_t*)p; + printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, delta, -sym_elf->tlsbase, (int32_t)offs, end-offs); + *p = (uintptr_t)((int32_t)offs - sym_elf->tlsbase); + } else { + printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, (int32_t)offs); + } + } + break; + case R_386_TLS_DTPMOD32: + // ID of module containing symbol + if(!symname || symname[0]=='\0' || bind==STB_LOCAL) { + offs = getElfIndex(my_context, head); + sym_elf = head; + } else { + offs = getElfIndex(my_context, sym_elf); + } + if(p) { + printf_dump(LOG_NEVER, "Apply %s %s %p with sym=%s (%p -> %p)\n", "R_386_TLS_DTPMOD32", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, from_ptrv(*p), from_ptrv(offs)); + *p = offs; + } else { + printf_log(LOG_NONE, "Warning, Symbol %s or Elf not found, but R_386_TLS_DTPMOD32 Slot Offset is NULL \n", symname); + } + break; + case R_386_TLS_DTPOFF32: + // Offset in TLS block + if (!offs && !end) { + if(bind==STB_WEAK) { + printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 %p (%p)\n", symname, p, from_ptrv(*p)); + } else { + printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 %p (%p) in %s\n", symname, p, from_ptrv(*p), head->name); + } + } else { + if(!symname || !symname[0]) { + offs = (uintptr_t)((intptr_t)(head->tlsaddr + head->delta) - (intptr_t)offs); // negative offset + } + if(p) { + printf_dump(LOG_NEVER, "Apply %s R_386_TLS_DTPOFF32 %p with sym=%s (ver=%d/%s) (%zd -> %zd)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, vername?vername:"(none)", (intptr_t)*p, (intptr_t)offs); + *p = offs; + } else { + printf_log(LOG_NONE, "Warning, Symbol %s found, but R_386_TLS_DTPOFF32 Slot Offset is NULL \n", symname); + } + } + break; + default: + printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p) for %s\n", i, DumpRelType32(ELF32_R_TYPE(rel[i].r_info)), p, symname?symname:"(nil)"); + } + } + return bindnow?ret_ok:0; +} + +static int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf32_Rela *rela, int* need_resolv) +{ + printf_log(LOG_NONE, "Error: RELA type of Relocation unsupported (only REL)\n"); + return 1; +} + +static int RelocateElfRELR(elfheader_t *head, int cnt, Elf32_Relr *relr) +{ + printf_log(LOG_NONE, "Error: RELR type of Relocation unsupported (only REL)\n"); + return 1; +} + +int RelocateElf32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head) +{ + if(0 && (head->flags&DF_BIND_NOW) && !bindnow) { // disable for now, needs more symbol in a fow libs like gtk and nss3 + bindnow = 1; + printf_log(LOG_DEBUG, "Forcing %s to Bind Now\n", head->name); + } + if(head->relr) { + int cnt = head->relrsz / head->relrent; + DumpRelRTable32(head, cnt, (Elf32_Relr *)(head->relr + head->delta), "RelR"); + printf_log(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s\n", cnt, head->name); + if(RelocateElfRELR(head, cnt, (Elf32_Relr *)(head->relr + head->delta))) + return -1; + } + if(head->rel) { + int cnt = head->relsz / head->relent; + DumpRelTable32(head, cnt, (Elf32_Rel *)(head->rel + head->delta), "Rel"); + printf_log(LOG_DEBUG, "Applying %d Relocation(s) for %s\n", cnt, head->name); + if(RelocateElfREL(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf32_Rel *)(head->rel + head->delta), NULL)) + return -1; + } + if(head->rela) { + int cnt = head->relasz / head->relaent; + DumpRelATable32(head, cnt, (Elf32_Rela *)(head->rela + head->delta), "RelA"); + printf_log(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s\n", cnt, head->name); + if(RelocateElfRELA(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf32_Rela *)(head->rela + head->delta), NULL)) + return -1; + } + return 0; +} diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h index 3743ce25..6bcf6d82 100644 --- a/src/elfs/elfloader_private.h +++ b/src/elfs/elfloader_private.h @@ -203,11 +203,15 @@ elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec); const char* BindSym(int bind); -Elf64_Half GetSymbolVersionFlag(elfheader_t* h, int index); +uint16_t GetSymbolVersionFlag(elfheader_t* h, int index); uint32_t old_elf_hash(const char* name); uint32_t new_elf_hash(const char *name); +Elf32_Sym* ElfLookup32(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt); +Elf32_Sym* ElfSymTabLookup32(elfheader_t* h, const char* symname); +Elf32_Sym* ElfDynSymLookup32(elfheader_t* h, const char* symname); + Elf64_Sym* ElfLookup64(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt); Elf64_Sym* ElfSymTabLookup64(elfheader_t* h, const char* symname); Elf64_Sym* ElfDynSymLookup64(elfheader_t* h, const char* symname); diff --git a/src/include/elfloader.h b/src/include/elfloader.h index 2bce3c64..edaf9771 100644 --- a/src/include/elfloader.h +++ b/src/include/elfloader.h @@ -45,7 +45,6 @@ int CalcLoadAddr(elfheader_t* head); int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin); void FreeElfMemory(elfheader_t* head); int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verneeded); -void GrabX64CopyMainElfReloc(elfheader_t* head); int RelocateElf(lib_t *maplib, lib_t* local_maplib, int bindnow, int deepbind, elfheader_t* head); int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, int bindnow, int deepbind, elfheader_t* head); void CalcStack(elfheader_t* h, uint64_t* stacksz, size_t* stackalign); -- cgit 1.4.1