diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-03-03 16:43:42 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-03-03 16:43:42 +0100 |
| commit | f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d (patch) | |
| tree | 211276c3587721126ded00be46487bf23b605591 /src | |
| parent | f73fbd3cee38b4c0086c934d73972375c9c8c7d6 (diff) | |
| download | box64-f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d.tar.gz box64-f4829a8ce42b1abbcc8621802d6c6fad3a56cd5d.zip | |
More infrastructure added to elf and x64 emu
Diffstat (limited to 'src')
37 files changed, 9404 insertions, 248 deletions
diff --git a/src/box64context.c b/src/box64context.c index fa4b74b7..4c75e98e 100755 --- a/src/box64context.c +++ b/src/box64context.c @@ -13,7 +13,10 @@ #include "threads.h" #include "x64trace.h" #include "bridge.h" - +#include "librarian.h" +#include "library.h" +#include "wrapper.h" +#include "x64emu.h" EXPORTDYN void initAllHelpers(box64context_t* context) @@ -35,7 +38,7 @@ void finiAllHelpers(box64context_t* context) return; fini_pthread_helper(context); //fini_signal_helper(); - //cleanAlternate(); + cleanAlternate(); fini_custommem_helper(context); finied = 1; } @@ -80,16 +83,28 @@ box64context_t *NewBox64Context(int argc) init_custommem_helper(context); + context->maplib = NewLibrarian(context, 1); + context->local_maplib = NewLibrarian(context, 1); context->system = NewBridge(); // create vsyscall -// context->vsyscall = AddBridge(context->system, vFv, x64Syscall, 0); + context->vsyscall = AddBridge(context->system, vFv, x64Syscall, 0); context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL); - //context->dlprivate = NewDLPrivate(); + context->dlprivate = NewDLPrivate(); context->argc = argc; context->argv = (char**)calloc(context->argc+1, sizeof(char*)); + pthread_mutex_init(&context->mutex_once, NULL); + pthread_mutex_init(&context->mutex_once2, NULL); + pthread_mutex_init(&context->mutex_trace, NULL); +#ifndef DYNAREC + pthread_mutex_init(&context->mutex_lock, NULL); +#else + pthread_mutex_init(&context->mutex_dyndump, NULL); +#endif + pthread_mutex_init(&context->mutex_tls, NULL); pthread_mutex_init(&context->mutex_thread, NULL); + pthread_key_create(&context->tlskey, free_tlsdatasize); for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255); @@ -107,8 +122,21 @@ void FreeBox64Context(box64context_t** context) if(!context) return; + if(--(*context)->forked >= 0) + return; + box64context_t* ctx = *context; // local copy to do the cleanning + for(int i=0; i<ctx->elfsize; ++i) { + FreeElfHeader(&ctx->elfs[i]); + } + free(ctx->elfs); + + if(ctx->maplib) + FreeLibrarian(&ctx->maplib); + if(ctx->local_maplib) + FreeLibrarian(&ctx->local_maplib); + FreeCollection(&ctx->box64_path); FreeCollection(&ctx->box64_ld_lib); FreeCollection(&ctx->box64_emulated_libs); @@ -118,12 +146,21 @@ void FreeBox64Context(box64context_t** context) if(ctx->zydis) DeleteX64Trace(ctx); + if(ctx->deferedInitList) + free(ctx->deferedInitList); + free(ctx->argv); for (int i=0; i<ctx->envc; ++i) free(ctx->envv[i]); free(ctx->envv); + if(ctx->atfork_sz) { + free(ctx->atforks); + ctx->atforks = NULL; + ctx->atfork_sz = ctx->atfork_cap = 0; + } + for(int i=0; i<MAX_SIGNAL; ++i) if(ctx->signals[i]!=0 && ctx->signals[i]!=1) { signal(i, SIG_DFL); @@ -133,7 +170,7 @@ void FreeBox64Context(box64context_t** context) CleanStackSize(ctx); - //FreeDLPrivate(&ctx->dlprivate); + FreeDLPrivate(&ctx->dlprivate); free(ctx->stack); @@ -142,6 +179,10 @@ void FreeBox64Context(box64context_t** context) FreeBridge(&ctx->system); +// freeGLProcWrapper(ctx); +// freeALProcWrapper(ctx); + + void* ptr; if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) { free_tlsdatasize(ptr); @@ -152,8 +193,22 @@ void FreeBox64Context(box64context_t** context) if(ctx->tlsdata) free(ctx->tlsdata); + pthread_mutex_destroy(&ctx->mutex_once); + pthread_mutex_destroy(&ctx->mutex_once2); + pthread_mutex_destroy(&ctx->mutex_trace); +#ifndef DYNAREC + pthread_mutex_destroy(&ctx->mutex_lock); +#else + pthread_mutex_destroy(&ctx->mutex_dyndump); +#endif + pthread_mutex_destroy(&ctx->mutex_tls); pthread_mutex_destroy(&ctx->mutex_thread); + free_neededlib(&ctx->neededlibs); + + if(ctx->emu_sig) + FreeX64Emu(&ctx->emu_sig); + finiAllHelpers(ctx); free(ctx); @@ -187,7 +242,7 @@ int AddTLSPartition(box64context_t* context, int tlssize) { return -context->tlssize; // negative offset } -/* + void add_neededlib(needed_libs_t* needed, library_t* lib) { if(!needed) @@ -209,4 +264,3 @@ void free_neededlib(needed_libs_t* needed) free(needed->libs); needed->libs = NULL; } -*/ \ No newline at end of file diff --git a/src/dynarec/dynarec.c b/src/dynarec/dynarec.c new file mode 100755 index 00000000..c88cd61f --- /dev/null +++ b/src/dynarec/dynarec.c @@ -0,0 +1,216 @@ +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <errno.h> +#include <setjmp.h> + +#include "debug.h" +#include "box64context.h" +#include "dynarec.h" +#include "emu/x64emu_private.h" +#include "tools/bridge_private.h" +#include "x64run.h" +#include "x64emu.h" +#include "box64stack.h" +#include "callback.h" +#include "emu/x64run_private.h" +#include "x64trace.h" +#include "threads.h" +#ifdef DYNAREC +#include "dynablock.h" +#include "dynablock_private.h" +#endif + +#ifdef DYNAREC +#ifdef ARM +void arm_prolog(x64emu_t* emu, void* addr) EXPORTDYN; +void arm_epilog() EXPORTDYN; +void arm_epilog_fast() EXPORTDYN; +#endif +#endif + +#ifdef DYNAREC +#ifdef HAVE_TRACE +uintptr_t getX64Address(dynablock_t* db, uintptr_t arm_addr); +#endif +void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2) +{ + #ifdef HAVE_TRACE + if(!addr) { + x2-=8; // actual PC is 2 instructions ahead + dynablock_t* db = FindDynablockFromNativeAddress(x2); + printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL); + } + #endif + dynablock_t* current = NULL; + void * jblock; + dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t); + if(!block) { + // no block, let link table as is... + //tableupdate(arm_epilog, addr, table); + return arm_epilog; + } + if(!block->done) { + // not finished yet... leave linker + //tableupdate(arm_linker, addr, table); + return arm_epilog; + } + if(!(jblock=block->block)) { + // null block, but done: go to epilog, no linker here + return arm_epilog; + } + //dynablock_t *father = block->father?block->father:block; + return jblock; +} +#endif + +void DynaCall(x64emu_t* emu, uintptr_t addr) +{ + // prepare setjump for signal handling + emu_jmpbuf_t *ejb = NULL; + int jmpbuf_reset = 0; + if(emu->type == EMUTYPE_MAIN) { + ejb = GetJmpBuf(); + if(!ejb->jmpbuf_ok) { + ejb->emu = emu; + ejb->jmpbuf_ok = 1; + jmpbuf_reset = 1; + if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) { + printf_log(LOG_DEBUG, "Setjmp DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]); + addr = R_RIP; // not sure if it should still be inside DynaCall! + } + } + } +#ifdef DYNAREC + if(!box86_dynarec) +#endif + EmuCall(emu, addr); +#ifdef DYNAREC + else { + uint64_t old_rsp = R_RSP; + uint64_t old_rbx = R_RBX; + uint64_t old_rdi = R_RDI; + uint64_t old_rsi = R_RSI; + uint64_t old_rbp = R_RBP; + uint64_t old_rip = R_RIP; + PushExit(emu); + R_RIP = addr; + emu->df = d_none; + dynablock_t* block = NULL; + dynablock_t* current = NULL; + while(!emu->quit) { + block = DBGetBlock(emu, R_RIP, 1, ¤t); + current = block; + if(!block || !block->block || !block->done) { + // no block, of block doesn't have DynaRec content (yet, temp is not null) + // Use interpreter (should use single instruction step...) + dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu); + Run(emu, 1); + } else { + dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu); + CHECK_FLAGS(emu); + // block is here, let's run it! + #ifdef ARM + arm_prolog(emu, block->block); + #endif + } + if(emu->fork) { + int forktype = emu->fork; + emu->quit = 0; + emu->fork = 0; + emu = x86emu_fork(emu, forktype); + if(emu->type == EMUTYPE_MAIN) { + ejb = GetJmpBuf(); + ejb->emu = emu; + ejb->jmpbuf_ok = 1; + jmpbuf_reset = 1; + if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) { + printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]); + addr = R_RIP; + } + } + } + } + emu->quit = 0; // reset Quit flags... + emu->df = d_none; + if(emu->quitonlongjmp && emu->longjmp) { + emu->longjmp = 0; // don't change anything because of the longjmp + } else { + R_RBX = old_rbx; + R_RDI = old_rdi; + R_RSI = old_rsi; + R_RBP = old_rbp; + R_RSP = old_rsp; + R_RIP = old_rip; // and set back instruction pointer + } + } +#endif + // clear the setjmp + if(ejb && jmpbuf_reset) + ejb->jmpbuf_ok = 0; +} + +int DynaRun(x64emu_t* emu) +{ + // prepare setjump for signal handling + emu_jmpbuf_t *ejb = NULL; +#ifdef DYNAREC + int jmpbuf_reset = 1; +#endif + if(emu->type == EMUTYPE_MAIN) { + ejb = GetJmpBuf(); + if(!ejb->jmpbuf_ok) { + ejb->emu = emu; + ejb->jmpbuf_ok = 1; +#ifdef DYNAREC + jmpbuf_reset = 1; +#endif + if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) + printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]); + } + } +#ifdef DYNAREC + if(!box86_dynarec) +#endif + return Run(emu, 0); +#ifdef DYNAREC + else { + dynablock_t* block = NULL; + dynablock_t* current = NULL; + while(!emu->quit) { + block = DBGetBlock(emu, R_RIP, 1, ¤t); + current = block; + if(!block || !block->block || !block->done) { + // no block, of block doesn't have DynaRec content (yet, temp is not null) + // Use interpreter (should use single instruction step...) + dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu); + Run(emu, 1); + } else { + dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu); + // block is here, let's run it! + #ifdef ARM + arm_prolog(emu, block->block); + #endif + } + if(emu->fork) { + int forktype = emu->fork; + emu->quit = 0; + emu->fork = 0; + emu = x86emu_fork(emu, forktype); + if(emu->type == EMUTYPE_MAIN) { + ejb = GetJmpBuf(); + ejb->emu = emu; + ejb->jmpbuf_ok = 1; + jmpbuf_reset = 1; + if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) + printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]); + } + } + } + } + // clear the setjmp + if(ejb && jmpbuf_reset) + ejb->jmpbuf_ok = 0; + return 0; +#endif +} \ No newline at end of file diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c index 1c87f7fc..bf90c9e1 100755 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -16,24 +16,24 @@ #include "debug.h" #include "elfload_dump.h" #include "elfloader_private.h" -//#include "librarian.h" -//#include "x86run.h" -//#include "bridge.h" -//#include "wrapper.h" +#include "librarian.h" +#include "x64run.h" +#include "bridge.h" +#include "wrapper.h" #include "box64context.h" -//#include "library.h" -//#include "x86emu.h" -//#include "box64stack.h" -//#include "callback.h" +#include "library.h" +#include "x64emu.h" +#include "box64stack.h" +#include "callback.h" //#include "dynarec.h" -//#include "box64stack.h" +#include "box64stack.h" #include "custommem.h" #include "wine_tools.h" -//#ifdef DYNAREC -//#include "dynablock.h" -//#endif -//#include "../emu/x86emu_private.h" -//#include "x86tls.h" +#ifdef DYNAREC +#include "dynablock.h" +#endif +#include "../emu/x64emu_private.h" +#include "x64tls.h" void* my__IO_2_1_stderr_ = NULL; void* my__IO_2_1_stdin_ = NULL; @@ -349,8 +349,8 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head) // TLS data are just a copy, no need to re-load it return 0; } -#if 0 -int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t** p) + +int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p) { if(!h) return 0; @@ -362,9 +362,9 @@ int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t* int t = ELF64_R_TYPE(rel[i].r_info); Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rel[i].r_info)]; const char* symname = SymName(h, sym); - if(!strcmp(symname, name) && t==R_386_COPY) { + if(!strcmp(symname, name) && t==R_X86_64_COPY) { *offs = sym->st_value + h->delta; - *p = (uint32_t*)(rel[i].r_offset + h->delta); + *p = (uint64_t*)(rel[i].r_offset + h->delta); return 1; } } @@ -378,25 +378,23 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn 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); - uint32_t ndx = sym->st_shndx; - uint32_t *p = (uint32_t*)(rel[i].r_offset + head->delta); + 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; uintptr_t tmp = 0; - elfheader_t* h_tls = head; if(bind==STB_LOCAL) { offs = sym->st_value + head->delta; end = offs + sym->st_size; } else { // this is probably very very wrong. A proprer way to get reloc need to be writen, 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_386_GLOB_DAT) { + 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(!offs && !end) { - h_tls = NULL; if(local_maplib) GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end); if(!offs && !end) @@ -404,48 +402,27 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn } } uintptr_t globoffs, globend; - uint32_t* globp; - int delta; + uint64_t* globp; switch(t) { - case R_386_NONE: + case R_X86_64_NONE: // can be ignored printf_log(LOG_DUMP, "Ignoring %s @%p (%p)\n", DumpRelType(t), p, (void*)(p?(*p):0)); break; - case R_386_TLS_TPOFF: - // Negated offset in static TLS block - { - if(h_tls) - offs = sym->st_value; - else { - if(local_maplib) - h_tls = GetGlobalSymbolElf(local_maplib, symname); - if(!h_tls) - h_tls = GetGlobalSymbolElf(maplib, symname); - } - if(h_tls) { - delta = *(int*)p; - printf_log(LOG_DUMP, "Applying %s %s on %s @%p (%d -> %d)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, (int32_t)offs + h_tls->tlsbase); - *p = (uint32_t)((int32_t)offs + h_tls->tlsbase); - } else { - printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, (int32_t)offs); - } - } - break; - case R_386_PC32: + case R_X86_64_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, *(void**)p, head->name); + 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); } offs = (offs - (uintptr_t)p); if(!offs) - printf_log(LOG_DUMP, "Apply %s R_386_PC32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(*(uintptr_t*)p+offs)); + printf_log(LOG_DUMP, "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_386_GLOB_DAT: - if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp)) { + case R_X86_64_GLOB_DAT: + if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp)) { // set global offs / size for the symbol offs = sym->st_value + head->delta; end = offs + sym->st_size; - printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) size=%d on sym=%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); + printf_log(LOG_DUMP, "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, (void*)globoffs, sym->st_size, symname); *p = globoffs; AddWeakSymbol(GetGlobalData(maplib), symname, offs, end-offs+1); } else { @@ -456,14 +433,14 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn } if (!offs) { if(strcmp(symname, "__gmon_start__")) - printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name); + printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name); } else { - printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname); + printf_log(LOG_DUMP, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname); *p = offs; } } break; - case R_386_COPY: + case R_X86_64_COPY: if(offs) { uintptr_t old_offs = offs; uintptr_t old_end = end; @@ -479,7 +456,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn offs = old_offs; end = old_end; } - printf_log(LOG_DUMP, "Apply %s R_386_COPY @%p with sym=%s, @%p size=%d (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size); + printf_log(LOG_DUMP, "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(LOG_DUMP<=box64_log) { uint32_t*k = (uint32_t*)p; @@ -488,64 +465,23 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn printf_log(LOG_DUMP, "%s)\n", (sym->st_size>128)?" ...":""); } } else { - printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name); + 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_386_RELATIVE: - printf_log(LOG_DUMP, "Apply %s R_386_RELATIVE @%p (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, *(void**)p, (void*)((*p)+head->delta)); + case R_X86_64_RELATIVE: + printf_log(LOG_DUMP, "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_386_32: + case R_X86_64_64: if (!offs) { - printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name); + printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", symname, p, *(void**)p, head->name); // return -1; } else { - printf_log(LOG_DUMP, "Apply %s R_386_32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+*(uint32_t*)p)); + printf_log(LOG_DUMP, "Apply %s R_X86_64_64 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+*(uint32_t*)p)); *p += 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); - else { - if(!h_tls) { - if(local_maplib) - h_tls = GetGlobalSymbolElf(local_maplib, symname); - if(!h_tls) - h_tls = GetGlobalSymbolElf(maplib, symname); - } - offs = getElfIndex(my_context, h_tls); - } - if(p) { - printf_log(LOG_DUMP, "Apply %s %s @%p with sym=%s (%p -> %p)\n", "R_386_TLS_DTPMOD32", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)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, *(void**)p); - } else { - printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name); - } -// return -1; - } else { - if(h_tls) - offs = sym->st_value; - if(p) { - int tlsoffset = offs; // it's not an offset in elf memory - printf_log(LOG_DUMP, "Apply %s R_386_TLS_DTPOFF32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)tlsoffset, (void*)offs); - *p = tlsoffset; - } else { - printf_log(LOG_NONE, "Warning, Symbol %s found, but R_386_TLS_DTPOFF32 Slot Offset is NULL \n", symname); - } - } - break; - case R_386_JMP_SLOT: + 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 @@ -555,21 +491,21 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn ) { 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, *(void**)p); + 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_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, head->name); + 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_log(LOG_DUMP, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs); + printf_log(LOG_DUMP, "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_log(LOG_DUMP, "Preparing (if needed) %s R_386_JMP_SLOT @%p (0x%x->0x%0x) with sym=%s to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname); + printf_log(LOG_DUMP, "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; @@ -589,21 +525,21 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c uintptr_t offs = 0; uintptr_t end = 0; switch(ELF64_R_TYPE(rela[i].r_info)) { - case R_386_NONE: - case R_386_PC32: + case R_X86_64_NONE: + case R_X86_64_PC32: // can be ignored break; - case R_386_COPY: + case R_X86_64_COPY: if(local_maplib) GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head); if(!offs) GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); if(offs) { // add r_addend to p? - printf_log(LOG_DUMP, "Apply R_386_COPY @%p with sym=%s, @%p size=%d\n", p, symname, (void*)offs, sym->st_size); + printf_log(LOG_DUMP, "Apply R_X86_64_COPY @%p with sym=%s, @%p size=%ld\n", p, symname, (void*)offs, sym->st_size); memcpy(p, (void*)(offs+rela[i].r_addend), sym->st_size); } else { - printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply RELA R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name); + printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply RELA R_X86_64_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name); } break; default: @@ -663,7 +599,7 @@ int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, elfheader_t* head) return 0; } -#endif + void CalcStack(elfheader_t* elf, uint32_t* stacksz, int* stackalign) { if(*stacksz < elf->stacksz) @@ -708,7 +644,7 @@ uintptr_t GetFunctionAddress(elfheader_t* h, const char* name) if(sym) return sym->st_value; return 0; } -#if 0 + uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h) { uintptr_t ep = h->entrypoint + h->delta; @@ -739,12 +675,12 @@ uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h) */ return ep; } -#endif + uintptr_t GetLastByte(elfheader_t* h) { return (uintptr_t)h->memory/* + h->delta*/ + h->memsz; } -#if 0 + void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h) { printf_log(LOG_DUMP, "Will look for Symbol to add in SymTable(%d)\n", h->numSymTab); @@ -812,7 +748,7 @@ $PLATFORM – Expands to the processor type of the current machine (see the uname(1) man page description of the -i option). For more details of this token expansion, see “System Specific Shared Objects” */ -int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box64context_t *box64, x86emu_t* emu) +int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box64context_t *box64, x64emu_t* emu) { DumpDynamicRPath(h); // update RPATH first @@ -874,7 +810,7 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int } return 0; } -#endif + int ElfCheckIfUseTCMallocMinimal(elfheader_t* h) { if(!h) @@ -889,8 +825,8 @@ int ElfCheckIfUseTCMallocMinimal(elfheader_t* h) } return 0; } -#if 0 -void RunElfInit(elfheader_t* h, x86emu_t *emu) + +void RunElfInit(elfheader_t* h, x64emu_t *emu) { if(!h || h->init_done) return; @@ -924,7 +860,7 @@ void RunElfInit(elfheader_t* h, x86emu_t *emu) } EXPORTDYN -void RunDeferedElfInit(x86emu_t *emu) +void RunDeferedElfInit(x64emu_t *emu) { box64context_t* context = GetEmuContext(emu); if(!context->deferedInit) @@ -939,7 +875,7 @@ void RunDeferedElfInit(x86emu_t *emu) context->deferedInitCap = context->deferedInitSz = 0; } -void RunElfFini(elfheader_t* h, x86emu_t *emu) +void RunElfFini(elfheader_t* h, x64emu_t *emu) { if(!h || h->fini_done) return; @@ -1110,7 +1046,7 @@ typedef struct my_dl_phdr_info_s { int dlpi_phnum; } my_dl_phdr_info_t; -static int dl_iterate_phdr_callback(x86emu_t *emu, void* F, my_dl_phdr_info_t *info, size_t size, void* data) +static int dl_iterate_phdr_callback(x64emu_t *emu, void* F, my_dl_phdr_info_t *info, size_t size, void* data) { int ret = RunFunctionWithEmu(emu, 0, (uintptr_t)F, 3, info, size, data); return ret; @@ -1151,7 +1087,7 @@ static void* find_dl_iterate_phdr_Fct(void* fct) } #undef SUPER -EXPORT int my_dl_iterate_phdr(x86emu_t *emu, void* F, void *data) { +EXPORT int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data) { printf_log(LOG_INFO, "Warning: call to partially implemented dl_iterate_phdr(%p, %p)\n", F, data); box64context_t *context = GetEmuContext(emu); const char* empty = ""; @@ -1217,7 +1153,7 @@ void CreateMemorymapFile(box64context_t* context, int fd) for (int i=0; i<h->numPHEntries; ++i) { if (h->PHEntries[i].p_memsz == 0) continue; - sprintf(buff, "%08x-%08x %c%c%c%c %08x %02x:%02x %ld %s\n", (uintptr_t)h->PHEntries[i].p_vaddr + h->delta, + sprintf(buff, "%016lx-%016lx %c%c%c%c %016lx %02x:%02x %ld %s\n", (uintptr_t)h->PHEntries[i].p_vaddr + h->delta, (uintptr_t)h->PHEntries[i].p_vaddr + h->PHEntries[i].p_memsz + h->delta, (h->PHEntries[i].p_type & (PF_R|PF_X) ? 'r':'-'), (h->PHEntries[i].p_type & PF_W ? 'w':'-'), (h->PHEntries[i].p_type & PF_X ? 'x':'-'), 'p', // p for private or s for shared @@ -1236,12 +1172,12 @@ void ElfAttachLib(elfheader_t* head, library_t* lib) } uintptr_t pltResolver = ~0; -EXPORT void PltResolver(x86emu_t* emu) +EXPORT void PltResolver(x64emu_t* emu) { - uintptr_t addr = Pop32(emu); - int slot = (int)Pop32(emu); + uintptr_t addr = Pop64(emu); + int slot = (int)Pop64(emu); elfheader_t *h = (elfheader_t*)addr; - printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s\n", (void*)addr, slot, *(void**)(R_ESP), h->name); + printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s\n", (void*)addr, slot, *(void**)(R_RSP), h->name); Elf64_Rel * rel = (Elf64_Rel *)(h->jmprel + h->delta + slot); @@ -1260,12 +1196,12 @@ EXPORT void PltResolver(x86emu_t* emu) GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end); if (!offs) { - printf_log(LOG_NONE, "Error: PltReolver: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, h->name); + printf_log(LOG_NONE, "Error: PltReolver: Symbol %s not found, cannot apply R_X86_64_JUMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, h->name); emu->quit = 1; return; } else { if(p) { - printf_log(LOG_DEBUG, "PltReolver: Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs))); + printf_log(LOG_DEBUG, "PltReolver: Apply %s R_X86_64_JUMP_SLOT @%p with sym=%s (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs))); *p = offs; } else { printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname); @@ -1273,6 +1209,5 @@ EXPORT void PltResolver(x86emu_t* emu) } // jmp to function - R_EIP = offs; + R_RIP = offs; } -#endif \ No newline at end of file diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h index 8de85633..8e95175d 100755 --- a/src/elfs/elfloader_private.h +++ b/src/elfs/elfloader_private.h @@ -1,12 +1,12 @@ #ifndef __ELFLOADER_PRIVATE_H_ #define __ELFLOADER_PRIVATE_H_ -//#ifdef DYNAREC -//typedef struct dynablocklist_s dynablocklist_t; -//#endif +#ifdef DYNAREC +typedef struct dynablocklist_s dynablocklist_t; +#endif -//typedef struct library_s library_t; -//typedef struct needed_libs_s needed_libs_t; +typedef struct library_s library_t; +typedef struct needed_libs_s needed_libs_t; #include <pthread.h> @@ -82,8 +82,8 @@ struct elfheader_s { uint64_t* multiblock_size; int multiblock_n; - //library_t *lib; - //needed_libs_t *neededlibs; + library_t *lib; + needed_libs_t *neededlibs; }; #define R_X86_64_NONE 0 /* No reloc */ diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c index 3ce6b63e..ea3cc138 100755 --- a/src/emu/x64emu.c +++ b/src/emu/x64emu.c @@ -14,8 +14,8 @@ #include "box64context.h" #include "x64run.h" #include "x64run_private.h" -//#include "callback.h" -//#include "bridge.h" +#include "callback.h" +#include "bridge.h" #ifdef DYNAREC #include "custommem.h" #endif @@ -43,16 +43,16 @@ uint32_t* GetParityTab() return x86emu_parity_tab; } -//void PushExit(x64emu_t* emu) -//{ -// uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0); -// Push(emu, endMarker); -//} +void PushExit(x64emu_t* emu) +{ + uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0); + Push(emu, endMarker); +} -//void* GetExit() -//{ -// return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0); -//} +void* GetExit() +{ + return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0); +} static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack) { @@ -403,31 +403,31 @@ void UnimpOpcode(x64emu_t* emu) emu->error |= ERR_UNIMPL; } -//void EmuCall(x64emu_t* emu, uintptr_t addr) -//{ -// uint64_t old_rsp = R_RSP; -// uint64_t old_rbx = R_RBX; -// uint64_t old_rdi = R_RDI; -// uint64_t old_rsi = R_RSI; -// uint64_t old_rbp = R_RBP; -// uint64_t old_rip = R_RIP; -// PushExit(emu); -// R_RIP = addr; -// emu->df = d_none; -// Run(emu, 0); -// emu->quit = 0; // reset Quit flags... -// emu->df = d_none; -// if(emu->quitonlongjmp && emu->longjmp) { -// emu->longjmp = 0; // don't change anything because of the longjmp -// } else { -// R_RBX = old_ebx; -// R_RDI = old_edi; -// R_RSI = old_esi; -// R_RBP = old_ebp; -// R_RSP = old_esp; -// R_RIP = old_eip; // and set back instruction pointer -// } -//} +void EmuCall(x64emu_t* emu, uintptr_t addr) +{ + uint64_t old_rsp = R_RSP; + uint64_t old_rbx = R_RBX; + uint64_t old_rdi = R_RDI; + uint64_t old_rsi = R_RSI; + uint64_t old_rbp = R_RBP; + uint64_t old_rip = R_RIP; + PushExit(emu); + R_RIP = addr; + emu->df = d_none; + Run(emu, 0); + emu->quit = 0; // reset Quit flags... + emu->df = d_none; + if(emu->quitonlongjmp && emu->longjmp) { + emu->longjmp = 0; // don't change anything because of the longjmp + } else { + R_RBX = old_rbx; + R_RDI = old_rdi; + R_RSI = old_rsi; + R_RBP = old_rbp; + R_RSP = old_rsp; + R_RIP = old_rip; // and set back instruction pointer + } +} uint64_t ReadTSC(x64emu_t* emu) { diff --git a/src/emu/x64run.c b/src/emu/x64run.c new file mode 100755 index 00000000..39533d8b --- /dev/null +++ b/src/emu/x64run.c @@ -0,0 +1,118 @@ +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> + +#include "debug.h" +#include "box64stack.h" +#include "x64emu.h" +#include "x64run.h" +#include "x64emu_private.h" +#include "x64run_private.h" +//#include "x64primop.h" +#include "x64trace.h" +#include "x87emu_private.h" +#include "box64context.h" +//#include "my_cpuid.h" +#include "bridge.h" +//#include "signals.h" +#ifdef DYNAREC +#include "../dynarec/arm_lock_helper.h" +#endif + +int my_setcontext(x64emu_t* emu, void* ucp); + +int Run(x64emu_t *emu, int step) +{ + uint8_t opcode; + uint8_t nextop; + reg64_t *oped; + uint8_t tmp8u, tmp8u2; + int8_t tmp8s; + uint16_t tmp16u, tmp16u2; + int16_t tmp16s; + uint32_t tmp32u, tmp32u2, tmp32u3; + uint64_t tmp64u, tmp64u2, tmp64u3; + int32_t tmp32s, tmp32s2; + int64_t tmp64s, tmp64s2; + uintptr_t ip; + double d; + float f; + int64_t ll; + sse_regs_t *opex, eax1; + mmx_regs_t *opem, eam1; + + if(emu->quit) + return 0; + + //ref opcode: http://ref.x64asm.net/geek32.html#xA1 + printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p\n", emu, (void*)R_RIP, emu->context->stack); +#define F8 *(uint8_t*)(ip++) +#define F8S *(int8_t*)(ip++) +#define F16 *(uint16_t*)(ip+=2, ip-2) +#define F32 *(uint32_t*)(ip+=4, ip-4) +#define F32S *(int32_t*)(ip+=4, ip-4) +#define PK(a) *(uint8_t*)(ip+a) +#ifdef DYNAREC +#define STEP if(step) goto stepout; +#else +#define STEP +#endif + +x64emurun: + ip = R_RIP; + +//#include "modrm.h" + while(1) { +#ifdef HAVE_TRACE + __builtin_prefetch((void*)ip, 0, 0); + emu->prev2_ip = emu->prev_ip; + emu->prev_ip = R_RIP; + R_RIP=ip; + if(my_context->dec && ( + (trace_end == 0) + || ((ip >= trace_start) && (ip < trace_end))) ) + PrintTrace(emu, ip, 0); +#endif + + opcode = F8; + switch(opcode) { + + default: + emu->old_ip = R_RIP; + R_RIP = ip; + UnimpOpcode(emu); + goto fini; + } + } +#ifdef DYNAREC +stepout: + emu->old_ip = R_RIP; + R_RIP = ip; + return 0; +#endif + +fini: + // fork handling +// if(emu->fork) { +// if(step) +// return 0; +// int forktype = emu->fork; +// emu->quit = 0; +// emu->fork = 0; +// emu = x64emu_fork(emu, forktype); +// goto x64emurun; +// } + // setcontext handling +// else if(emu->uc_link) { +// emu->quit = 0; +// my_setcontext(emu, emu->uc_link); +// goto x64emurun; +// } + return 0; +} diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c new file mode 100755 index 00000000..5ceae0a3 --- /dev/null +++ b/src/emu/x64run_private.c @@ -0,0 +1,787 @@ +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_TRACE +#include <unistd.h> +#include <sys/syscall.h> +#endif + +#include "debug.h" +#include "box64stack.h" +#include "x64emu.h" +#include "x64run.h" +#include "x64run_private.h" +#include "x64emu_private.h" +#include "box64context.h" +#include "x64run.h" +#include "librarian.h" +#include "elfloader.h" +#ifdef HAVE_TRACE +#include "x64trace.h" +#endif +#include "x64tls.h" + +#define PARITY2(x) (((emu->x64emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) +#define PARITY(x) (PARITY2((x)>>32)^PARITY2((x)&0xffffffff)) +#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1) + +int32_t EXPORT my___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) +{ + //TODO: register rtld_fini + //TODO: register fini + // let's cheat and set all args... + Push(emu, (uint64_t)my_context->envv); + Push(emu, (uint64_t)my_context->argv); + Push(emu, (uint64_t)my_context->argc); + if(init) { + PushExit(emu); + R_RIP=(uint64_t)*init; + printf_log(LOG_DEBUG, "Calling init(%p) from __libc_start_main\n", *init); + DynaRun(emu); + if(emu->error) // any error, don't bother with more + return 0; + emu->quit = 0; + } + printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main); + // call main and finish + PushExit(emu); + R_RIP=(uint64_t)main; +#ifdef DYNAREC + DynaRun(emu); +#endif + return 0; +} + +const char* GetNativeName(void* p) +{ + static char buff[500] = {0}; + Dl_info info; + if(dladdr(p, &info)==0) { + const char *ret = GetNameOffset(my_context->maplib, p); + if(ret) + return ret; + sprintf(buff, "%s(%p)", "???", p); + return buff; + } else { + if(info.dli_sname) { + strcpy(buff, info.dli_sname); + if(info.dli_fname) { + strcat(buff, " ("); strcat(buff, info.dli_fname); strcat(buff, ")"); + } + } else { + sprintf(buff, "%s(%s/%p)", "???", info.dli_fname, p); + return buff; + } + } + return buff; +} +#if 0 +void UpdateFlags(x64emu_t *emu) +{ + uint32_t cc; + uint32_t lo, hi; + uint32_t bc; + uint32_t cnt; + + switch(emu->df) { + case d_none: + return; + case d_add8: + CONDITIONAL_SET_FLAG(emu->res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_add16: + CONDITIONAL_SET_FLAG(emu->res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_add32: + lo = (emu->op2 & 0xFFFF) + (emu->op1 & 0xFFFF); + hi = (lo >> 16) + (emu->op2 >> 16) + (emu->op1 >> 16); + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_and8: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_and16: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_and32: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_dec8: + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_dec16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_dec32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_inc8: + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = ((1 & emu->op1) | (~emu->res)) & (1 | emu->op1); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_inc16: + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (1 & emu->op1) | ((~emu->res) & (1 | emu->op1)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_inc32: + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (1 & emu->op1) | ((~emu->res) & (1 | emu->op1)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_imul8: + lo = emu->res & 0xff; + hi = (emu->res>>8)&0xff; + if (((lo & 0x80) == 0 && hi == 0x00) || + ((lo & 0x80) != 0 && hi == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_imul16: + lo = (uint16_t)emu->res; + hi = (uint16_t)(emu->res >> 16); + if (((lo & 0x8000) == 0 && hi == 0x00) || + ((lo & 0x8000) != 0 && hi == 0xFFFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_imul32: + if (((emu->res & 0x80000000) == 0 && emu->op1 == 0x00) || + ((emu->res & 0x80000000) != 0 && emu->op1 == 0xFFFFFFFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_mul8: + lo = emu->res & 0xff; + hi = (emu->res>>8)&0xff; + if (hi == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_mul16: + lo = (uint16_t)emu->res; + hi = (uint16_t)(emu->res >> 16); + if (hi == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF); + break; + case d_mul32: + if (emu->op1 == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_or8: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_or16: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_or32: + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + break; + case d_neg8: + CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = emu->res | emu->op1; + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_neg16: + CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = emu->res | emu->op1; + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_neg32: + CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = emu->res | emu->op1; + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_shl8: + if (emu->op2 < 8) { + cnt = emu->op2 % 8; + if (cnt > 0) { + cc = emu->op1 & (1 << (8 - cnt)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((emu->res & 0x80) == 0x80) ^(ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + CONDITIONAL_SET_FLAG((emu->op1 << (emu->op2-1)) & 0x80, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + break; + case d_shl16: + if (emu->op2 < 16) { + cnt = emu->op2 % 16; + if (cnt > 0) { + cc = emu->op1 & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(((!!(emu->res & 0x8000)) ^(ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + CONDITIONAL_SET_FLAG((emu->op1 << (emu->op2-1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + break; + case d_shl32: + if (emu->op2 > 0) { + cc = emu->op1 & (1 << (32 - emu->op2)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (emu->op2 == 1) { + CONDITIONAL_SET_FLAG(((!!(emu->res & 0x80000000)) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + break; + case d_sar8: + if (emu->op2 < 8) { + if(emu->op2) { + cc = emu->op1 & (1 << (emu->op2 - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + } + } else { + if (emu->op1&0x80) { + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + } + } + break; + case d_sar16: + if (emu->op2 < 16) { + if(emu->op2) { + cc = emu->op1 & (1 << (emu->op2 - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + } else { + if (emu->op1&0x8000) { + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + } + } + break; + case d_sar32: + if(emu->op2) { + cc = emu->op1 & (1 << (emu->op2 - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + break; + case d_shr8: + if (emu->op2 < 8) { + cnt = emu->op2 % 8; + if (cnt > 0) { + cc = emu->op1 & (1 << (cnt - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF); + } + } else { + CONDITIONAL_SET_FLAG((emu->op1 >> (emu->op2-1)) & 0x1, F_CF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + break; + case d_shr16: + if (emu->op2 < 16) { + cnt = emu->op2 % 16; + if (cnt > 0) { + cc = emu->op1 & (1 << (cnt - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF); + } + } else { + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + } + break; + case d_shr32: + cnt = emu->op2; + if (cnt > 0) { + cc = emu->op1 & (1 << (cnt - 1)); + CONDITIONAL_SET_FLAG(cc, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF); + } + break; + case d_sub8: + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sub16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sub32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_xor8: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + break; + case d_xor16: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + break; + case d_xor32: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + break; + case d_cmp8: + CLEAR_FLAG(F_CF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_cmp16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_cmp32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_tst8: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + break; + case d_tst16: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + break; + case d_tst32: + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + break; + case d_adc8: + CONDITIONAL_SET_FLAG(emu->res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_adc16: + CONDITIONAL_SET_FLAG(emu->res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_adc32: + if(emu->res == (emu->op1+emu->op2)) { + lo = (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF); + } else { + lo = 1 + (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF); + } + hi = (lo >> 16) + (emu->op1 >> 16) + (emu->op2 >> 16); + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + cc = (emu->op2 & emu->op1) | ((~emu->res) & (emu->op2 | emu->op1)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + break; + case d_sbb8: + CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sbb16: + CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_sbb32: + CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(!emu->res, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF); + bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + break; + case d_rol8: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 7)) & 1, F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF); + break; + case d_rol16: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 15)) & 1, F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF); + break; + case d_rol32: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 31)) & 1, F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF); + break; + case d_ror8: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & (1 << 7), F_CF); + break; + case d_ror16: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & (1 << 15), F_CF); + break; + case d_ror32: + if(emu->op2 == 1) { + CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF); + } + CONDITIONAL_SET_FLAG(emu->res & (1 << 31), F_CF); + break; + + case d_unknown: + printf_log(LOG_NONE, "Box86: %p trying to evaluate Unknown defered Flags\n", (void*)R_RIP); + break; + } + RESET_FLAGS(emu); +} +#endif + +uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg) +{ + if(emu->segs_serial[seg] != emu->context->sel_serial) { + emu->segs_offs[seg] = (uintptr_t)GetSegmentBase(emu->segs[seg]); + emu->segs_serial[seg] = emu->context->sel_serial; + } + return emu->segs_offs[seg]; +} + + +const char* getAddrFunctionName(uintptr_t addr) +{ + static char ret[1000]; + uint32_t sz = 0; + uintptr_t start = 0; + const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, addr), (void*)addr, &start, &sz); + if(symbname && addr>=start && (addr<(start+sz) || !sz)) { + if(addr==start) + sprintf(ret, "%s/%s", ElfName(FindElfAddress(my_context, addr)), symbname); + else + sprintf(ret, "%s/%s + %ld", ElfName(FindElfAddress(my_context, addr)), symbname, addr - start); + } else + sprintf(ret, "???"); + return ret; +} + +void printFunctionAddr(uintptr_t nextaddr, const char* text) +{ + uint32_t sz = 0; + uintptr_t start = 0; + const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, nextaddr), (void*)nextaddr, &start, &sz); + if(symbname && nextaddr>=start && (nextaddr<(start+sz) || !sz)) { + if(nextaddr==start) + printf_log(LOG_NONE, " (%s%s/%s)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname); + else + printf_log(LOG_NONE, " (%s%s/%s + %ld)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname, nextaddr - start); + } +} + +#ifdef HAVE_TRACE +extern uint64_t start_cnt; +#define PK(a) (*(uint8_t*)(ip+a)) +#define PK32(a) (*(int32_t*)((uint8_t*)(ip+a))) +#define PK64(a) (*(int64_t*)((uint8_t*)(ip+a))) + +void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec) +{ + if(start_cnt) --start_cnt; + if(!start_cnt && my_context->dec && ( + (trace_end == 0) + || ((ip >= trace_start) && (ip < trace_end))) ) { + int tid = syscall(SYS_gettid); + pthread_mutex_lock(&my_context->mutex_trace); +#ifdef DYNAREC + if((my_context->trace_tid != tid) || (my_context->trace_dynarec!=dynarec)) { + printf_log(LOG_NONE, "Thread %04d| (%s) |\n", tid, dynarec?"dyn":"int"); + my_context->trace_tid = tid; + my_context->trace_dynarec = dynarec; + } +#else + if(my_context->trace_tid != tid) { + printf_log(LOG_NONE, "Thread %04d|\n", tid); + my_context->trace_tid = tid; + } +#endif + printf_log(LOG_NONE, "%s", DumpCPURegs(emu, ip)); + if(PK(0)==0xcc && PK(1)=='S' && PK(2)=='C') { + uint64_t a = *(uint64_t*)(ip+3); + if(a==0) { + printf_log(LOG_NONE, "%p: Exit x86emu\n", (void*)ip); + } else { + printf_log(LOG_NONE, "%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(*(void**)(ip+7))); + } + } else { + printf_log(LOG_NONE, "%s", DecodeX64Trace(my_context->dec, ip)); + uint8_t peek = PK(0); + if(peek==0xC3 || peek==0xC2) { + printf_log(LOG_NONE, " => %p", *(void**)(R_RSP)); + printFunctionAddr(*(uintptr_t*)(R_RSP), "=> "); + } else if(peek==0x55) { + printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_RSP)); + printFunctionAddr(ip, "here: "); + } else if(peek==0xE8) { // Call + uintptr_t nextaddr = ip + 5 + PK64(1); + printFunctionAddr(nextaddr, "=> "); + } else if(peek==0xFF) { + if(PK(1)==0x25) { + uintptr_t nextaddr = ip + 6 + PK64(2); + printFunctionAddr(nextaddr, "=> "); + } + } + printf_log(LOG_NONE, "\n"); + } + pthread_mutex_unlock(&my_context->mutex_trace); + } +} + +#endif diff --git a/src/emu/x64syscall.c b/src/emu/x64syscall.c new file mode 100755 index 00000000..5359939c --- /dev/null +++ b/src/emu/x64syscall.c @@ -0,0 +1,186 @@ +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/syscall.h> /* For SYS_xxx definitions */ +#include <unistd.h> +#include <time.h> +#include <sys/mman.h> +#include <sys/select.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <asm/stat.h> +#include <errno.h> +#include <sched.h> +#include <sys/wait.h> +#include <sys/utsname.h> +#include <sys/resource.h> +#include <poll.h> + +#include "debug.h" +#include "box64stack.h" +#include "x64emu.h" +#include "x64run.h" +#include "x64emu_private.h" +#include "x64run_private.h" +//#include "x64primop.h" +#include "x64trace.h" +//#include "myalign.h" +#include "box64context.h" +//#include "callback.h" +//#include "signals.h" +//#include "x64tls.h" + +typedef struct x64_sigaction_s x64_sigaction_t; + + +//int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags); +//int of_convert(int flag); +//int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode); + +//int my_sigaction(x64emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact); +//int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]); +//void* my_mmap(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset); +//void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset); +//int my_munmap(x64emu_t* emu, void* addr, unsigned long length); +//int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot); + +// cannot include <fcntl.h>, it conflict with some asm includes... +#ifndef O_NONBLOCK +#define O_NONBLOCK 04000 +#endif +#undef fcntl +int fcntl(int fd, int cmd, ... /* arg */ ); + +// Syscall table for x86_64 can be found +typedef struct scwrap_s { + int x64s; + int nats; + int nbpars; +} scwrap_t; + +scwrap_t syscallwrap[] = { + { 0, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc + { 1, __NR_write, 3 }, // same + { 2, __NR_open, 3 }, // flags need transformation + { 3, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc + { 4, __NR_stat, 2 }, + { 5, __NR_fstat, 2}, +}; + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +//struct x86_pt_regs { +// long ebx; +// long ecx; +// long edx; +// long esi; +// long edi; +// long ebp; +// long eax; +// int xds; +// int xes; +// int xfs; +// int xgs; +// long orig_eax; +// long eip; +// int xcs; +// long eflags; +// long esp; +// int xss; +//}; + +//int clone_fn(void* arg) +//{ +// x64emu_t *emu = (x64emu_t*)arg; +// R_RAX = 0; +// DynaRun(emu); +// int ret = R_EAX; +// FreeX64Emu(&emu); +// return ret; +//} + +void EXPORT x64Syscall(x64emu_t *emu) +{ + RESET_FLAGS(emu); + uint32_t s = R_EAX; + printf_log(LOG_DEBUG, "%p: Calling syscall 0x%02X (%d) %p %p %p %p %p %p", (void*)R_RIP, s, s, (void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_R10, (void*)R_R8, (void*)R_R9); + // check wrapper first + int cnt = sizeof(syscallwrap) / sizeof(scwrap_t); + for (int i=0; i<cnt; i++) { + if(syscallwrap[i].x64s == s) { + int sc = syscallwrap[i].nats; + switch(syscallwrap[i].nbpars) { + case 0: *(int64_t*)&R_RAX = syscall(sc); break; + case 1: *(int64_t*)&R_RAX = syscall(sc, R_RDI); break; + case 2: if(s==33) {printf_log(LOG_DUMP, " => sys_access(\"%s\", %ld)\n", (char*)R_RDI, R_RSI);}; *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI); break; + case 3: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX); break; + case 4: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10); break; + case 5: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10, R_R8); break; + case 6: *(int64_t*)&R_RAX = syscall(sc, R_RDI, R_RSI, R_RDX, R_R10, R_R8, R_R9); break; + default: + printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); + emu->quit = 1; + return; + } + printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX); + return; + } + } + switch (s) { + default: + printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s); + emu->quit = 1; + emu->error |= ERR_UNIMPL; + return; + } + printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX); +} + +#define stack(n) (R_RSP+8+n) +#define i32(n) *(int32_t*)stack(n) +#define u32(n) *(uint32_t*)stack(n) +#define u64(n) *(uint64_t*)stack(n) +#define p(n) *(void**)stack(n) + +uint32_t EXPORT my_syscall(x64emu_t *emu) +{ + uint32_t s = R_EDI;; + printf_log(LOG_DUMP, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_RIP, s, s, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9); + // check wrapper first + int cnt = sizeof(syscallwrap) / sizeof(scwrap_t); + for (int i=0; i<cnt; i++) { + if(syscallwrap[i].x64s == s) { + int sc = syscallwrap[i].nats; + switch(syscallwrap[i].nbpars) { + case 0: return syscall(sc); + case 1: return syscall(sc, R_RSI); + case 2: return syscall(sc, R_RSI, R_RDX); + case 3: return syscall(sc, R_RSI, R_RDX, R_RCX); + case 4: return syscall(sc, R_RSI, R_RDX, R_RCX, R_R8); + case 5: return syscall(sc, R_RSI, R_RDX, R_RCX, R_R8, R_R9); + case 6: return syscall(sc, R_RSI, R_RDX, R_RCX, R_R8, R_R9, u64(0)); + default: + printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); + emu->quit = 1; + return 0; + } + } + } + switch (s) { + default: + printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s); + emu->quit = 1; + emu->error |= ERR_UNIMPL; + } + return 0; +} diff --git a/src/emu/x64tls.c b/src/emu/x64tls.c new file mode 100755 index 00000000..b76646b5 --- /dev/null +++ b/src/emu/x64tls.c @@ -0,0 +1,213 @@ +// Handling of TLS calls, include x86 specifi set_thread_area +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "debug.h" +#include "box64context.h" +#include "x64emu.h" +#include "x64tls.h" +#include "elfloader.h" + +typedef struct thread_area_s +{ + int entry_number; + uintptr_t base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; +} thread_area_t; + +static pthread_once_t thread_key_once0 = PTHREAD_ONCE_INIT; +static pthread_once_t thread_key_once1 = PTHREAD_ONCE_INIT; +static pthread_once_t thread_key_once2 = PTHREAD_ONCE_INIT; + +static void thread_key_alloc0() { + pthread_key_create(&my_context->segtls[0].key, NULL); +} +static void thread_key_alloc1() { + pthread_key_create(&my_context->segtls[1].key, NULL); +} +static void thread_key_alloc2() { + pthread_key_create(&my_context->segtls[2].key, NULL); +} + +uint32_t my_set_thread_area(thread_area_t* td) +{ + printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only); + + int isempty = 0; + // first, check if the "user_desc", here td, is "empty" + if(td->read_exec_only==1 && td->seg_not_present==1) + if( !td->base_addr + && !td->limit + && !td->seg_32bit + && !td->contents + && !td->limit_in_pages + && !td->useable) + isempty = 1; + int idx = td->entry_number; + if(idx==-1) { + // find a free one + for (int i=0; i<3 && idx==-1; ++i) + if(!my_context->segtls[i].present) + idx=i; + if(idx==-1) { + errno = ESRCH; + return (uint32_t)-1; + } + idx+=7; + td->entry_number = idx; + } + if(isempty && (td->entry_number<7 || td->entry_number>7+2)) { + errno = EINVAL; + return (uint32_t)-1; + } + if(isempty) { + memset(&my_context->segtls[td->entry_number-7], 0, sizeof(base_segment_t)); + return 0; + } + if((idx<7 || idx>7+2)) { + errno = EINVAL; + return (uint32_t)-1; + } + + my_context->segtls[idx-7].base = td->base_addr; + my_context->segtls[idx-7].limit = td->limit; + my_context->segtls[idx-7].present = 1; + switch (idx-7) { + case 0: pthread_once(&thread_key_once0, thread_key_alloc0); break; + case 1: pthread_once(&thread_key_once1, thread_key_alloc1); break; + case 2: pthread_once(&thread_key_once2, thread_key_alloc2); break; + } + + pthread_setspecific(my_context->segtls[idx-7].key, (void*)my_context->segtls[idx-7].base); + + ResetSegmentsCache(thread_get_emu()); + + return 0; +} + +uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size) +{ + printf_log(/*LOG_DEBUG*/LOG_INFO, "modify_ldt(0x%x, %p[0x%x/base=%p/limit=%u/32bits:%u/%u/%u...], %d)\n", op, td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only, size); + if(!td) { + errno = EFAULT; + return (uint32_t)-1; + } + if(op!=0x11) { + errno = ENOSYS; + return (uint32_t)-1; + } + if(!td->seg_32bit) { + // not handling 16bits segments for now + errno = EINVAL; + return (uint32_t)-1; + } + + int idx = td->entry_number - 7; + if(idx<0 || idx>2) { + errno = EINVAL; + return (uint32_t)-1; + } + + /* + my_context->segtls[idx].base = td->base_addr; + my_context->segtls[idx].limit = td->limit; + pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base); + */ + + ResetSegmentsCache(thread_get_emu()); + + return 0; +} + +#define POS_TLS 0x50 + +static tlsdatasize_t* setupTLSData(box64context_t* context) +{ + // Setup the GS segment: + int dtsize = context->elfsize*8; + void *ptr = (char*)malloc(context->tlssize+4+POS_TLS+dtsize); + memcpy(ptr, context->tlsdata, context->tlssize); + tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t)); + data->tlsdata = ptr; + data->tlssize = context->tlssize; + pthread_setspecific(context->tlskey, data); + // copy canary... + memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes + memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place + uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize; + memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, 4); + uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS; + memcpy((void*)(tlsptr+0x4), &dtp, 4); + if(dtsize) { + for (int i=0; i<context->elfsize; ++i) { + // set pointer + dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i])); + memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8), &dtp, 4); + memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8+4), &i, 4); // index + } + } + memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall + return data; +} + +void* fillTLSData(box64context_t *context) +{ + pthread_mutex_lock(&context->mutex_tls); + tlsdatasize_t *data = setupTLSData(context); + pthread_mutex_unlock(&context->mutex_tls); + return data; +} + +void* resizeTLSData(box64context_t *context, void* oldptr) +{ + pthread_mutex_lock(&context->mutex_tls); + tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr; + tlsdatasize_t *data = setupTLSData(context); + // copy the relevent old part, in case something changed + memcpy((void*)((uintptr_t)data->tlsdata+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize); + // all done, update new size, free old pointer and exit + pthread_mutex_unlock(&context->mutex_tls); + free_tlsdatasize(oldptr); + return data; +} + +static void* GetSeg33Base() +{ + tlsdatasize_t* ptr; + if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) == NULL) { + ptr = (tlsdatasize_t*)fillTLSData(my_context); + } + if(ptr->tlssize != my_context->tlssize) + ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr); + return ptr->tlsdata+ptr->tlssize; +} + +void* GetSegmentBase(uint32_t desc) +{ + if(!desc) { + printf_log(LOG_NONE, "Warning, accessing segment NULL\n"); + return NULL; + } + int base = desc>>3; + if(base==0xe || base==0xf) + return NULL; // regular value... + if(base==0x6) + return GetSeg33Base(); + + if(base>6 && base<10 && my_context->segtls[base-7].present) { + void* ptr = pthread_getspecific(my_context->segtls[base-7].key); + return ptr; + } + + printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc); + return NULL; +} diff --git a/src/include/box64context.h b/src/include/box64context.h index 9eca567e..c9c25bf3 100755 --- a/src/include/box64context.h +++ b/src/include/box64context.h @@ -11,7 +11,22 @@ typedef struct zydis_s zydis_t; typedef struct zydis_dec_s zydis_dec_t; typedef struct lib_s lib_t; typedef struct bridge_s bridge_t; +typedef struct dlprivate_s dlprivate_t; +typedef struct kh_symbolmap_s kh_symbolmap_t; +typedef struct library_s library_t; typedef struct kh_threadstack_s kh_threadstack_t; +typedef struct atfork_fnc_s { + uintptr_t prepare; + uintptr_t parent; + uintptr_t child; + void* handle; +} atfork_fnc_t; +#ifdef DYNAREC +typedef struct dynablock_s dynablock_t; +typedef struct dynablocklist_s dynablocklist_t; +typedef struct mmaplist_s mmaplist_t; +typedef struct kh_dynablocks_s kh_dynablocks_t; +#endif typedef void* (*procaddess_t)(const char* name); typedef void* (*vkprocaddess_t)(void* instance, const char* name); @@ -25,6 +40,22 @@ typedef struct tlsdatasize_s { void free_tlsdatasize(void* p); +typedef struct needed_libs_s { + int cap; + int size; + library_t **libs; +} needed_libs_t; + +void add_neededlib(needed_libs_t* needed, library_t* lib); +void free_neededlib(needed_libs_t* needed); + +typedef struct base_segment_s { + uintptr_t base; + uint64_t limit; + int present; + pthread_key_t key; +} base_segment_t; + typedef struct box64context_s { path_collection_t box64_path; // PATH env. variable path_collection_t box64_ld_lib; // LD_LIBRARY_PATH env. variable @@ -56,7 +87,8 @@ typedef struct box64context_s { int elfcap; int elfsize; // number of elf loaded - int deferedInit; + + needed_libs_t neededlibs; // needed libs for main elf uintptr_t ep; // entry point @@ -66,12 +98,62 @@ typedef struct box64context_s { kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary) bridge_t *system; // other bridges uintptr_t vsyscall; // vsyscall bridge value - + dlprivate_t *dlprivate; // dlopen library map + kh_symbolmap_t *glwrappers; // the map of wrapper for glProcs (for GLX or SDL1/2) + kh_symbolmap_t *glmymap; // link to the mysymbolmap of libGL + procaddess_t glxprocaddress; + kh_symbolmap_t *alwrappers; // the map of wrapper for alGetProcAddress + kh_symbolmap_t *almymap; // link to the mysymbolmap if libOpenAL + kh_symbolmap_t *vkwrappers; // the map of wrapper for VulkanProcs (TODO: check SDL2) + kh_symbolmap_t *vkmymap; // link to the mysymbolmap of libGL + vkprocaddess_t vkprocaddress; + + pthread_mutex_t mutex_once; + pthread_mutex_t mutex_once2; + pthread_mutex_t mutex_trace; + #ifndef DYNAREC + pthread_mutex_t mutex_lock; // dynarec build will use their own mecanism + #else + pthread_mutex_t mutex_dyndump; + int trace_dynarec; + #endif + pthread_mutex_t mutex_tls; pthread_mutex_t mutex_thread; + library_t *libclib; // shortcut to libc library (if loaded, so probably yes) + library_t *sdl1lib; // shortcut to SDL1 library (if loaded) + void* sdl1allocrw; + void* sdl1freerw; + library_t *sdl1mixerlib; + library_t *sdl2lib; // shortcut to SDL2 library (if loaded) + void* sdl2allocrw; + void* sdl2freerw; + library_t *sdl2mixerlib; + library_t *x11lib; + library_t *libxcb; + library_t *libxcbxfixes; + library_t *libxcbshape; + library_t *libxcbshm; + library_t *libxcbrandr; + library_t *libxcbimage; + library_t *libxcbkeysyms; + library_t *libxcbxtest; + library_t *zlib; + library_t *vorbisfile; + library_t *vorbis; + library_t *asound; + library_t *pulse; + library_t *d3dadapter9; + + int deferedInit; + elfheader_t **deferedInitList; + int deferedInitSz; + int deferedInitCap; + pthread_key_t tlskey; // then tls key to have actual tlsdata void* tlsdata; // the initial global tlsdata int32_t tlssize; // wanted size of tlsdata + base_segment_t segtls[3]; // only handling 0/1/2 descriptors uintptr_t *auxval_start; @@ -81,6 +163,12 @@ typedef struct box64context_s { zydis_dec_t *dec; // trace + int forked; // how many forks... cleanup only when < 0 + + atfork_fnc_t *atforks; // fnc for atfork... + int atfork_sz; + int atfork_cap; + uint8_t canary[4]; uintptr_t signals[MAX_SIGNAL]; diff --git a/src/include/callback.h b/src/include/callback.h new file mode 100755 index 00000000..b9482fc1 --- /dev/null +++ b/src/include/callback.h @@ -0,0 +1,12 @@ +#ifndef __CALLBACK_H__ +#define __CALLBACK_H__ + +#include <stdint.h> + +typedef struct x64emu_s x64emu_t; + +uint64_t RunFunction(box64context_t *context, uintptr_t fnc, int nargs, ...); +// use emu state to run function +uint64_t RunFunctionWithEmu(x64emu_t *emu, int QuitOnLongJump, uintptr_t fnc, int nargs, ...); + +#endif //__CALLBACK_H__ \ No newline at end of file diff --git a/src/include/dynarec.h b/src/include/dynarec.h new file mode 100755 index 00000000..a68c6d6a --- /dev/null +++ b/src/include/dynarec.h @@ -0,0 +1,8 @@ +#ifndef __DYNAREC_H_ +#define __DYNAREC_H_ + +typedef struct x64emu_s x64emu_t; + +void DynaCall(x64emu_t* emu, uintptr_t addr); // try to use DynaRec... Fallback to EmuCall if no dynarec available + +#endif // __DYNAREC_H_ \ No newline at end of file diff --git a/src/include/elfloader.h b/src/include/elfloader.h index 28ce4844..a4d2cb6b 100755 --- a/src/include/elfloader.h +++ b/src/include/elfloader.h @@ -3,20 +3,20 @@ #include <stdio.h> typedef struct elfheader_s elfheader_t; -//typedef struct lib_s lib_t; -//typedef struct library_s library_t; -//typedef struct kh_mapsymbols_s kh_mapsymbols_t; +typedef struct lib_s lib_t; +typedef struct library_s library_t; +typedef struct kh_mapsymbols_s kh_mapsymbols_t; typedef struct box64context_s box64context_t; -//typedef struct x86emu_s x86emu_t; -//typedef struct needed_libs_s needed_libs_t; -//#ifdef DYNAREC -//typedef struct dynablocklist_s dynablocklist_t; -//#endif +typedef struct x64emu_s x64emu_t; +typedef struct needed_libs_s needed_libs_t; +#ifdef DYNAREC +typedef struct dynablocklist_s dynablocklist_t; +#endif elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec void FreeElfHeader(elfheader_t** head); const char* ElfName(elfheader_t* head); -//void ElfAttachLib(elfheader_t* head, library_t* lib); +void ElfAttachLib(elfheader_t* head, library_t* lib); // return 0 if OK int CalcLoadAddr(elfheader_t* head); @@ -24,34 +24,34 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin); void FreeElfMemory(elfheader_t* head); int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head); int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head); -//int RelocateElf(lib_t *maplib, lib_t* local_maplib, elfheader_t* head); -//int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, elfheader_t* head); +int RelocateElf(lib_t *maplib, lib_t* local_maplib, elfheader_t* head); +int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, elfheader_t* head); void CalcStack(elfheader_t* h, uint32_t* stacksz, int* stackalign); -//uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h); +uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h); uintptr_t GetLastByte(elfheader_t* h); -//void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h); -//int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box64context_t *box86, x86emu_t* emu); -//uintptr_t GetElfInit(elfheader_t* h); -//uintptr_t GetElfFini(elfheader_t* h); -//void RunElfInit(elfheader_t* h, x86emu_t *emu); -//void RunElfFini(elfheader_t* h, x86emu_t *emu); -//void RunDeferedElfInit(x86emu_t *emu); -//void* GetBaseAddress(elfheader_t* h); -//void* GetElfDelta(elfheader_t* h); -//uint32_t GetBaseSize(elfheader_t* h); -//int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr); -//elfheader_t* FindElfAddress(box64context_t *context, uintptr_t addr); -//const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uint32_t* sz); -//int32_t GetTLSBase(elfheader_t* h); -//uint32_t GetTLSSize(elfheader_t* h); -//void* GetTLSPointer(box64context_t* context, elfheader_t* h); -//void* GetDTatOffset(box64context_t* context, int index, int offset); -//#ifdef DYNAREC -//dynablocklist_t* GetDynablocksFromAddress(box64context_t *context, uintptr_t addr); -//dynablocklist_t* GetDynablocksFromElf(elfheader_t* h); -//#endif -//void ResetSpecialCaseMainElf(elfheader_t* h); -//void CreateMemorymapFile(box64context_t* context, int fd); +void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h); +int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box64context_t *box86, x64emu_t* emu); +uintptr_t GetElfInit(elfheader_t* h); +uintptr_t GetElfFini(elfheader_t* h); +void RunElfInit(elfheader_t* h, x64emu_t *emu); +void RunElfFini(elfheader_t* h, x64emu_t *emu); +void RunDeferedElfInit(x64emu_t *emu); +void* GetBaseAddress(elfheader_t* h); +void* GetElfDelta(elfheader_t* h); +uint32_t GetBaseSize(elfheader_t* h); +int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr); +elfheader_t* FindElfAddress(box64context_t *context, uintptr_t addr); +const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uint32_t* sz); +int32_t GetTLSBase(elfheader_t* h); +uint32_t GetTLSSize(elfheader_t* h); +void* GetTLSPointer(box64context_t* context, elfheader_t* h); +void* GetDTatOffset(box64context_t* context, int index, int offset); +#ifdef DYNAREC +dynablocklist_t* GetDynablocksFromAddress(box64context_t *context, uintptr_t addr); +dynablocklist_t* GetDynablocksFromElf(elfheader_t* h); +#endif +void ResetSpecialCaseMainElf(elfheader_t* h); +void CreateMemorymapFile(box64context_t* context, int fd); int ElfCheckIfUseTCMallocMinimal(elfheader_t* h); // return 1 if tcmalloc is used diff --git a/src/include/librarian.h b/src/include/librarian.h new file mode 100755 index 00000000..a25fcd7b --- /dev/null +++ b/src/include/librarian.h @@ -0,0 +1,51 @@ +#ifndef __LIBRARIAN_H_ +#define __LIBRARIAN_H_ +#include <stdint.h> + +typedef struct lib_s lib_t; +typedef struct bridge_s bridge_t; +typedef struct library_s library_t; +typedef struct kh_mapsymbols_s kh_mapsymbols_t; +typedef struct dlprivate_s dlprivate_t; +typedef struct box64context_s box64context_t; +typedef struct x64emu_s x64emu_t; +typedef struct elfheader_s elfheader_t; +typedef struct needed_libs_s needed_libs_t; +typedef struct kh_mapoffsets_s kh_mapoffsets_t; +typedef char* cstr_t; + +lib_t *NewLibrarian(box64context_t* context, int ownlibs); +void FreeLibrarian(lib_t **maplib); +dlprivate_t *NewDLPrivate(); +void FreeDLPrivate(dlprivate_t **lib); + +box64context_t* GetLibrarianContext(lib_t* maplib); +kh_mapsymbols_t* GetMapSymbol(lib_t* maplib); +kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib); +kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib); +kh_mapsymbols_t* GetGlobalData(lib_t* maplib); +int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, int local, const char* path, box64context_t* box86, x64emu_t* emu); // 0=success, 1=error +library_t* GetLibMapLib(lib_t* maplib, const char* name); +library_t* GetLibInternal(const char* name); +uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name); +int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self); +int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self); +int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end); +int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end); +int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self); +int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self); +elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name); +int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name); + +void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz); // replace if already there +uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name); +void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz); // don't add if already there +int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end); +const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* offs, uint32_t* sz); + +const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, const char** libname, void** base); + +void AddOffsetSymbol(lib_t *maplib, void* offs, const char* name); +const char* GetNameOffset(lib_t *maplib, void* offs); + +#endif //__LIBRARIAN_H_ \ No newline at end of file diff --git a/src/include/library.h b/src/include/library.h new file mode 100755 index 00000000..d33b1126 --- /dev/null +++ b/src/include/library.h @@ -0,0 +1,36 @@ +#ifndef __LIBRARY_H_ +#define __LIBRARY_H_ +#include <stdint.h> + +typedef struct library_s library_t; +typedef struct lib_s lib_t; +typedef struct kh_symbolmap_s kh_symbolmap_t; +typedef struct box64context_s box64context_t; +typedef struct x64emu_s x64emu_t; +typedef struct needed_libs_s needed_libs_t; + +library_t *NewLibrary(const char* path, box64context_t* box86); +int AddSymbolsLibrary(lib_t* maplib, library_t* lib, x64emu_t* emu); +int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x64emu_t* emu); +int ReloadLibrary(library_t* lib, x64emu_t* emu); +void InactiveLibrary(library_t* lib); +void Free1Library(library_t **lib); + +char* GetNameLib(library_t *lib); +int IsSameLib(library_t* lib, const char* path); // check if lib is same (path -> name) +int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end); +int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end); +int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end); +void fillGLProcWrapper(box64context_t* context); +void freeGLProcWrapper(box64context_t* context); +void fillALProcWrapper(box64context_t* context); +void freeALProcWrapper(box64context_t* context); +needed_libs_t* GetNeededLibs(library_t* lib); +int GetNeededLibN(library_t* lib); +library_t* GetNeededLib(library_t* lib, int idx); +lib_t* GetMaplib(library_t* lib); + +int GetElfIndex(library_t* lib); // -1 if no elf (i.e. native) +void* GetHandle(library_t* lib); // NULL if not native + +#endif //__LIBRARY_H_ \ No newline at end of file diff --git a/src/include/wrappedlibs.h b/src/include/wrappedlibs.h new file mode 100755 index 00000000..d8cf3a64 --- /dev/null +++ b/src/include/wrappedlibs.h @@ -0,0 +1,21 @@ +#ifndef __WRAPPEDLIBS_H__ +#define __WRAPPEDLIBS_H__ +#include <stdint.h> + +typedef struct library_s library_t; +typedef struct box64context_s box64context_t; + +typedef int (*wrappedlib_init_t)(library_t * lib, box64context_t* box64); // 0 = success +typedef void (*wrappedlib_fini_t)(library_t * lib); +typedef int (*wrappedlib_get_t)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz); + +typedef struct wrappedlib_s { + const char* name; + wrappedlib_init_t init; + wrappedlib_fini_t fini; + wrappedlib_get_t get; + wrappedlib_get_t getnoweak; + wrappedlib_get_t getlocal; +} wrappedlib_t; + +#endif //__WRAPPEDLIBS_H__ \ No newline at end of file diff --git a/src/include/x64emu.h b/src/include/x64emu.h index ff19339b..f0ad24dd 100755 --- a/src/include/x64emu.h +++ b/src/include/x64emu.h @@ -42,8 +42,8 @@ void ResetSegmentsCache(x64emu_t *emu); const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip); void StopEmu(x64emu_t* emu, const char* reason); -//void PushExit(x64emu_t* emu); -//void* GetExit(); +void PushExit(x64emu_t* emu); +void* GetExit(); void EmuCall(x64emu_t* emu, uintptr_t addr); void AddCleanup(x64emu_t *emu, void *p); void AddCleanup1Arg(x64emu_t *emu, void *p, void* a); diff --git a/src/include/x64run.h b/src/include/x64run.h index 6b7333f7..78903bbc 100755 --- a/src/include/x64run.h +++ b/src/include/x64run.h @@ -3,12 +3,12 @@ #include <stdint.h> typedef struct x64emu_s x64emu_t; -//int Run(x64emu_t *emu, int step); // 0 if run was successfull, 1 if error in x86 world -//int DynaRun(x64emu_t *emu); +int Run(x64emu_t *emu, int step); // 0 if run was successfull, 1 if error in x86 world +int DynaRun(x64emu_t *emu); -//uint32_t LibSyscall(x64emu_t *emu); -//void PltResolver(x64emu_t* emu); -//extern uintptr_t pltResolver; +uint32_t LibSyscall(x64emu_t *emu); +void PltResolver(x64emu_t* emu); +extern uintptr_t pltResolver; int GetTID(); #endif //__X64RUN_H_ \ No newline at end of file diff --git a/src/include/x64tls.h b/src/include/x64tls.h new file mode 100755 index 00000000..61f58887 --- /dev/null +++ b/src/include/x64tls.h @@ -0,0 +1,13 @@ +#ifndef __X64_TLS_H__ +#define __X64_TLS_H__ + +typedef struct thread_area_s thread_area_t; + +uint32_t my_set_thread_area(thread_area_t* td); +uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size); + +void* fillTLSData(box64context_t *context); +void* resizeTLSData(box64context_t *context, void* oldptr); +void* GetSegmentBase(uint32_t desc); + +#endif //__X64_TLS_H__ \ No newline at end of file diff --git a/src/librarian/librarian.c b/src/librarian/librarian.c new file mode 100755 index 00000000..5f429c88 --- /dev/null +++ b/src/librarian/librarian.c @@ -0,0 +1,588 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <pthread.h> + +#include "debug.h" +#include "librarian.h" +#include "librarian_private.h" +#include "library.h" +#include "library_private.h" +#include "x64emu.h" +#include "box64context.h" +#include "elfloader.h" + +#include "bridge.h" + +KHASH_MAP_IMPL_STR(mapsymbols, onesymbol_t); +KHASH_MAP_IMPL_INT(mapoffsets, cstr_t); + +lib_t *NewLibrarian(box64context_t* context, int ownlibs) +{ + lib_t *maplib = (lib_t*)calloc(1, sizeof(lib_t)); + + maplib->mapsymbols = kh_init(mapsymbols); + maplib->weaksymbols = kh_init(mapsymbols); + maplib->localsymbols = kh_init(mapsymbols); + maplib->mapoffsets = kh_init(mapoffsets); + maplib->globaldata = kh_init(mapsymbols); + maplib->bridge = NewBridge(); + + maplib->context = context; + + maplib->ownlibs = ownlibs; + + return maplib; +} +void FreeLibrarian(lib_t **maplib) +{ + // should that be in reverse order? + if(!maplib || !*maplib) + return; + + if((*maplib)->ownlibs) { + printf_log(LOG_DEBUG, "Closing %d libs from maplib %p\n", (*maplib)->libsz, *maplib); + for (int i=0; i<(*maplib)->libsz; ++i) { + printf_log(LOG_DEBUG, "Unloading %s\n", (*maplib)->libraries[i].lib->name); + Free1Library(&(*maplib)->libraries[i].lib); + } + } + free((*maplib)->libraries); + (*maplib)->libraries = NULL; + + if((*maplib)->mapsymbols) { + kh_destroy(mapsymbols, (*maplib)->mapsymbols); + } + if((*maplib)->weaksymbols) { + kh_destroy(mapsymbols, (*maplib)->weaksymbols); + } + if((*maplib)->localsymbols) { + kh_destroy(mapsymbols, (*maplib)->localsymbols); + } + if((*maplib)->mapoffsets) { + kh_destroy(mapoffsets, (*maplib)->mapoffsets); + } + if((*maplib)->globaldata) { + kh_destroy(mapsymbols, (*maplib)->globaldata); + } + (*maplib)->libsz = (*maplib)->libcap = 0; + + if((*maplib)->bridge) + FreeBridge(&(*maplib)->bridge); + + free(*maplib); + *maplib = NULL; + +} + +box64context_t* GetLibrarianContext(lib_t* maplib) +{ + return maplib->context; +} + +kh_mapsymbols_t* GetMapSymbol(lib_t* maplib) +{ + return maplib->mapsymbols; +} + +kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib) +{ + return maplib->weaksymbols; +} + +kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib) +{ + return maplib->localsymbols; +} + +kh_mapsymbols_t* GetGlobalData(lib_t* maplib) +{ + return maplib->globaldata; +} + +library_t* getLib(lib_t* maplib, const char* path) +{ + for(int i=0; i<maplib->libsz; ++i) { + onelib_t *onelib = &maplib->libraries[i]; + if(IsSameLib(onelib->lib, path)) { + return onelib->lib; + } + } + return NULL; +} + +static int libraryInMapLib(lib_t* maplib, library_t* lib) +{ + if(!maplib) + return 0; + for(int i=0; i<maplib->libsz; ++i) + if(maplib->libraries[i].lib==lib) + return 1; + return 0; +} + +void MapLibAddLib(lib_t* maplib, library_t* lib) +{ + if (maplib->libsz == maplib->libcap) { + maplib->libcap += 8; + maplib->libraries = (onelib_t*)realloc(maplib->libraries, maplib->libcap*sizeof(onelib_t)); + } + maplib->libraries[maplib->libsz].lib = lib; + maplib->libraries[maplib->libsz].name = GetNameLib(lib); + ++maplib->libsz; +} + +void MapLibAddMapLib(lib_t* dest, lib_t* src) +{ + if(!src) + return; + for(int i=0; i<src->libsz; ++i) { + library_t* lib = src->libraries[i].lib; + if(!lib) continue; + if(lib->maplib && src!=lib->maplib) { //TODO: find why is src!=lib->maplib needed + MapLibAddMapLib(dest, lib->maplib); + free(lib->maplib); + lib->maplib = NULL; + } + if(!libraryInMapLib(dest, lib)) + MapLibAddLib(dest, lib); + } +} + +void MapLibRemoveLib(lib_t* maplib, library_t* lib) +{ + if(!maplib || !lib) + return; + int idx = 0; + while(idx<maplib->libsz && maplib->libraries[idx].lib!=lib) ++idx; + if(idx==maplib->libsz) //not found + return; + --maplib->libsz; + if(idx!=(maplib->libsz)) + memmove(&maplib->libraries[idx], &maplib->libraries[idx+1], sizeof(onelib_t)*(maplib->libsz-idx)); + maplib->libraries[maplib->libsz].lib = NULL; + maplib->libraries[maplib->libsz].name = NULL; +} + +EXPORTDYN +int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, int local, const char* path, box64context_t* box64, x64emu_t* emu) +{ + printf_log(LOG_DEBUG, "Trying to add \"%s\" to maplib%s\n", path, local?" (local)":""); + // first check if lib is already loaded + library_t *lib = getLib(my_context->maplib, path); + if(lib) { + add_neededlib(neededlibs, lib); + printf_log(LOG_DEBUG, "Already present in maplib => success\n"); + return 0; + } + // check also in the local loaded lib + lib = getLib(my_context->local_maplib, path); + if(lib) { + printf_log(LOG_DEBUG, "Already present in local_maplib => success\n"); + if(local) { + // add lib to maplib... + if(maplib) { + if(lib->maplib) { + MapLibAddMapLib(maplib, lib->maplib); + } + if(!libraryInMapLib(maplib, lib)) + MapLibAddLib(maplib, lib); + } + } else { + // promote lib from local to global... + // for add the depending local libs... + if(lib->maplib) { + MapLibAddMapLib(my_context->maplib, lib->maplib); + free(lib->maplib); + lib->maplib = NULL; + } + if(!libraryInMapLib(my_context->maplib, lib)) + MapLibAddLib(my_context->maplib, lib); + MapLibRemoveLib(my_context->local_maplib, lib); + } + add_neededlib(neededlibs, lib); + return 0; + } + // load a new one + lib = NewLibrary(path, box64); + if(!lib) { + printf_log(LOG_DEBUG, "Faillure to create lib => fail\n"); + return 1; //Error + } + + add_neededlib(neededlibs, lib); + + // add lib now + if(local) { + MapLibAddLib(my_context->local_maplib, lib); + if(maplib) + MapLibAddLib(maplib, lib); + lib->maplib = NewLibrarian(box64, 0); + MapLibAddLib(lib->maplib, lib); + } else { + MapLibAddLib(my_context->maplib, lib); + } + + if(!maplib) + maplib = (local)?lib->maplib:my_context->maplib; + + int mainelf = GetElfIndex(lib); + + if(mainelf==-1) { + // It's a native libs, just add wrapped symbols to global map + if(AddSymbolsLibrary(maplib, lib, emu)) { // also add needed libs + printf_log(LOG_DEBUG, "Failure to Add lib => fail\n"); + return 1; + } + } else { + // it's an emulated lib, + // lets load dependancies before adding symbols and launch init sequence + if(LoadNeededLibs(box64->elfs[mainelf], maplib, &lib->needed, 0, box64, emu)) { + printf_log(LOG_DEBUG, "Failure to Add dependant lib => fail\n"); + return 1; + } + // some special case, where dependancies may not be correct + if(!strcmp(GetNameLib(lib), "libCgGL.so")) { + AddNeededLib(maplib, &lib->needed, 0, "libGL.so.1", box64, emu); + } + if(!strcmp(GetNameLib(lib), "libmss.so.6")) { + AddNeededLib(maplib, &lib->needed, 0, "libSDL-1.2.so.0", box64, emu); + AddNeededLib(maplib, &lib->needed, 0, "libdl.so.2", box64, emu); + } + // add symbols + if(AddSymbolsLibrary(maplib, lib, emu)) { // also add needed libs + printf_log(LOG_DEBUG, "Failure to Add lib => fail\n"); + return 1; + } + + // finalize the lib + if(FinalizeLibrary(lib, local?maplib:NULL, emu)) { + printf_log(LOG_DEBUG, "Failure to finalizing lib => fail\n"); + return 1; + } + } + // success + printf_log(LOG_DEBUG, "Created lib and added to maplib => success\n"); + + return 0; +} + +library_t* GetLibMapLib(lib_t* maplib, const char* name) +{ + printf_log(LOG_DEBUG, "Trying to Get \"%s\" to maplib\n", name); + return getLib(maplib, name); +} + +library_t* GetLibInternal(const char* name) +{ + printf_log(LOG_DEBUG, "Trying to Get \"%s\" to maplib\n", name); + library_t* lib = getLib(my_context->maplib, name); + if(!lib) lib = getLib(my_context->local_maplib, name); + return lib; +} + +EXPORTDYN +uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name) +{ + uintptr_t start = 0, end = 0; + if(GetGlobalSymbolStartEnd(maplib, name, &start, &end)) + return start; + return 0; +} + +int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self) +{ + //excude self if defined + if(maplib->context->elfs[0]!=self) { + if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end)) + if(*start) + return 1; + if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end)) + if(*start) + return 1; + } + for(int i=0; i<maplib->libsz; ++i) { + if(GetElfIndex(maplib->libraries[i].lib)==-1 || (maplib->context->elfs[GetElfIndex(maplib->libraries[i].lib)]!=self)) + if(GetLibSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start) + return 1; + } + // if self defined, give it another chance with self... + if(self) { + if(maplib->context->elfs[0]==self) { + if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end)) + if(*start) + return 1; + if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end)) + if(*start) + return 1; + } + for(int i=0; i<maplib->libsz; ++i) { + if(GetElfIndex(maplib->libraries[i].lib)!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i].lib)]==self)) + if(GetLibSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start) + return 1; + } + } + // nope, not found + return 0; +} +static int GetGlobalSymbolStartEnd_internal(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end) +{ + // search non-weak symbol, from older to newer (first GLOBAL object wins) + if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end)) + if(*start) + return 1; + // TODO: create a temporary map to search lib only 1 time, and in order of needed... + // search in needed libs from neededlibs first, in order + for(int i=0; i<my_context->neededlibs.size; ++i) + if(GetLibNoWeakSymbolStartEnd(my_context->neededlibs.libs[i], name, start, end)) + if(*start) + return 1; + // search in global symbols + for(int i=0; i<maplib->libsz; ++i) { + if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start) + return 1; + } + + // library from newer to older, weak only now + for(int i=maplib->libsz-1; i>=0; --i) { + if(GetLibSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) // only weak symbol haven't been found yet + if(*start) + return 1; + } + if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end)) + if(*start) + return 1; + // nope, not found + return 0; +} +//void** my_GetGTKDisplay(); +//void** my_GetGthreadsGotInitialized(); +int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end) +{ + if(GetGlobalSymbolStartEnd_internal(maplib, name, start, end)) { + if(start && end && *end==*start) { // object is of 0 sized, try to see an "_END" object of null size + uintptr_t start2, end2; + char* buff = (char*)malloc(strlen(name) + strlen("_END") + 1); + strcpy(buff, name); + strcat(buff, "_END"); + if(GetGlobalSymbolStartEnd_internal(maplib, buff, &start2, &end2)) { + if(end2>*end && start2==end2) + *end = end2; + } + free(buff); + } + return 1; + } + // some special case symbol, defined inside box64 itself +// if(!strcmp(name, "gdk_display")) { +// *start = (uintptr_t)my_GetGTKDisplay(); +// *end = *start+sizeof(void*); +// printf_log(LOG_INFO, "Using global gdk_display for gdk-x11 (%p:%p)\n", start, *(void**)start); +// return 1; +// } +// if(!strcmp(name, "g_threads_got_initialized")) { +// *start = (uintptr_t)my_GetGthreadsGotInitialized(); +// *end = *start+sizeof(int); +// printf_log(LOG_INFO, "Using global g_threads_got_initialized for gthread2 (%p:%p)\n", start, *(void**)start); +// return 1; +// } + // not found... + return 0; +} + +elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name) +{ + uintptr_t start = 0; + uintptr_t end = 0; + if(GetSymbolStartEnd(maplib->mapsymbols, name, &start, &end)) + return maplib->context->elfs[0]; + if(GetSymbolStartEnd(maplib->weaksymbols, name, &start, &end)) + return maplib->context->elfs[0]; + for(int i=0; i<maplib->libsz; ++i) { + if(GetLibSymbolStartEnd(maplib->libraries[i].lib, name, &start, &end)) { + int idx = GetElfIndex(maplib->libraries[i].lib); + if(idx==-1) { + printf_log(LOG_NONE, "Warning, getting Elf info for a native symbol \"%s\" from lib \"%s\"\n", name, GetNameLib(maplib->libraries[i].lib)); + return NULL; + } + return maplib->context->elfs[idx]; + } + } + // nope, not found + return NULL; +} + +int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end) +{ + if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end)) + if(*start || *end) + return 1; + for(int i=0; i<maplib->libsz; ++i) + if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start || *end) + return 1; + // nope, not found + return 0; +} + +int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name) +{ + uintptr_t start, end; + for(int i=0; i<maplib->libsz; ++i) + if(GetElfIndex(maplib->libraries[i].lib)==-1) + if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i].lib, name, &start, &end)) + if(start || end) + return 1; + // nope, not found + return 0; + +} + +int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self) +{ + if(maplib->context->elfs[0]==self || !self) { + if(GetSymbolStartEnd(maplib->localsymbols, name, start, end)) + if(*start || *end) + return 1; + if(self) + return 0; + } + for(int i=0; i<maplib->libsz; ++i) { + if(GetElfIndex(maplib->libraries[i].lib)!=-1 && (!self || maplib->context->elfs[GetElfIndex(maplib->libraries[i].lib)]==self)) { + if(GetLibLocalSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start) + return 1; + if(self) + return 0; + } + } + return 0; +} + +int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self) +{ + if(maplib->context->elfs[0]==self) { + if(GetSymbolStartEnd(maplib->localsymbols, name, start, end)) + if(*start || *end) + return 1; + } else { + for(int i=0; i<maplib->libsz; ++i) { + if(GetElfIndex(maplib->libraries[i].lib)!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i].lib)]==self)) + if(GetLibSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start || *end) + return 1; + } + } + return 0; +} + +int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self) +{ + if(maplib->context->elfs[0]==self) { + if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end)) + if(*start || *end) + return 1; + } else { + for(int i=0; i<maplib->libsz; ++i) { + if(GetElfIndex(maplib->libraries[i].lib)!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i].lib)]==self)) + if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i].lib, name, start, end)) + if(*start || *end) + return 1; + } + } + return 0; +} + + +void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz) +{ + int ret; + khint_t k = kh_put(mapsymbols, mapsymbols, name, &ret); + kh_value(mapsymbols, k).offs = addr; + kh_value(mapsymbols, k).sz = sz; +} +uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name) +{ + khint_t k = kh_get(mapsymbols, mapsymbols, name); + if(k==kh_end(mapsymbols)) + return 0; + return kh_val(mapsymbols, k).offs; +} +void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz) +{ + int ret; + khint_t k = kh_put(mapsymbols, mapsymbols, name, &ret); + if(ret==0) + return; // Symbol already there, don't touch it + kh_value(mapsymbols, k).offs = addr; + kh_value(mapsymbols, k).sz = sz; +} + +int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end) +{ + khint_t k = kh_get(mapsymbols, mapsymbols, name); + if(k==kh_end(mapsymbols)) + return 0; + *start = kh_val(mapsymbols, k).offs; + *end = *start + kh_val(mapsymbols, k).sz; + return 1; +} + +const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* start, uint32_t* sz) +{ + uintptr_t addr = (uintptr_t)p; + onesymbol_t *one; + kh_foreach_value_ref(mapsymbols, one, + if((one->offs >= addr) && (one->offs+one->sz<addr)) { + *start = one->offs; + *sz = one->sz; + return kh_key(mapsymbols, __i); + } + ); + return NULL; +} + +const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, const char** libname, void** base) +{ + // first, search in self... + const char* ret = NULL; + uintptr_t offs = 0; + uint32_t size = 0; + elfheader_t* h = FindElfAddress(my_context, (uintptr_t)p); + if(h) { + ret = FindNearestSymbolName(h, p, &offs, &size); + } + if(h) { + if(start) + *start = (void*)offs; + if(sz) + *sz = size; + if(libname) + *libname = ElfName(h); + if(base) + *base = GetBaseAddress(h); + return ret; + } + // TODO: then search in the other libs... + return NULL; +} + +void AddOffsetSymbol(lib_t *maplib, void* offs, const char* name) +{ + int ret; + khint_t k = kh_put(mapoffsets, maplib->mapoffsets, (uintptr_t)offs, &ret); + kh_value(maplib->mapoffsets, k) = (cstr_t)name; +} + +const char* GetNameOffset(lib_t *maplib, void* offs) +{ + if(!maplib || !maplib->mapoffsets) + return NULL; + khint_t k = kh_get(mapoffsets, maplib->mapoffsets, (uintptr_t)offs); + if (k!=kh_end(maplib->mapoffsets)) + return kh_value(maplib->mapoffsets, k); + return NULL; +} diff --git a/src/librarian/librarian_private.h b/src/librarian/librarian_private.h new file mode 100755 index 00000000..d70b048f --- /dev/null +++ b/src/librarian/librarian_private.h @@ -0,0 +1,44 @@ +#ifndef __LIBRARIAN_PRIVATE_H_ +#define __LIBRARIAN_PRIVATE_H_ +#include <stdint.h> + +#include "custommem.h" +#include "khash.h" + +typedef struct box64context_s box64context_t; + +typedef struct onesymbol_s { + uintptr_t offs; + uint32_t sz; + // need to track type of symbol? + // need to track origin? +} onesymbol_t; + +typedef struct { + char *name; + library_t *lib; +} onelib_t; + +typedef char* cstr_t; + +KHASH_MAP_DECLARE_STR(mapsymbols, onesymbol_t) + +KHASH_MAP_DECLARE_INT(mapoffsets, cstr_t); + +typedef struct lib_s { + khash_t(mapsymbols) *mapsymbols; + khash_t(mapsymbols) *weaksymbols; + khash_t(mapsymbols) *localsymbols; + khash_t(mapoffsets) *mapoffsets; + khash_t(mapsymbols) *globaldata; + onelib_t *libraries; + int libsz; + int libcap; + int ownlibs; + + box64context_t* context; + + bridge_t *bridge; // all x86 -> arm bridge +} lib_t; + +#endif //__LIBRARIAN_PRIVATE_H_ diff --git a/src/librarian/library.c b/src/librarian/library.c new file mode 100755 index 00000000..bcd8248a --- /dev/null +++ b/src/librarian/library.c @@ -0,0 +1,700 @@ +#define _GNU_SOURCE +#define __USE_GNU +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include "debug.h" +#include "library.h" +#include "elfloader.h" +#include "bridge.h" +#include "library_private.h" +#include "khash.h" +#include "box64context.h" +#include "fileutils.h" +#include "librarian.h" +#include "librarian_private.h" +#include "pathcoll.h" +#include "x64emu.h" + +#include "wrappedlibs.h" +// create the native lib list +#define GO(P, N) int wrapped##N##_init(library_t* lib, box64context_t *box64); \ + void wrapped##N##_fini(library_t* lib);\ + int wrapped##N##_get(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz); \ + int wrapped##N##_getnoweak(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz); +#include "library_list.h" +#undef GO + +#define GO(P, N) {P, wrapped##N##_init, wrapped##N##_fini, wrapped##N##_get, wrapped##N##_getnoweak}, +wrappedlib_t wrappedlibs[] = { +#include "library_list.h" +}; +#undef GO + +typedef struct bridged_s { + char* name; + uintptr_t start; + uint32_t end; +} bridged_t; + +KHASH_MAP_INIT_STR(bridgemap, bridged_t) + +KHASH_MAP_IMPL_STR(datamap, uint32_t) +KHASH_MAP_IMPL_STR(symbolmap, wrapper_t) +KHASH_MAP_IMPL_STR(symbol2map, symbol2_t) + +char* Path2Name(const char* path) +{ + char* name = (char*)calloc(1, MAX_PATH); + char* p = strrchr(path, '/'); + strcpy(name, (p)?(p+1):path); + // name should be libXXX.so.A(.BB.CCCC) + // so keep only 2 dot after ".so" (if any) + p = strstr(name, ".so"); + if(p) { + p=strchr(p+3, '.'); // this one is ok + //if(p) p=strchr(p+1, '.');// this one is ok too + if(p) p=strchr(p+1, '.');// this one is not + if(p) *p = '\0'; + } + return name; +} +int NbDot(const char* name) +{ + char *p = strstr(name, ".so"); + if(!p) + return -1; + int ret = 0; + while(p) { + p = strchr(p+1, '.'); + if(p) ++ret; + } + return ret; +} + +void EmuLib_Fini(library_t* lib) +{ + kh_destroy(mapsymbols, lib->priv.n.mapsymbols); + kh_destroy(mapsymbols, lib->priv.n.localsymbols); +} + +int EmuLib_Get(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz) +{ + khint_t k; + // symbols... + k = kh_get(mapsymbols, lib->priv.n.mapsymbols, name); + if(k!=kh_end(lib->priv.n.mapsymbols)) { + *offs = kh_value(lib->priv.n.mapsymbols, k).offs; + *sz = kh_value(lib->priv.n.mapsymbols, k).sz; + return 1; + } + // weak symbols... + k = kh_get(mapsymbols, lib->priv.n.weaksymbols, name); + if(k!=kh_end(lib->priv.n.weaksymbols)) { + *offs = kh_value(lib->priv.n.weaksymbols, k).offs; + *sz = kh_value(lib->priv.n.weaksymbols, k).sz; + return 1; + } + return 0; +} +int EmuLib_GetNoWeak(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz) +{ + khint_t k; + k = kh_get(mapsymbols, lib->priv.n.mapsymbols, name); + if(k!=kh_end(lib->priv.n.mapsymbols)) { + *offs = kh_value(lib->priv.n.mapsymbols, k).offs; + *sz = kh_value(lib->priv.n.mapsymbols, k).sz; + return 1; + } + return 0; +} +int EmuLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz) +{ + khint_t k; + k = kh_get(mapsymbols, lib->priv.n.localsymbols, name); + if(k!=kh_end(lib->priv.n.localsymbols)) { + *offs = kh_value(lib->priv.n.localsymbols, k).offs; + *sz = kh_value(lib->priv.n.localsymbols, k).sz; + return 1; + } + return 0; +} + +int NativeLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz) +{ + return 0; +} + +static void initNativeLib(library_t *lib, box64context_t* context) { + int nb = sizeof(wrappedlibs) / sizeof(wrappedlib_t); + for (int i=0; i<nb; ++i) { + if(strcmp(lib->name, wrappedlibs[i].name)==0) { + if(wrappedlibs[i].init(lib, context)) { + // error! + printf_log(LOG_NONE, "Error initializing native %s (last dlerror is %s)\n", lib->name, dlerror()); + return; // non blocker... + } + printf_log(LOG_INFO, "Using native(wrapped) %s\n", lib->name); + lib->priv.w.box64lib = context->box64lib; + lib->context = context; + lib->fini = wrappedlibs[i].fini; + lib->get = wrappedlibs[i].get; + lib->getnoweak = wrappedlibs[i].getnoweak; + lib->getlocal = NativeLib_GetLocal; + lib->type = 0; + // Call librarian to load all dependant elf + for(int i=0; i<lib->priv.w.needed; ++i) { + if(AddNeededLib(context->maplib, &lib->needed, 0, lib->priv.w.neededlibs[i], context, NULL)) { // probably all native, not emulated, so that's fine + printf_log(LOG_NONE, "Error: loading needed libs in elf %s\n", lib->priv.w.neededlibs[i]); + return; + } + } + break; + } + } +} + +static int loadEmulatedLib(const char* libname, library_t *lib, box64context_t* context) +{ + if(FileExist(libname, IS_FILE)) + { + FILE *f = fopen(libname, "rb"); + if(!f) { + printf_log(LOG_NONE, "Error: Cannot open %s\n", libname); + return 0; + } + elfheader_t *elf_header = LoadAndCheckElfHeader(f, libname, 0); + if(!elf_header) { + printf_log(LOG_DEBUG, "Error: reading elf header of %s\n", libname); // this one can be too alarming... + fclose(f); + return 0; + } + int mainelf = AddElfHeader(context, elf_header); + + if(CalcLoadAddr(elf_header)) { + printf_log(LOG_NONE, "Error: reading elf header of %s\n", libname); + fclose(f); + return 0; + } + // allocate memory + if(AllocElfMemory(context, elf_header, 0)) { + printf_log(LOG_NONE, "Error: allocating memory for elf %s\n", libname); + fclose(f); + return 0; + } + // Load elf into memory + if(LoadElfMemory(f, context, elf_header)) { + printf_log(LOG_NONE, "Error: loading in memory elf %s\n", libname); + fclose(f); + return 0; + } + // can close the file now + fclose(f); + + ElfAttachLib(elf_header, lib); + + lib->type = 1; + lib->fini = EmuLib_Fini; + lib->get = EmuLib_Get; + lib->getnoweak = EmuLib_GetNoWeak; + lib->getlocal = EmuLib_GetLocal; + lib->priv.n.elf_index = mainelf; + lib->priv.n.mapsymbols = kh_init(mapsymbols); + lib->priv.n.weaksymbols = kh_init(mapsymbols); + lib->priv.n.localsymbols = kh_init(mapsymbols); + + printf_log(LOG_INFO, "Using emulated %s\n", libname); + return 1; + } + return 0; +} + +static void initEmulatedLib(const char* path, library_t *lib, box64context_t* context) +{ + char libname[MAX_PATH]; + strcpy(libname, path); + int found = FileExist(libname, IS_FILE); + if(!found && !strchr(path, '/')) + for(int i=0; i<context->box64_ld_lib.size; ++i) + { + strcpy(libname, context->box64_ld_lib.paths[i]); + strcat(libname, path); + if(FileExist(libname, IS_FILE)) + if(loadEmulatedLib(libname, lib, context)) + return; + } + else + loadEmulatedLib(libname, lib, context); +} + +library_t *NewLibrary(const char* path, box64context_t* context) +{ + printf_log(LOG_DEBUG, "Trying to load \"%s\"\n", path); + library_t *lib = (library_t*)calloc(1, sizeof(library_t)); + lib->path = strdup(path); + lib->name = Path2Name(path); + lib->nbdot = NbDot(lib->name); + lib->context = context; + lib->type = -1; + printf_log(LOG_DEBUG, "Simplified name is \"%s\"\n", lib->name); + if(box64_nopulse) { + if(strstr(lib->name, "libpulse.so")==lib->name || strstr(lib->name, "libpulse-simple.so")==lib->name) { + Free1Library(&lib); + return NULL; + } + } + if(box64_novulkan) { + if(strstr(lib->name, "libvulkan.so")==lib->name) { + Free1Library(&lib); + return NULL; + } + } + int notwrapped = FindInCollection(lib->name, &context->box64_emulated_libs); + // And now, actually loading a library + // look for native(wrapped) libs first + if(!notwrapped) + initNativeLib(lib, context); + // then look for a native one + if(lib->type==-1) + initEmulatedLib(path, lib, context); + // still not loaded but notwrapped indicated: use wrapped... + if(lib->type==-1 && notwrapped) + initNativeLib(lib, context); + // nothing loaded, so error... + if(lib->type==-1) + { + Free1Library(&lib); + return NULL; + } + + lib->bridgemap = kh_init(bridgemap); + + return lib; +} +int AddSymbolsLibrary(lib_t *maplib, library_t* lib, x64emu_t* emu) +{ + lib->active = 1; + if(lib->type==1) { + elfheader_t *elf_header = lib->context->elfs[lib->priv.n.elf_index]; + // add symbols + AddSymbols(maplib, lib->priv.n.mapsymbols, lib->priv.n.weaksymbols, lib->priv.n.localsymbols, elf_header); + } + return 0; +} +int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x64emu_t* emu) +{ + if(!lib) + return 0; + if(lib->type==1) { + if(lib->priv.n.finalized) + return 0; + lib->priv.n.finalized = 1; + elfheader_t *elf_header = my_context->elfs[lib->priv.n.elf_index]; + // finalize relocations + if(RelocateElf(my_context->maplib, local_maplib, elf_header)) { + printf_log(LOG_NONE, "Error: relocating symbols in elf %s\n", lib->name); + return 1; + } + RelocateElfPlt(my_context->maplib, local_maplib, elf_header); + if(trace_func) { + if (GetGlobalSymbolStartEnd(my_context->maplib, trace_func, &trace_start, &trace_end)) { + SetTraceEmu(trace_start, trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", trace_func, (void*)trace_start, (void*)trace_end); + free(trace_func); + trace_func = NULL; + } else if(GetLibLocalSymbolStartEnd(lib, trace_func, &trace_start, &trace_end)) { + SetTraceEmu(trace_start, trace_end); + printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", trace_func, (void*)trace_start, (void*)trace_end); + free(trace_func); + trace_func = NULL; + } + } + RunElfInit(elf_header, emu); + } + if(box64_dynarec && strcmp(lib->name, "libfmod.so")==0) { + if (GetGlobalSymbolStartEnd(lib->maplib?lib->maplib:my_context->maplib, "FSOUND_Mixer_FPU_Ramp", &fmod_smc_start, &fmod_smc_end)) { + printf_log(LOG_INFO, "Detected libfmod with potential SMC part, applying workaround in Dynarec\n"); + } + } + return 0; +} + +int ReloadLibrary(library_t* lib, x64emu_t* emu) +{ + lib->active = 1; + if(lib->type==1) { + elfheader_t *elf_header = lib->context->elfs[lib->priv.n.elf_index]; + // reload image in memory and re-run the mapping + char libname[MAX_PATH]; + strcpy(libname, lib->path); + int found = FileExist(libname, IS_FILE); + if(!found && !strchr(lib->path, '/')) + for(int i=0; i<lib->context->box64_ld_lib.size; ++i) + { + strcpy(libname, lib->context->box64_ld_lib.paths[i]); + strcat(libname, lib->path); + if(FileExist(libname, IS_FILE)) + break; + } + if(!FileExist(libname, IS_FILE)) { + printf_log(LOG_NONE, "Error: open file to re-load elf %s\n", libname); + return 1; // failed to reload... + } + FILE *f = fopen(libname, "rb"); + if(!f) { + printf_log(LOG_NONE, "Error: cannot open file to re-load elf %s (errno=%d/%s)\n", libname, errno, strerror(errno)); + return 1; // failed to reload... + } + if(ReloadElfMemory(f, lib->context, elf_header)) { + printf_log(LOG_NONE, "Error: re-loading in memory elf %s\n", libname); + fclose(f); + return 1; + } + // can close the file now + fclose(f); + if(RelocateElf(lib->context->maplib, lib->maplib, elf_header)) { + printf_log(LOG_NONE, "Error: relocating symbols in elf %s\n", lib->name); + return 1; + } + RelocateElfPlt(lib->context->maplib, lib->maplib, elf_header); + // init (will use PltRelocator... because some other libs are not yet resolved) + RunElfInit(elf_header, emu); + } + return 0; +} + +void InactiveLibrary(library_t* lib) +{ + lib->active = 0; +} + +void Free1Library(library_t **lib) +{ + if(!(*lib)) return; + + if((*lib)->type!=-1 && (*lib)->fini) { + (*lib)->fini(*lib); + } + free((*lib)->name); + free((*lib)->path); + free((*lib)->altmy); + + if((*lib)->bridgemap) { + bridged_t *br; + kh_foreach_value_ref((*lib)->bridgemap, br, + free(br->name); + ); + kh_destroy(bridgemap, (*lib)->bridgemap); + } + if((*lib)->symbolmap) + kh_destroy(symbolmap, (*lib)->symbolmap); + if((*lib)->wsymbolmap) + kh_destroy(symbolmap, (*lib)->wsymbolmap); + if((*lib)->datamap) + kh_destroy(datamap, (*lib)->datamap); + if((*lib)->wdatamap) + kh_destroy(datamap, (*lib)->wdatamap); + if((*lib)->mydatamap) + kh_destroy(datamap, (*lib)->mydatamap); + if((*lib)->mysymbolmap) + kh_destroy(symbolmap, (*lib)->mysymbolmap); + if((*lib)->stsymbolmap) + kh_destroy(symbolmap, (*lib)->stsymbolmap); + if((*lib)->symbol2map) + kh_destroy(symbol2map, (*lib)->symbol2map); + free_neededlib(&(*lib)->needed); + + if((*lib)->maplib) + FreeLibrarian(&(*lib)->maplib); + + free(*lib); + *lib = NULL; +} + +char* GetNameLib(library_t *lib) +{ + return lib->name; +} +int IsSameLib(library_t* lib, const char* path) +{ + int ret = 0; + if(!lib) + return 0; + char* name = Path2Name(path); + if(strcmp(name, lib->name)==0) + ret=1; + else { + int n = NbDot(name); + if(n>=0 && n<lib->nbdot) + if(strncmp(name, lib->name, strlen(name))==0) + ret=1; + } + + free(name); + return ret; +} +int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end) +{ + if(!name[0] || !lib->active) + return 0; + khint_t k; + // check first if already in the map + k = kh_get(bridgemap, lib->bridgemap, name); + if(k!=kh_end(lib->bridgemap)) { + *start = kh_value(lib->bridgemap, k).start; + *end = kh_value(lib->bridgemap, k).end; + return 1; + } + // get a new symbol + if(lib->get(lib, name, start, end)) { + *end += *start; // lib->get(...) gives size, not end + char* symbol = strdup(name); + int ret; + k = kh_put(bridgemap, lib->bridgemap, symbol, &ret); + kh_value(lib->bridgemap, k).name = symbol; + kh_value(lib->bridgemap, k).start = *start; + kh_value(lib->bridgemap, k).end = *end; + return 1; + } + // nope + return 0; +} +int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end) +{ + if(!name[0] || !lib->active) + return 0; + khint_t k; + // get a new symbol + if(lib->getnoweak(lib, name, start, end)) { + *end += *start; // lib->get(...) gives size, not end + // check if already in the map + k = kh_get(bridgemap, lib->bridgemap, name); + if(k!=kh_end(lib->bridgemap)) { + *start = kh_value(lib->bridgemap, k).start; + *end = kh_value(lib->bridgemap, k).end; + return 1; + } + char* symbol = strdup(name); + int ret; + k = kh_put(bridgemap, lib->bridgemap, symbol, &ret); + kh_value(lib->bridgemap, k).name = symbol; + kh_value(lib->bridgemap, k).start = *start; + kh_value(lib->bridgemap, k).end = *end; + return 1; + } + // nope + return 0; +} +int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end) +{ + if(!name[0] || !lib->active) + return 0; + khint_t k; + // check first if already in the map + k = kh_get(bridgemap, lib->bridgemap, name); + if(k!=kh_end(lib->bridgemap)) { + *start = kh_value(lib->bridgemap, k).start; + *end = kh_value(lib->bridgemap, k).end; + return 1; + } + // get a new symbol + if(lib->getlocal(lib, name, start, end)) { + *end += *start; // lib->get(...) gives size, not end + char* symbol = strdup(name); + int ret; + k = kh_put(bridgemap, lib->bridgemap, symbol, &ret); + kh_value(lib->bridgemap, k).name = symbol; + kh_value(lib->bridgemap, k).start = *start; + kh_value(lib->bridgemap, k).end = *end; + return 1; + } + // nope + return 0; +} +int GetElfIndex(library_t* lib) +{ + if(!lib || lib->type!=1) + return -1; + return lib->priv.n.elf_index; +} + +int getSymbolInMaps(library_t*lib, const char* name, int noweak, uintptr_t *addr, uint32_t *size) +{ + if(!lib->active) + return 0; + khint_t k; + void* symbol; + // check in datamap + k = kh_get(datamap, lib->datamap, name); + if (k!=kh_end(lib->datamap)) { + symbol = dlsym(lib->priv.w.lib, kh_key(lib->datamap, k)); + if(symbol) { + // found! + *addr = (uintptr_t)symbol; + *size = kh_value(lib->datamap, k); + return 1; + } + } + if(!noweak) { + k = kh_get(datamap, lib->wdatamap, name); + if (k!=kh_end(lib->wdatamap)) { + symbol = dlsym(lib->priv.w.lib, kh_key(lib->wdatamap, k)); + if(symbol) { + // found! + *addr = (uintptr_t)symbol; + *size = kh_value(lib->wdatamap, k); + return 1; + } + } + } + // check in mydatamap + k = kh_get(datamap, lib->mydatamap, name); + if (k!=kh_end(lib->mydatamap)) { + char buff[200]; + if(lib->altmy) + strcpy(buff, lib->altmy); + else + strcpy(buff, "my_"); + strcat(buff, name); + symbol = dlsym(lib->priv.w.box64lib, buff); + if(!symbol) + printf_log(LOG_NONE, "Warning, data %s not found\n", buff); + if(symbol) { + // found! + *addr = (uintptr_t)symbol; + *size = kh_value(lib->mydatamap, k); + return 1; + } + } + // check in mysymbolmap + k = kh_get(symbolmap, lib->mysymbolmap, name); + if (k!=kh_end(lib->mysymbolmap)) { + char buff[200]; + if(lib->altmy) + strcpy(buff, lib->altmy); + else + strcpy(buff, "my_"); + strcat(buff, name); + symbol = dlsym(lib->priv.w.box64lib, buff); + if(!symbol) { + printf_log(LOG_NONE, "Warning, function %s not found\n", buff); + } else + AddOffsetSymbol(lib->context->maplib, symbol, name); + *addr = AddBridge(lib->priv.w.bridge, kh_value(lib->mysymbolmap, k), symbol, 0); + *size = sizeof(void*); + return 1; + } + // check in stsymbolmap (return struct...) + k = kh_get(symbolmap, lib->stsymbolmap, name); + if (k!=kh_end(lib->stsymbolmap)) { + char buff[200]; + if(lib->altmy) + strcpy(buff, lib->altmy); + else + strcpy(buff, "my_"); + strcat(buff, name); + symbol = dlsym(lib->priv.w.box64lib, buff); + if(!symbol) { + printf_log(LOG_NONE, "Warning, function %s not found\n", buff); + } else + AddOffsetSymbol(lib->context->maplib, symbol, name); + *addr = AddBridge(lib->priv.w.bridge, kh_value(lib->stsymbolmap, k), symbol, 4); // all of this for this little "4" + *size = sizeof(void*); + return 1; + } + // check in symbolmap + k = kh_get(symbolmap, lib->symbolmap, name); + if (k!=kh_end(lib->symbolmap)) { + symbol = dlsym(lib->priv.w.lib, name); + if(!symbol && lib->priv.w.altprefix) { + char newname[200]; + strcpy(newname, lib->priv.w.altprefix); + strcat(newname, name); + symbol = dlsym(lib->priv.w.lib, newname); + } + if(!symbol) { + printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", name, lib->name); + return 0; + } else + AddOffsetSymbol(lib->context->maplib, symbol, name); + *addr = AddBridge(lib->priv.w.bridge, kh_value(lib->symbolmap, k), symbol, 0); + *size = sizeof(void*); + return 1; + } + if(!noweak) { + k = kh_get(symbolmap, lib->wsymbolmap, name); + if (k!=kh_end(lib->wsymbolmap)) { + symbol = dlsym(lib->priv.w.lib, name); + if(!symbol && lib->priv.w.altprefix) { + char newname[200]; + strcpy(newname, lib->priv.w.altprefix); + strcat(newname, name); + symbol = dlsym(lib->priv.w.lib, newname); + } + if(!symbol) { + printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", name, lib->name); + return 0; + } else + AddOffsetSymbol(lib->context->maplib, symbol, name); + *addr = AddBridge(lib->priv.w.bridge, kh_value(lib->wsymbolmap, k), symbol, 0); + *size = sizeof(void*); + return 1; + } + } + // check in symbol2map + k = kh_get(symbol2map, lib->symbol2map, name); + if (k!=kh_end(lib->symbol2map)) + if(!noweak || !kh_value(lib->symbol2map, k).weak) + { + symbol = dlsym(lib->priv.w.lib, kh_value(lib->symbol2map, k).name); + if(!symbol) + symbol = dlsym(RTLD_DEFAULT, kh_value(lib->symbol2map, k).name); // search globaly maybe + if(!symbol) { + printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", kh_value(lib->symbol2map, k).name, lib->name); + return 0; + } else + AddOffsetSymbol(lib->context->maplib, symbol, name); + *addr = AddBridge(lib->priv.w.bridge, kh_value(lib->symbol2map, k).w, symbol, 0); + *size = sizeof(void*); + return 1; + } + + return 0; +} + +int GetNeededLibN(library_t* lib) { + return lib->needed.size; +} +library_t* GetNeededLib(library_t* lib, int idx) +{ + if(idx<0 || idx>=lib->needed.size) + return NULL; + return lib->needed.libs[idx]; +} +needed_libs_t* GetNeededLibs(library_t* lib) +{ + return &lib->needed; +} + +void* GetHandle(library_t* lib) +{ + if(!lib) + return NULL; + if(lib->type!=0) + return NULL; + return lib->priv.w.lib; +} + +lib_t* GetMaplib(library_t* lib) +{ + if(!lib) + return NULL; + return lib->maplib; +} \ No newline at end of file diff --git a/src/librarian/library_private.h b/src/librarian/library_private.h new file mode 100755 index 00000000..78a7da94 --- /dev/null +++ b/src/librarian/library_private.h @@ -0,0 +1,101 @@ +#ifndef __LIBRARY_PRIVATE_H_ +#define __LIBRARY_PRIVATE_H_ +#include <stdint.h> + +#include "custommem.h" +#include "khash.h" +#include "wrappedlibs.h" +#include "box64context.h" + +typedef struct lib_s lib_t; +typedef struct bridge_s bridge_t; +typedef struct kh_bridgemap_s kh_bridgemap_t; +typedef struct kh_mapsymbols_s kh_mapsymbols_t; + +typedef struct x64emu_s x64emu_t; +typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc); + +typedef struct symbol2_s { + wrapper_t w; + const char* name; + int weak; +} symbol2_t; + +KHASH_MAP_DECLARE_STR(symbolmap, wrapper_t) +KHASH_MAP_DECLARE_STR(symbol2map, symbol2_t) +KHASH_MAP_DECLARE_STR(datamap, uint32_t) + + +#ifndef MAX_PATH +#define MAX_PATH 4096 +#endif + +typedef struct wlib_s { + bridge_t *bridge; + void* lib; // dlopen result + void* priv; // actual private + void* p2; // second private + void* box64lib; // ref to the dlopen on box86 itself from context + char* altprefix; // if function names are mangled.. + int needed; + char** neededlibs; +} wlib_t; + +typedef struct nlib_s { + int elf_index; + int finalized; + kh_mapsymbols_t *mapsymbols; + kh_mapsymbols_t *weaksymbols; + kh_mapsymbols_t *localsymbols; +} nlib_t; + +typedef struct library_s { + char* name; // <> path + char* path; // original path + int nbdot; // nombre of "." after .so + int type; // 0: native(wrapped) 1: emulated(elf) -1: undetermined + int active; + wrappedlib_fini_t fini; + wrappedlib_get_t get; // get weak and no weak + wrappedlib_get_t getnoweak; // get only non weak symbol + wrappedlib_get_t getlocal; + union { + wlib_t w; + nlib_t n; + } priv; // private lib data + box64context_t *context; // parent context + kh_bridgemap_t *bridgemap; + kh_symbolmap_t *symbolmap; + kh_symbolmap_t *wsymbolmap; + kh_symbolmap_t *mysymbolmap; + kh_symbolmap_t *stsymbolmap; + kh_symbol2map_t *symbol2map; + kh_datamap_t *datamap; + kh_datamap_t *wdatamap; + kh_datamap_t *mydatamap; + char *altmy; // to avoid duplicate symbol, like with SDL1/SDL2 + needed_libs_t needed; + lib_t *maplib; // local maplib, for dlopen'd library with LOCAL binding (most of the dlopen) +} library_t; + +// type for map elements +typedef struct map_onesymbol_s { + const char* name; + wrapper_t w; + int weak; +} map_onesymbol_t; +typedef struct map_onesymbol2_s { + const char* name; + wrapper_t w; + int weak; + const char* name2; +} map_onesymbol2_t; +typedef struct map_onedata_s { + const char* name; + uint32_t sz; + int weak; +} map_onedata_t; + +int getSymbolInMaps(library_t*lib, const char* name, int noweak, uintptr_t *addr, uint32_t *size); // Add bridges to functions + +#endif //__LIBRARY_PRIVATE_H_ \ No newline at end of file diff --git a/src/library_list.h b/src/library_list.h new file mode 100755 index 00000000..7d24d334 --- /dev/null +++ b/src/library_list.h @@ -0,0 +1,146 @@ +#ifndef GO +#error Nope +#endif + +GO("libc.so.6", libc) +//GO("libpthread.so.0", libpthread) +//GO("librt.so.1", librt) +//GO("libGL.so.1", libgl) +//GO("libGL.so", libgl) +//GO("libGLU.so.1", libglu) +//GO("libX11.so.6", libx11) +//GO("libasound.so.2", libasound) +//GO("libdl.so.2", libdl) +//GO("libm.so.6", libm) +//GO("libSDL2-2.0.so.0", sdl2) +//GO("libSDL2-2.0.so.1", sdl2) +//GO("libSDL2.so", sdl2) +//GO("libsdl2-2.0.so.0", sdl2) +//GO("libSDL2_mixer-2.0.so.0", sdl2mixer) +//GO("libSDL2_image-2.0.so.0", sdl2image) +//GO("libSDL2_ttf-2.0.so.0", sdl2ttf) +//GO("libSDL-1.2.so.0", sdl1) +//GO("libSDL-1.1.so.0", sdl1) +//GO("libSDL_mixer-1.2.so.0", sdl1mixer) +//GO("libSDL_image-1.2.so.0", sdl1image) +//GO("libSDL_ttf-2.0.so.0", sdl1ttf) +//GO("libsmpeg-0.4.so.0", smpeg) +//GO("libsmpeg2-2.0.so.0", smpeg2) +//GO("libvorbisfile.so.3", vorbisfile) +//GO("libvorbis.so.0", libvorbis) +//GO("libogg.so.0", libogg) +//GO("libpng12.so.0", png12) +//GO("libpng16.so.16", png16) +//GO("libXxf86vm.so.1", libxxf86vm) +//GO("libXinerama.so.1", xinerama) +//GO("libXrandr.so.2", libxrandr) +//GO("libXext.so.6", libxext) +//GO("libXfixes.so.3", libxfixes) +//GO("libXcursor.so.1", libxcursor) +//GO("libXrender.so.1", libxrender) +//GO("libXi.so.6", libxi) +//GO("libXss.so.1", libxss) +//GO("libXpm.so.4", libxpm) +//GO("libXau.so.6", libxau) +//GO("libXdmcp.so.6", libxdmcp) +//GO("libX11-xcb.so.1", libx11xcb) +//GO("libxcb.so.1", libxcb) +//GO("libxcb-xfixes.so.0", libxcbxfixes) +//GO("libxcb-shape.so.0", libxcbshape) +//GO("libxcb-shm.so.0", libxcbshm) +//GO("libxcb-randr.so.0", libxcbrandr) +//GO("libxcb-image.so.0", libxcbimage) +//GO("libxcb-keysyms.so.1", libxcbkeysyms) +//GO("libxcb-xtest.so.0", libxcbxtest) +//GO("libxcb-dri2.so.0", libxcbdri2) +//GO("libxcb-dri3.so.0", libxcbdri3) +//GO("libxcb-present.so.0", libxcbpresent) +//GO("libXtst.so.6", libxtst) +//GO("libXt.so.6", libxt) +//GO("libXcomposite.so.1", libxcomposite) +//GO("libXdamage.so.1", libxdamage) +//GO("libXmu.so.6", libxmu) +//GO("libz.so.1", libz) +//GO("libopenal.so.1", openal) +//GO("libopenal.so.0", openal) +//GO("libopenal.so", openal) +//GO("openal.so", openal) +//GO("libalut.so.0", alut) +//GO("libjpeg.so.8", libjpeg) +//GO("libjpeg.so.62", libjpeg62) +//GO("libturbojpeg.so.0", turbojpeg) +//GO("libcurl.so.4", curl) +//GO("libcurl-gnutls.so.4", curl) +//GO("libudev.so.0", udev0) +//GO("libudev.so.1", udev1) +//GO("libdbus-1.so.3", dbus) +//GO("libiconv.so.2", iconv) +//GO("libdrm.so.2", libdrm) +//GO("libcrypto.so.1", crypto) +//GO("libssl.so.1", libssl) +//GO("libcrypt.so.1", libcrypt) +//GO("libutil.so.1", util) +//GO("libuuid.so.1", libuuid) +//GO("libresolv.so.2", libresolv) +//GO("libpulse-simple.so.0", pulsesimple) +//GO("libpulse.so.0", pulse) +//GO("libsndfile.so.1", libsndfile) +//GO("libgtk-x11-2.0.so.0", gtkx112) +//GO("libgdk-x11-2.0.so.0", gdkx112) +//GO("libgtk-3.so.0", gtk3) +//GO("libgdk-3.so.0", gdk3) +//GO("libgdk_pixbuf-2.0.so.0", gdkpixbuf2) +//GO("libgio-2.0.so.0", gio2) +//GO("libgmodule-2.0.so.0", gmodule2) +//GO("libgobject-2.0.so.0", gobject2) +//GO("libglib-2.0.so.0", glib2) +//GO("libgthread-2.0.so.0", gthread2) +//GO("libgstreamer-0.10.so.0", gstreamer010) +//GO("libgstinterfaces-0.10.so.0", gstinterfaces010) +//GO("libdbusmenu-gtk.so.4", dbusmenugtk) +//GO("libdbusmenu-glib.so.4", dbusmenuglib) +//GO("libdbus-glib-1.so.2", dbusglib1) +//GO("libgudev-1.0.so.0", gudev1) +//GO("libappindicator.so.1", appindicator) +//GO("libatk-1.0.so.0", atk) +//GO("libpangoft2-1.0.so", pangoft2) +//GO("libpangoft2-1.0.so.0", pangoft2) +//GO("libpangocairo-1.0.so.0", pangocairo) +//GO("libcairo.so.2", cairo) +//GO("libpango-1.0.so.0", pango) +//GO("libnm.so.0", libnm) +//GO("libnm-glib.so.4", libnm) +//GO("libnm-util.so.2", libnm) +//GO("libfontconfig.so.1", fontconfig) +//GO("libfreetype.so.6", freetype) +//GO("libbz2.so.1", bz2) +//GO("libSM.so.6", libsm) +//GO("libICE.so.6", libice) +//GO("libusb-1.0.so.0", libusb1) +//GO("libncursesw.so.5", libncursesw) +//GO("libformw.so.5", libformw) +//GO("libncurses.so.5", libncurses) +//GO("libtinfo.so.5", libtinfo) +//GO("libncurses.so.6", libncurses6) +//GO("libtinfo.so.6", libtinfo6) +//GO("libtcmalloc_minimal.so.4", tcmallocminimal) +//GO("libmpg123.so.0", mpg123) +//GO("libgnutls.so.30", gnutls) +//GO("libcups.so.2", libcups) +//GO("d3dadapter9.so.1", d3dadapter9) +//GO("libvulkan.so.1", vulkan) +//GO("libvulkan.so", vulkan) +//GO("libwayland-client.so.0", waylandclient) +//GO("libxml2.so.2", xml2) +//GO("libxslt.so.1", xslt) +//GO("libldap_r-2.4.so.2", ldapr) +//GO("liblber-2.4.so.2", lber) +//GO("libnsl.so.1", nsl) +//GO("liblcms2.so.2", lcms2) +//GO("libkrb5.so.3", krb5) +//GO("libgssapi_krb5.so.2", gssapikrb5) +//GO("libtiff.so.5", libtiff) + +GO("ld-linux-x86-64.so.2", ldlinux) + +//GO("crashhandler.so", crashhandler) diff --git a/src/libtools/threads.c b/src/libtools/threads.c index a245d6a9..64cc414a 100755 --- a/src/libtools/threads.c +++ b/src/libtools/threads.c @@ -12,7 +12,7 @@ #include "box64context.h" #include "threads.h" #include "emu/x64emu_private.h" -//#include "tools/bridge_private.h" +#include "tools/bridge_private.h" #include "x64run.h" #include "x64emu.h" #include "box64stack.h" @@ -22,7 +22,7 @@ #include "emu/x64run_private.h" #include "x64trace.h" //#include "dynarec.h" -//#include "bridge.h" +#include "bridge.h" #ifdef DYNAREC #include "dynablock.h" #endif @@ -756,31 +756,31 @@ EXPORT int my_pthread_mutex_unlock(pthread_mutex_t *m) #endif #endif -//static void emujmpbuf_destroy(void* p) -//{ -// emu_jmpbuf_t *ej = (emu_jmpbuf_t*)p; -// free(ej->jmpbuf); -// free(ej); -//} +static void emujmpbuf_destroy(void* p) +{ + emu_jmpbuf_t *ej = (emu_jmpbuf_t*)p; + free(ej->jmpbuf); + free(ej); +} -//static pthread_key_t jmpbuf_key; +static pthread_key_t jmpbuf_key; -//emu_jmpbuf_t* GetJmpBuf() -//{ -// emu_jmpbuf_t *ejb = (emu_jmpbuf_t*)pthread_getspecific(jmpbuf_key); -// if(!ejb) { -// ejb = (emu_jmpbuf_t*)calloc(1, sizeof(emu_jmpbuf_t)); -// ejb->jmpbuf = calloc(1, sizeof(struct __jmp_buf_tag)); -// pthread_setspecific(jmpbuf_key, ejb); -// } -// return ejb; -//} +emu_jmpbuf_t* GetJmpBuf() +{ + emu_jmpbuf_t *ejb = (emu_jmpbuf_t*)pthread_getspecific(jmpbuf_key); + if(!ejb) { + ejb = (emu_jmpbuf_t*)calloc(1, sizeof(emu_jmpbuf_t)); + ejb->jmpbuf = calloc(1, sizeof(struct __jmp_buf_tag)); + pthread_setspecific(jmpbuf_key, ejb); + } + return ejb; +} void init_pthread_helper() { // InitCancelThread(); // mapcond = kh_init(mapcond); -// pthread_key_create(&jmpbuf_key, emujmpbuf_destroy); + pthread_key_create(&jmpbuf_key, emujmpbuf_destroy); #ifndef NOALIGN // unaligned_mutex = kh_init(mutex); #endif diff --git a/src/tools/callback.c b/src/tools/callback.c new file mode 100755 index 00000000..8c46139e --- /dev/null +++ b/src/tools/callback.c @@ -0,0 +1,86 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <stdarg.h> + +#include "debug.h" +#include "x64emu.h" +#include "x64run.h" +#include "emu/x64emu_private.h" +#include "emu/x64run_private.h" +#include "box64context.h" +#include "box64stack.h" +#include "dynarec.h" + +EXPORTDYN +uint64_t RunFunction(box64context_t *context, uintptr_t fnc, int nargs, ...) +{ + x64emu_t *emu = thread_get_emu(); + + if(nargs>6) + R_ESP -= (nargs-6)*4; // need to push in reverse order + + uint64_t *p = (uint64_t*)R_RSP; + + va_list va; + va_start (va, nargs); + for (int i=0; i<nargs; ++i) { + if(i<6) { + int nn[] = {_DI, _SI, _DX, _CX, _R8, _R9}; + emu->regs[nn[i]].q[0] = va_arg(va, uint64_t); + } else { + *p = va_arg(va, uint64_t); + p++; + } + } + va_end (va); + + DynaCall(emu, fnc); + if(nargs>6) + R_ESP+=((nargs-6)*4); + + uint64_t ret = R_RAX; + + return ret; +} + +EXPORTDYN +uint64_t RunFunctionWithEmu(x64emu_t *emu, int QuitOnLongJump, uintptr_t fnc, int nargs, ...) +{ + if(nargs>6) + R_ESP -= (nargs-6)*4; // need to push in reverse order + + uint64_t *p = (uint64_t*)R_RSP; + + va_list va; + va_start (va, nargs); + for (int i=0; i<nargs; ++i) { + if(i<6) { + int nn[] = {_DI, _SI, _DX, _CX, _R8, _R9}; + emu->regs[nn[i]].q[0] = va_arg(va, uint64_t); + } else { + *p = va_arg(va, uint64_t); + p++; + } + } + va_end (va); + + uintptr_t oldip = R_RIP; + int old_quit = emu->quit; + int oldlong = emu->quitonlongjmp; + + emu->quit = 0; + emu->quitonlongjmp = QuitOnLongJump; + + DynaCall(emu, fnc); + + if(oldip==R_RIP && nargs>6) + R_ESP+=((nargs-6)*4); // restore stack only if EIP is the one expected (else, it means return value is not the one expected) + + emu->quit = old_quit; + emu->quitonlongjmp = oldlong; + + + return R_RAX; +} diff --git a/src/wrapped/generated/functions_list.txt b/src/wrapped/generated/functions_list.txt new file mode 100644 index 00000000..147507f1 --- /dev/null +++ b/src/wrapped/generated/functions_list.txt @@ -0,0 +1,15 @@ +#() vFE +#() vFv +#() pFE +#() pFp +#() vFpp +#() iFEp +#() pFEp +#() iFEpp +#() pFEpi +#() pFEpp +#() iFEpip +#() pFEppi +#() pFEppp +#() iFipppi +#() pFEv -> pFE diff --git a/src/wrapped/generated/wrapper.c b/src/wrapped/generated/wrapper.c new file mode 100644 index 00000000..6598ae7e --- /dev/null +++ b/src/wrapped/generated/wrapper.c @@ -0,0 +1,102 @@ +/***************************************************************** + * File automatically generated by rebuild_wrappers.py (v1.2.0.09) + *****************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "wrapper.h" +#include "emu/x64emu_private.h" +#include "emu/x87emu_private.h" +#include "regs.h" +#include "x64emu.h" + +typedef union ui64_s { + int64_t i; + uint64_t u; + uint32_t d[2]; +} ui64_t; + +typedef struct _2uint_struct_s { + uint32_t a; + uint32_t b; +} _2uint_struct_t; + +extern void* my__IO_2_1_stderr_; +extern void* my__IO_2_1_stdin_ ; +extern void* my__IO_2_1_stdout_; + +static void* io_convert(void* v) +{ + if(!v) + return v; + if(v==my__IO_2_1_stderr_) + return stderr; + if(v==my__IO_2_1_stdin_) + return stdin; + if(v==my__IO_2_1_stdout_) + return stdout; + return v; +} + +typedef struct my_GValue_s +{ + int g_type; + union { + int v_int; + int64_t v_int64; + uint64_t v_uint64; + float v_float; + double v_double; + void* v_pointer; + } data[2]; +} my_GValue_t; + +static void alignGValue(my_GValue_t* v, void* value) +{ + v->g_type = *(int*)value; + memcpy(v->data, value+4, 2*sizeof(double)); +} +static void unalignGValue(void* value, my_GValue_t* v) +{ + *(int*)value = v->g_type; + memcpy(value+4, v->data, 2*sizeof(double)); +} + +void* VulkanFromx86(void* src, void** save); +void VulkanTox86(void* src, void* save); + +#define ST0val ST0.d + +int of_convert(int); +typedef void (*vFE_t)(x64emu_t*); +typedef void (*vFv_t)(void); +typedef void* (*pFE_t)(x64emu_t*); +typedef void* (*pFp_t)(void*); +typedef void (*vFpp_t)(void*, void*); +typedef int32_t (*iFEp_t)(x64emu_t*, void*); +typedef void* (*pFEp_t)(x64emu_t*, void*); +typedef int32_t (*iFEpp_t)(x64emu_t*, void*, void*); +typedef void* (*pFEpi_t)(x64emu_t*, void*, int32_t); +typedef void* (*pFEpp_t)(x64emu_t*, void*, void*); +typedef int32_t (*iFEpip_t)(x64emu_t*, void*, int32_t, void*); +typedef void* (*pFEppi_t)(x64emu_t*, void*, void*, int32_t); +typedef void* (*pFEppp_t)(x64emu_t*, void*, void*, void*); +typedef int32_t (*iFipppi_t)(int32_t, void*, void*, void*, int32_t); + +void vFE(x64emu_t *emu, uintptr_t fcn) { vFE_t fn = (vFE_t)fcn; fn(emu); } +void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); } +void pFE(x64emu_t *emu, uintptr_t fcn) { pFE_t fn = (pFE_t)fcn; R_RAX=(uintptr_t)fn(emu); } +void pFp(x64emu_t *emu, uintptr_t fcn) { pFp_t fn = (pFp_t)fcn; R_RAX=(uintptr_t)fn(*(void**)(R_RSP + 4)); } +void vFpp(x64emu_t *emu, uintptr_t fcn) { vFpp_t fn = (vFpp_t)fcn; fn(*(void**)(R_RSP + 4), *(void**)(R_RSP + 12)); } +void iFEp(x64emu_t *emu, uintptr_t fcn) { iFEp_t fn = (iFEp_t)fcn; R_RAX=fn(emu, *(void**)(R_RSP + 4)); } +void pFEp(x64emu_t *emu, uintptr_t fcn) { pFEp_t fn = (pFEp_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4)); } +void iFEpp(x64emu_t *emu, uintptr_t fcn) { iFEpp_t fn = (iFEpp_t)fcn; R_RAX=fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12)); } +void pFEpi(x64emu_t *emu, uintptr_t fcn) { pFEpi_t fn = (pFEpi_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(int32_t*)(R_RSP + 12)); } +void pFEpp(x64emu_t *emu, uintptr_t fcn) { pFEpp_t fn = (pFEpp_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12)); } +void iFEpip(x64emu_t *emu, uintptr_t fcn) { iFEpip_t fn = (iFEpip_t)fcn; R_RAX=fn(emu, *(void**)(R_RSP + 4), *(int32_t*)(R_RSP + 12), *(void**)(R_RSP + 16)); } +void pFEppi(x64emu_t *emu, uintptr_t fcn) { pFEppi_t fn = (pFEppi_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12), *(int32_t*)(R_RSP + 20)); } +void pFEppp(x64emu_t *emu, uintptr_t fcn) { pFEppp_t fn = (pFEppp_t)fcn; R_RAX=(uintptr_t)fn(emu, *(void**)(R_RSP + 4), *(void**)(R_RSP + 12), *(void**)(R_RSP + 20)); } +void iFipppi(x64emu_t *emu, uintptr_t fcn) { iFipppi_t fn = (iFipppi_t)fcn; R_RAX=fn(*(int32_t*)(R_RSP + 4), *(void**)(R_RSP + 8), *(void**)(R_RSP + 16), *(void**)(R_RSP + 24), *(int32_t*)(R_RSP + 32)); } + +void pFEv(x64emu_t *emu, uintptr_t fcn) { pFE_t fn = (pFE_t)fcn; R_RAX=(uintptr_t)fn(emu); } diff --git a/src/wrapped/generated/wrapper.h b/src/wrapped/generated/wrapper.h new file mode 100644 index 00000000..19ccf6b3 --- /dev/null +++ b/src/wrapped/generated/wrapper.h @@ -0,0 +1,50 @@ +/***************************************************************** + * File automatically generated by rebuild_wrappers.py (v1.2.0.09) + *****************************************************************/ +#ifndef __WRAPPER_H_ +#define __WRAPPER_H_ +#include <stdint.h> +#include <string.h> + +typedef struct x64emu_s x64emu_t; + +// the generic wrapper pointer functions +typedef void (*wrapper_t)(x64emu_t* emu, uintptr_t fnc); + +// list of defined wrapper +// v = void, i = int32, u = uint32, U/I= (u)int64 +// l = signed long, L = unsigned long (long is an int with the size of a pointer) +// p = pointer, P = callback +// f = float, d = double, D = long double, K = fake long double +// V = vaargs, E = current x86emu struct, e = ref to current x86emu struct +// 0 = constant 0, 1 = constant 1 +// o = stdout +// C = unsigned byte c = char +// W = unsigned short w = short +// O = libc O_ flags bitfield +// S = _IO_2_1_stdXXX_ pointer (or FILE*) +// Q = ... +// 2 = struct of 2 uint +// P = Vulkan struture pointer +// G = a single GValue pointer +// N = ... automatically sending 1 arg +// M = ... automatically sending 2 args + +void vFE(x64emu_t *emu, uintptr_t fnc); +void vFv(x64emu_t *emu, uintptr_t fnc); +void pFE(x64emu_t *emu, uintptr_t fnc); +void pFp(x64emu_t *emu, uintptr_t fnc); +void vFpp(x64emu_t *emu, uintptr_t fnc); +void iFEp(x64emu_t *emu, uintptr_t fnc); +void pFEp(x64emu_t *emu, uintptr_t fnc); +void iFEpp(x64emu_t *emu, uintptr_t fnc); +void pFEpi(x64emu_t *emu, uintptr_t fnc); +void pFEpp(x64emu_t *emu, uintptr_t fnc); +void iFEpip(x64emu_t *emu, uintptr_t fnc); +void pFEppi(x64emu_t *emu, uintptr_t fnc); +void pFEppp(x64emu_t *emu, uintptr_t fnc); +void iFipppi(x64emu_t *emu, uintptr_t fnc); + +void pFEv(x64emu_t *emu, uintptr_t fnc); + +#endif //__WRAPPER_H_ diff --git a/src/wrapped/wrappedldlinux.c b/src/wrapped/wrappedldlinux.c new file mode 100755 index 00000000..56b581a0 --- /dev/null +++ b/src/wrapped/wrappedldlinux.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <dlfcn.h> + +#include "wrappedlibs.h" + +#include "debug.h" +#include "wrapper.h" +#include "bridge.h" +#include "librarian/library_private.h" +#include "x64emu.h" +#include "emu/x64emu_private.h" +#include "elfloader.h" +#include "box64context.h" + +typedef struct my_tls_s { + int i; + uint32_t o; +} my_tls_t; + +EXPORT void* my___tls_get_addr(x64emu_t* emu, void* p) +{ + my_tls_t *t = (my_tls_t*)p; + return GetDTatOffset(emu->context, t->i, t->o); +} + +EXPORT void* my____tls_get_addr(x64emu_t* emu) +{ + // the GNU version (with 3 '_') use register for the parameter! + my_tls_t *t = (my_tls_t*)R_RAX; + return GetDTatOffset(emu->context, t->i, t->o); +} + + +const char* ldlinuxName = "ld-linux-x86-64.so.2"; +#define LIBNAME ldlinux + +// define all standard library functions +#include "wrappedlib_init.h" + diff --git a/src/wrapped/wrappedldlinux_private.h b/src/wrapped/wrappedldlinux_private.h new file mode 100755 index 00000000..1c829369 --- /dev/null +++ b/src/wrapped/wrappedldlinux_private.h @@ -0,0 +1,25 @@ +#if defined(GO) && defined(GOM) && defined(GO2) && defined(DATA) + +// _dl_allocate_tls +// _dl_allocate_tls_init +// _dl_argv //type B +// _dl_cache_libcmp +// _dl_deallocate_tls +// _dl_debug_state +// _dl_get_tls_static_info +// _dl_make_stack_executable +// _dl_mcount +// _dl_rtld_di_serinfo +// _dl_tls_setup +DATA(__libc_enable_secure, 4) +DATA(__libc_stack_end, 4) +DATA(__pointer_chk_guard, 4) +// _r_debug //type B +DATA(_rtld_global, 4) +DATA(_rtld_global_ro, 4) +DATA(__stack_chk_guard, 4) +// defini dans glibc/sysdeps/i386/dl-tls.h +GOM(___tls_get_addr, pFEv) //the parameter tls_index is in a register (EAX?) +GOM(__tls_get_addr, pFEp) //same, but the parameter is in the stack + +#endif \ No newline at end of file diff --git a/src/wrapped/wrappedlib_init.h b/src/wrapped/wrappedlib_init.h new file mode 100755 index 00000000..3f946286 --- /dev/null +++ b/src/wrapped/wrappedlib_init.h @@ -0,0 +1,239 @@ +#ifndef LIBNAME +#error Meh +#endif + +#define FUNC3(M,N) wrapped##M##N +#define FUNC2(M,N) FUNC3(M,N) +#define FUNC(N) FUNC2(LIBNAME,N) +#define QUOTE(M) #M +#define PRIVATE2(P) QUOTE(wrapped##P##_private.h) +#define PRIVATE(P) PRIVATE2(P) +#define MAPNAME3(N,M) N##M +#define MAPNAME2(N,M) MAPNAME3(N,M) +#define MAPNAME(N) MAPNAME2(LIBNAME,N) +// prepare the maps +#define GO(N, W) +#define GOW(N, W) +#define GOM(N, W) +#define GOS(N, W) +#define GO2(N, W, O) +#define DATA(N, S) +#define DATAV(N, S) +#define DATAB(N, S) +#define DATAM(N, S) + +// #define the 4 maps first +#undef GO +#define GO(N, W) {#N, W, 0}, +static const map_onesymbol_t MAPNAME(symbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GO +#define GO(N, W) +#undef GOW +#define GOW(N, W) {#N, W, 1}, +static const map_onesymbol_t MAPNAME(wsymbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GOW +#define GOW(N, W) +#undef GOM +#define GOM(N, W) {#N, W, 0}, +static const map_onesymbol_t MAPNAME(mysymbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GOM +#define GOM(N, W) +#undef GOS +#define GOS(N, W) {#N, W, 0}, +static const map_onesymbol_t MAPNAME(stsymbolmap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GOS +#define GOS(N, W) +#undef GO2 +#define GO2(N, W, O) {#N, W, 0, #O}, +static const map_onesymbol2_t MAPNAME(symbol2map)[] = { + #include PRIVATE(LIBNAME) +}; +#undef GO2 +#define GO2(N, W, O) +#undef DATA +#undef DATAV +#undef DATAB +#define DATA(N, S) {#N, S, 0}, +#define DATAV(N, S) {#N, S, 1}, +#define DATAB(N, S) {#N, S, 0}, +static const map_onedata_t MAPNAME(datamap)[] = { + #include PRIVATE(LIBNAME) +}; +#undef DATA +#undef DATAV +#undef DATAB +#define DATA(N, S) +#define DATAV(N, S) +#define DATAB(N, S) +#undef DATAM +#define DATAM(N, S) {#N, S, 0}, +static const map_onedata_t MAPNAME(mydatamap)[] = { + #include PRIVATE(LIBNAME) +}; +#include "wrappedlib_undefs.h" + + + +int FUNC(_init)(library_t* lib, box64context_t* box64) +{ +// Init first + free(lib->path); lib->path=NULL; +#ifdef PRE_INIT + PRE_INIT +#endif + { + lib->priv.w.lib = dlopen(MAPNAME(Name), RTLD_LAZY | RTLD_GLOBAL); + if(!lib->priv.w.lib) { +#ifdef ALTNAME + lib->priv.w.lib = dlopen(ALTNAME, RTLD_LAZY | RTLD_GLOBAL); + if(!lib->priv.w.lib) +#endif +#ifdef ALTNAME2 + { + lib->priv.w.lib = dlopen(ALTNAME2, RTLD_LAZY | RTLD_GLOBAL); + if(!lib->priv.w.lib) +#endif + return -1; +#ifdef ALTNAME2 + else lib->path = strdup(ALTNAME2); + } else lib->path = strdup(ALTNAME); +#endif + } else lib->path = strdup(MAPNAME(Name)); + } + lib->priv.w.bridge = NewBridge(); +// Create maps + lib->symbolmap = kh_init(symbolmap); + lib->wsymbolmap = kh_init(symbolmap); + lib->mysymbolmap = kh_init(symbolmap); + lib->stsymbolmap = kh_init(symbolmap); + lib->symbol2map = kh_init(symbol2map); + lib->datamap = kh_init(datamap); + lib->wdatamap = kh_init(datamap); + lib->mydatamap = kh_init(datamap); + + khint_t k; + int ret; + int cnt; + + // populates maps... + cnt = sizeof(MAPNAME(symbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->symbolmap, MAPNAME(symbolmap)[i].name, &ret); + kh_value(lib->symbolmap, k) = MAPNAME(symbolmap)[i].w; + } + cnt = sizeof(MAPNAME(wsymbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->wsymbolmap, MAPNAME(wsymbolmap)[i].name, &ret); + kh_value(lib->wsymbolmap, k) = MAPNAME(wsymbolmap)[i].w; + } + cnt = sizeof(MAPNAME(mysymbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->mysymbolmap, MAPNAME(mysymbolmap)[i].name, &ret); + kh_value(lib->mysymbolmap, k) = MAPNAME(mysymbolmap)[i].w; + } + cnt = sizeof(MAPNAME(stsymbolmap))/sizeof(map_onesymbol_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbolmap, lib->stsymbolmap, MAPNAME(stsymbolmap)[i].name, &ret); + kh_value(lib->stsymbolmap, k) = MAPNAME(stsymbolmap)[i].w; + } + cnt = sizeof(MAPNAME(symbol2map))/sizeof(map_onesymbol2_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(symbol2map, lib->symbol2map, MAPNAME(symbol2map)[i].name, &ret); + kh_value(lib->symbol2map, k).name = MAPNAME(symbol2map)[i].name2; + kh_value(lib->symbol2map, k).w = MAPNAME(symbol2map)[i].w; + kh_value(lib->symbol2map, k).weak = MAPNAME(symbol2map)[i].weak; + } + cnt = sizeof(MAPNAME(datamap))/sizeof(map_onedata_t); + for (int i=0; i<cnt; ++i) { + if(MAPNAME(datamap)[i].weak) { + k = kh_put(datamap, lib->wdatamap, MAPNAME(datamap)[i].name, &ret); + kh_value(lib->wdatamap, k) = MAPNAME(datamap)[i].sz; + } else { + k = kh_put(datamap, lib->datamap, MAPNAME(datamap)[i].name, &ret); + kh_value(lib->datamap, k) = MAPNAME(datamap)[i].sz; + } + } + cnt = sizeof(MAPNAME(mydatamap))/sizeof(map_onedata_t); + for (int i=0; i<cnt; ++i) { + k = kh_put(datamap, lib->mydatamap, MAPNAME(mydatamap)[i].name, &ret); + kh_value(lib->mydatamap, k) = MAPNAME(mydatamap)[i].sz; + } +#ifdef CUSTOM_INIT + CUSTOM_INIT +#endif + + return 0; +} + +int FUNC(_fini)(library_t* lib) +{ +#ifdef CUSTOM_FINI + CUSTOM_FINI +#endif + if(lib->priv.w.lib) + dlclose(lib->priv.w.lib); + lib->priv.w.lib = NULL; + if(lib->priv.w.altprefix) + free(lib->priv.w.altprefix); + if(lib->priv.w.neededlibs) { + for(int i=0; i<lib->priv.w.needed; ++i) + free(lib->priv.w.neededlibs[i]); + free(lib->priv.w.neededlibs); + } + FreeBridge(&lib->priv.w.bridge); + return 1; +} + +int FUNC(_get)(library_t* lib, const char* name, uintptr_t *offs, uint32_t *sz) +{ + uintptr_t addr = 0; + uint32_t size = 0; +#ifdef CUSTOM_FAIL + void* symbol = NULL; +#endif +//PRE + if (!getSymbolInMaps(lib, name, 0, &addr, &size)) { +#ifdef CUSTOM_FAIL + CUSTOM_FAIL +#else + return 0; +#endif + } +//POST + if(!addr && !size) + return 0; + *offs = addr; + *sz = size; + return 1; +} + +int FUNC(_getnoweak)(library_t* lib, const char* name, uintptr_t *offs, uint32_t *sz) +{ + uintptr_t addr = 0; + uint32_t size = 0; +#ifdef CUSTOM_FAIL + void* symbol = NULL; +#endif +//PRE + if (!getSymbolInMaps(lib, name, 1, &addr, &size)) { +#ifdef CUSTOM_FAIL + CUSTOM_FAIL +#else + return 0; +#endif + } +//POST + if(!addr && !size) + return 0; + *offs = addr; + *sz = size; + return 1; +} diff --git a/src/wrapped/wrappedlib_undefs.h b/src/wrapped/wrappedlib_undefs.h new file mode 100755 index 00000000..7c6ac84b --- /dev/null +++ b/src/wrapped/wrappedlib_undefs.h @@ -0,0 +1,23 @@ +// regular symbol mapped to itself +#undef GO + +// regular symbol mapped to itself, but weak (unimplemented for now) +#undef GOW + +// symbol mapped to my_symbol +#undef GOM + +// symbol mapped to another one +#undef GO2 + +// data +#undef DATA + +// data, Weak (type V) +#undef DATAV + +// data, Uninitialized (type B) +#undef DATAB + +// data, "my_" type +#undef DATAM diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c new file mode 100755 index 00000000..dce09009 --- /dev/null +++ b/src/wrapped/wrappedlibc.c @@ -0,0 +1,2590 @@ +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> +#include <wchar.h> +#include <dlfcn.h> +#include <signal.h> +#include <errno.h> +#include <err.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <unistd.h> +#include <fcntl.h> +#include <glob.h> +#include <ctype.h> +#include <dirent.h> +#include <search.h> +#include <sys/types.h> +#include <poll.h> +#include <sys/epoll.h> +#include <ftw.h> +#include <sys/syscall.h> +#include <sys/socket.h> +#include <sys/utsname.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <setjmp.h> +#include <sys/vfs.h> +#include <spawn.h> + +#include "wrappedlibs.h" + +#include "box64stack.h" +#include "x64emu.h" +#include "debug.h" +#include "wrapper.h" +#include "bridge.h" +//#include "callback.h" +#include "librarian.h" +#include "librarian/library_private.h" +#include "emu/x64emu_private.h" +#include "box64context.h" +//#include "myalign.h" +//#include "signals.h" +#include "fileutils.h" +#include "auxval.h" +#include "elfloader.h" +#include "bridge.h" + + +#define LIBNAME libc +const char* libcName = "libc.so.6"; + +static library_t* my_lib = NULL; + +typedef int (*iFL_t)(unsigned long); +typedef void (*vFpp_t)(void*, void*); +typedef void (*vFipp_t)(int32_t, void*, void*); +typedef int32_t (*iFpi_t)(void*, int32_t); +typedef int32_t (*iFpp_t)(void*, void*); +typedef int32_t (*iFpL_t)(void*, size_t); +typedef int32_t (*iFiip_t)(int32_t, int32_t, void*); +typedef int32_t (*iFipp_t)(int32_t, void*, void*); +typedef int32_t (*iFppi_t)(void*, void*, int32_t); +typedef int32_t (*iFpup_t)(void*, uint32_t, void*); +typedef int32_t (*iFpuu_t)(void*, uint32_t, uint32_t); +typedef int32_t (*iFiiII_t)(int, int, int64_t, int64_t); +typedef int32_t (*iFiiiV_t)(int, int, int, ...); +typedef int32_t (*iFippi_t)(int32_t, void*, void*, int32_t); +typedef int32_t (*iFpppp_t)(void*, void*, void*, void*); +typedef int32_t (*iFpipp_t)(void*, int32_t, void*, void*); +typedef int32_t (*iFppii_t)(void*, void*, int32_t, int32_t); +typedef int32_t (*iFipuu_t)(int32_t, void*, uint32_t, uint32_t); +typedef int32_t (*iFipiI_t)(int32_t, void*, int32_t, int64_t); +typedef int32_t (*iFipuup_t)(int32_t, void*, uint32_t, uint32_t, void*); +typedef int32_t (*iFiiV_t)(int32_t, int32_t, ...); +typedef void* (*pFp_t)(void*); + +#define SUPER() \ + GO(_ITM_addUserCommitAction, iFpup_t) \ + GO(_IO_file_stat, iFpp_t) + + +typedef struct libc_my_s { + #define GO(A, B) B A; + SUPER() + #undef GO +} libc_my_t; + +void* getLIBCMy(library_t* lib) +{ + libc_my_t* my = (libc_my_t*)calloc(1, sizeof(libc_my_t)); + #define GO(A, W) my->A = (W)dlsym(lib->priv.w.lib, #A); + SUPER() + #undef GO + return my; +} +#undef SUPER + +void freeLIBCMy(void* lib) +{ + // empty for now +} +#if 0 +// utility functions +#define SUPER() \ +GO(0) \ +GO(1) \ +GO(2) \ +GO(3) \ +GO(4) \ +GO(5) \ +GO(6) \ +GO(7) \ +GO(8) \ +GO(9) \ +GO(10) \ +GO(11) \ +GO(12) \ +GO(13) \ +GO(14) \ +GO(15) + +// compare +#define GO(A) \ +static uintptr_t my_compare_fct_##A = 0; \ +static int my_compare_##A(void* a, void* b) \ +{ \ + return (int)RunFunction(my_context, my_compare_fct_##A, 2, a, b);\ +} +SUPER() +#undef GO +static void* findcompareFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_compare_fct_##A == (uintptr_t)fct) return my_compare_##A; + SUPER() + #undef GO + #define GO(A) if(my_compare_fct_##A == 0) {my_compare_fct_##A = (uintptr_t)fct; return my_compare_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc compare callback\n"); + return NULL; +} + +// ftw +#define GO(A) \ +static uintptr_t my_ftw_fct_##A = 0; \ +static int my_ftw_##A(void* fpath, void* sb, int flag) \ +{ \ + return (int)RunFunction(my_context, my_ftw_fct_##A, 3, fpath, sb, flag); \ +} +SUPER() +#undef GO +static void* findftwFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_ftw_fct_##A == (uintptr_t)fct) return my_ftw_##A; + SUPER() + #undef GO + #define GO(A) if(my_ftw_fct_##A == 0) {my_ftw_fct_##A = (uintptr_t)fct; return my_ftw_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc ftw callback\n"); + return NULL; +} + +// ftw64 +#define GO(A) \ +static uintptr_t my_ftw64_fct_##A = 0; \ +static int my_ftw64_##A(void* fpath, void* sb, int flag) \ +{ \ + struct i386_stat64 i386st; \ + UnalignStat64(sb, &i386st); \ + return (int)RunFunction(my_context, my_ftw64_fct_##A, 3, fpath, &i386st, flag); \ +} +SUPER() +#undef GO +static void* findftw64Fct(void* fct) +{ + if(!fct) return NULL; + #define GO(A) if(my_ftw64_fct_##A == (uintptr_t)fct) return my_ftw64_##A; + SUPER() + #undef GO + #define GO(A) if(my_ftw64_fct_##A == 0) {my_ftw64_fct_##A = (uintptr_t)fct; return my_ftw64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc ftw64 callback\n"); + return NULL; +} + +// nftw +#define GO(A) \ +static uintptr_t my_nftw_fct_##A = 0; \ +static int my_nftw_##A(void* fpath, void* sb, int flag, void* ftwbuff) \ +{ \ + return (int)RunFunction(my_context, my_nftw_fct_##A, 4, fpath, sb, flag, ftwbuff); \ +} +SUPER() +#undef GO +static void* findnftwFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_nftw_fct_##A == (uintptr_t)fct) return my_nftw_##A; + SUPER() + #undef GO + #define GO(A) if(my_nftw_fct_##A == 0) {my_nftw_fct_##A = (uintptr_t)fct; return my_nftw_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc nftw callback\n"); + return NULL; +} + +// nftw64 +#define GO(A) \ +static uintptr_t my_nftw64_fct_##A = 0; \ +static int my_nftw64_##A(void* fpath, void* sb, int flag, void* ftwbuff) \ +{ \ + struct i386_stat64 i386st; \ + UnalignStat64(sb, &i386st); \ + return (int)RunFunction(my_context, my_nftw64_fct_##A, 4, fpath, &i386st, flag, ftwbuff); \ +} +SUPER() +#undef GO +static void* findnftw64Fct(void* fct) +{ + if(!fct) return NULL; + #define GO(A) if(my_nftw64_fct_##A == (uintptr_t)fct) return my_nftw64_##A; + SUPER() + #undef GO + #define GO(A) if(my_nftw64_fct_##A == 0) {my_nftw64_fct_##A = (uintptr_t)fct; return my_nftw64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc nftw64 callback\n"); + return NULL; +} + +// globerr +#define GO(A) \ +static uintptr_t my_globerr_fct_##A = 0; \ +static int my_globerr_##A(void* epath, int eerrno) \ +{ \ + return (int)RunFunction(my_context, my_globerr_fct_##A, 2, epath, eerrno); \ +} +SUPER() +#undef GO +static void* findgloberrFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_globerr_fct_##A == (uintptr_t)fct) return my_globerr_##A; + SUPER() + #undef GO + #define GO(A) if(my_globerr_fct_##A == 0) {my_globerr_fct_##A = (uintptr_t)fct; return my_globerr_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc globerr callback\n"); + return NULL; +} +#undef dirent +// filter_dir +#define GO(A) \ +static uintptr_t my_filter_dir_fct_##A = 0; \ +static int my_filter_dir_##A(const struct dirent* a) \ +{ \ + return (int)RunFunction(my_context, my_filter_dir_fct_##A, 1, a); \ +} +SUPER() +#undef GO +static void* findfilter_dirFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_filter_dir_fct_##A == (uintptr_t)fct) return my_filter_dir_##A; + SUPER() + #undef GO + #define GO(A) if(my_filter_dir_fct_##A == 0) {my_filter_dir_fct_##A = (uintptr_t)fct; return my_filter_dir_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc filter_dir callback\n"); + return NULL; +} +// compare_dir +#define GO(A) \ +static uintptr_t my_compare_dir_fct_##A = 0; \ +static int my_compare_dir_##A(const struct dirent* a, const struct dirent* b) \ +{ \ + return (int)RunFunction(my_context, my_compare_dir_fct_##A, 2, a, b); \ +} +SUPER() +#undef GO +static void* findcompare_dirFct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_compare_dir_fct_##A == (uintptr_t)fct) return my_compare_dir_##A; + SUPER() + #undef GO + #define GO(A) if(my_compare_dir_fct_##A == 0) {my_compare_dir_fct_##A = (uintptr_t)fct; return my_compare_dir_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc compare_dir callback\n"); + return NULL; +} + +// filter64 +#define GO(A) \ +static uintptr_t my_filter64_fct_##A = 0; \ +static int my_filter64_##A(const struct dirent64* a) \ +{ \ + return (int)RunFunction(my_context, my_filter64_fct_##A, 1, a); \ +} +SUPER() +#undef GO +static void* findfilter64Fct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_filter64_fct_##A == (uintptr_t)fct) return my_filter64_##A; + SUPER() + #undef GO + #define GO(A) if(my_filter64_fct_##A == 0) {my_filter64_fct_##A = (uintptr_t)fct; return my_filter64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc filter64 callback\n"); + return NULL; +} +// compare64 +#define GO(A) \ +static uintptr_t my_compare64_fct_##A = 0; \ +static int my_compare64_##A(const struct dirent64* a, const struct dirent64* b) \ +{ \ + return (int)RunFunction(my_context, my_compare64_fct_##A, 2, a, b); \ +} +SUPER() +#undef GO +static void* findcompare64Fct(void* fct) +{ + if(!fct) return NULL; + void* p; + if((p = GetNativeFnc((uintptr_t)fct))) return p; + #define GO(A) if(my_compare64_fct_##A == (uintptr_t)fct) return my_compare64_##A; + SUPER() + #undef GO + #define GO(A) if(my_compare64_fct_##A == 0) {my_compare64_fct_##A = (uintptr_t)fct; return my_compare64_##A; } + SUPER() + #undef GO + printf_log(LOG_NONE, "Warning, no more slot for libc compare64 callback\n"); + return NULL; +} + +#undef SUPER + +// some my_XXX declare and defines +int32_t my___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, char * *), + int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void (* stack_end)); // implemented in x86run_private.c +EXPORT void my___libc_init_first(x64emu_t* emu, int argc, char* arg0, char** b) +{ + // do nothing specific for now + return; +} +#endif +uint64_t my_syscall(x64emu_t *emu); // implemented in x86syscall.c +void EXPORT my___stack_chk_fail(x64emu_t* emu) +{ + char buff[200]; + #ifdef HAVE_TRACE + sprintf(buff, "%p: Stack is corrupted, aborting (prev IP=%p->%p)\n", (void*)emu->old_ip, (void*)emu->prev2_ip, (void*)emu->prev_ip); + #else + sprintf(buff, "%p: Stack is corrupted, aborting\n", (void*)emu->old_ip); + #endif + StopEmu(emu, buff); +} +void EXPORT my___gmon_start__(x64emu_t *emu) +{ + printf_log(LOG_DEBUG, "__gmon_start__ called (dummy call)\n"); +} +#if 0 +int EXPORT my___cxa_atexit(x64emu_t* emu, void* p, void* a, void* d) +{ + AddCleanup1Arg(emu, p, a); + return 0; +} +void EXPORT my___cxa_finalize(x64emu_t* emu, void* p) +{ + if(!p) { + // p is null, call (and remove) all Cleanup functions + CallAllCleanup(emu); + return; + } + CallCleanup(emu, p); +} +int EXPORT my_atexit(x64emu_t* emu, void *p) +{ + AddCleanup(emu, p); + return 0; +} + +int my_getcontext(x64emu_t* emu, void* ucp); +int my_setcontext(x64emu_t* emu, void* ucp); +int my_makecontext(x64emu_t* emu, void* ucp, void* fnc, int32_t argc, void* argv); +int my_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2); + +// All signal and context functions defined in signals.c + +// All fts function defined in myfts.c + +// getauxval implemented in auxval.c + + +// this one is defined in elfloader.c +int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data); + + +pid_t EXPORT my_fork(x64emu_t* emu) +{ + // execute atforks prepare functions, in reverse order + for (int i=my_context->atfork_sz-1; i>=0; --i) + if(my_context->atforks[i].prepare) + RunFunctionWithEmu(emu, 0, my_context->atforks[i].prepare, 0); + int type = emu->type; + pid_t v; + v = fork(); + if(type == EMUTYPE_MAIN) + thread_set_emu(emu); + if(v<0) { + printf_log(LOG_NONE, "BOX86: Warning, fork errored... (%d)\n", v); + // error... + } else if(v>0) { + // execute atforks parent functions + for (int i=0; i<my_context->atfork_sz; --i) + if(my_context->atforks[i].parent) + RunFunctionWithEmu(emu, 0, my_context->atforks[i].parent, 0); + + } else /*if(v==0)*/ { + // execute atforks child functions + for (int i=0; i<my_context->atfork_sz; --i) + if(my_context->atforks[i].child) + RunFunctionWithEmu(emu, 0, my_context->atforks[i].child, 0); + } + return v; +} +pid_t EXPORT my___fork(x64emu_t* emu) __attribute__((alias("my_fork"))); +pid_t EXPORT my_vfork(x64emu_t* emu) +{ + #if 1 + emu->quit = 1; + emu->fork = 1; // use regular fork... + return 0; + #else + return 0; + #endif +} + +int EXPORT my_uname(struct utsname *buf) +{ + // sizeof(struct utsname)==390 on i686, and also on ARM, so this seem safe + int ret = uname(buf); + strcpy(buf->machine, /*(box64_steam)?"x86_64":*/"i686"); + return ret; +} + +// X86_O_RDONLY 0x00 +#define X86_O_WRONLY 0x01 // octal 01 +#define X86_O_RDWR 0x02 // octal 02 +#define X86_O_CREAT 0x40 // octal 0100 +#define X86_O_EXCL 0x80 // octal 0200 +#define X86_O_NOCTTY 0x100 // octal 0400 +#define X86_O_TRUNC 0x200 // octal 01000 +#define X86_O_APPEND 0x400 // octal 02000 +#define X86_O_NONBLOCK 0x800 // octal 04000 +#define X86_O_SYNC 0x101000 // octal 04010000 +#define X86_O_DSYNC 0x1000 // octal 010000 +#define X86_O_RSYNC O_SYNC +#define X86_FASYNC 020000 +#define X86_O_DIRECT 040000 +#define X86_O_LARGEFILE 0100000 +#define X86_O_DIRECTORY 0200000 +#define X86_O_NOFOLLOW 0400000 +#define X86_O_NOATIME 01000000 +#define X86_O_CLOEXEC 02000000 +#define X86_O_TMPFILE 020200000 + +#ifndef O_TMPFILE +#define O_TMPFILE (020000000 | O_DIRECTORY) +#endif + +#define SUPER() \ + GO(O_WRONLY) \ + GO(O_RDWR) \ + GO(O_CREAT) \ + GO(O_EXCL) \ + GO(O_NOCTTY) \ + GO(O_TRUNC) \ + GO(O_APPEND) \ + GO(O_NONBLOCK) \ + GO(O_SYNC) \ + GO(O_DSYNC) \ + GO(O_RSYNC) \ + GO(FASYNC) \ + GO(O_DIRECT) \ + GO(O_LARGEFILE) \ + GO(O_TMPFILE) \ + GO(O_DIRECTORY) \ + GO(O_NOFOLLOW) \ + GO(O_NOATIME) \ + GO(O_CLOEXEC) \ + +// x86->arm +int of_convert(int a) +{ + if(!a || a==-1) return a; + int b=0; + #define GO(A) if((a&X86_##A)==X86_##A) {a&=~X86_##A; b|=A;} + SUPER(); + #undef GO + if(a) { + printf_log(LOG_NONE, "Warning, of_convert(...) left over 0x%x, converted 0x%x\n", a, b); + } + return a|b; +} + +// arm->x86 +int of_unconvert(int a) +{ + if(!a || a==-1) return a; + int b=0; + #define GO(A) if((a&A)==A) {a&=~A; b|=X86_##A;} + SUPER(); + #undef GO + if(a) { + printf_log(LOG_NONE, "Warning, of_unconvert(...) left over 0x%x, converted 0x%x\n", a, b); + } + return a|b; +} +#undef SUPER + + +EXPORT void* my__ZGTtnaX (size_t a) { printf("warning _ZGTtnaX called\n"); return NULL; } +EXPORT void my__ZGTtdlPv (void* a) { printf("warning _ZGTtdlPv called\n"); } +EXPORT uint8_t my__ITM_RU1(const uint8_t * a) { printf("warning _ITM_RU1 called\n"); return 0; } +EXPORT uint32_t my__ITM_RU4(const uint32_t * a) { printf("warning _ITM_RU4 called\n"); return 0; } +EXPORT uint64_t my__ITM_RU8(const uint64_t * a) { printf("warning _ITM_RU8 called\n"); return 0; } +EXPORT void my__ITM_memcpyRtWn(void * a, const void * b, size_t c) {printf("warning _ITM_memcpyRtWn called\n"); } +EXPORT void my__ITM_memcpyRnWt(void * a, const void * b, size_t c) {printf("warning _ITM_memcpyRtWn called\n"); } + +EXPORT void my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val); +EXPORT void my__longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); +EXPORT void my_siglongjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); +EXPORT void my___longjmp_chk(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) __attribute__((alias("my_longjmp"))); + +EXPORT int32_t my_setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p); +EXPORT int32_t my__setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) __attribute__((alias("my_setjmp"))); +EXPORT int32_t my___sigsetjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) __attribute__((alias("my_setjmp"))); +#if 0 +EXPORT void my_exit(x64emu_t *emu, int32_t status) +{ + R_EAX = (uint32_t)status; + emu->quit = 1; +} +EXPORT void my__exit(x64emu_t *emu, int32_t status) __attribute__((alias("my_exit"))); +EXPORT void my__Exit(x64emu_t *emu, int32_t status) __attribute__((alias("my_exit"))); +#endif +void myStackAlign(const char* fmt, uint32_t* st, uint32_t* mystack); // align st into mystack according to fmt (for v(f)printf(...)) +typedef int (*iFpp_t)(void*, void*); +typedef int (*iFppp_t)(void*, void*, void*); +typedef int (*iFpupp_t)(void*, uint32_t, void*, void*); +EXPORT int my_printf(x64emu_t *emu, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + return vprintf((const char*)fmt, V); + #endif +} +EXPORT int my___printf_chk(x64emu_t *emu, void* fmt, void* b, va_list V) __attribute__((alias("my_printf"))); + +EXPORT int my_vprintf(x64emu_t *emu, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + void* f = vprintf; + return ((iFpp_t)f)(fmt, (uint32_t*)b); + #endif +} +EXPORT int my___vprintf_chk(x64emu_t *emu, void* fmt, void* b, va_list V) __attribute__((alias("my_vprintf"))); + +EXPORT int my_vfprintf(x64emu_t *emu, void* F, void* fmt, void* b) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vfprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + // other platform don't need that + void* f = vfprintf; + return ((iFppp_t)f)(F, fmt, (uint32_t*)b); + #endif +} +EXPORT int my___vfprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b) __attribute__((alias("my_vfprintf"))); +EXPORT int my__IO_vfprintf(x64emu_t *emu, void* F, void* fmt, void* b) __attribute__((alias("my_vfprintf"))); + +EXPORT int my_fprintf(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vfprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + // other platform don't need that + return vfprintf((FILE*)F, (const char*)fmt, V); + #endif +} +EXPORT int my___fprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) __attribute__((alias("my_fprintf"))); + +EXPORT int my_wprintf(x64emu_t *emu, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vwprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + return vwprintf((const wchar_t*)fmt, V); + #endif +} +EXPORT int my___wprintf_chk(x64emu_t *emu, int flag, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vwprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + // other platform don't need that + return vwprintf((const wchar_t*)fmt, V); + #endif +} +EXPORT int my_fwprintf(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vfwprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + // other platform don't need that + return vfwprintf((FILE*)F, (const wchar_t*)fmt, V); + #endif +} +EXPORT int my___fwprintf_chk(x64emu_t *emu, void* F, void* fmt, void* b, va_list V) __attribute__((alias("my_fwprintf"))); + +EXPORT int my_vfwprintf(x64emu_t *emu, void* F, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vfwprintf; + return ((iFppp_t)f)(F, fmt, VARARGS); + #else + void* f = vfwprintf; + return ((iFppp_t)f)(F, fmt, b); + #endif +} + +EXPORT int my_vwprintf(x64emu_t *emu, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vwprintf; + return ((iFpp_t)f)(fmt, VARARGS); + #else + void* f = vwprintf; + return ((iFpp_t)f)(fmt, b); + #endif +} + +EXPORT void *my_div(void *result, int numerator, int denominator) { + *(div_t *)result = div(numerator, denominator); + return result; +} + +EXPORT int my_snprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vsnprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, VARARGS); + return r; + #else + return vsnprintf((char*)buff, s, (char*)fmt, V); + #endif +} +EXPORT int my___snprintf_chk(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_snprintf"))); +EXPORT int my___snprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_snprintf"))); + +EXPORT int my_sprintf(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vsprintf; + return ((iFppp_t)f)(buff, fmt, VARARGS); + #else + return vsprintf((char*)buff, (char*)fmt, V); + #endif +} +EXPORT int my___sprintf_chk(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) __attribute__((alias("my_sprintf"))); + +EXPORT int my_asprintf(x64emu_t* emu, void** buff, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + return ((iFppp_t)f)(buff, fmt, VARARGS); + #else + return vasprintf((char**)buff, (char*)fmt, V); + #endif +} +EXPORT int my___asprintf(x64emu_t* emu, void** buff, void * fmt, void * b, va_list V) __attribute__((alias("my_asprintf"))); + + +EXPORT int my_vsprintf(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vsprintf; + int r = ((iFppp_t)f)(buff, fmt, VARARGS); + return r; + #else + void* f = vsprintf; + int r = ((iFppp_t)f)(buff, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vsprintf_chk(x64emu_t* emu, void* buff, void * fmt, void * b, va_list V) __attribute__((alias("my_vsprintf"))); + +#ifdef POWERPCLE +EXPORT int my_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) // probably uneeded to do a GOM, a simple wrap should enough +{ + //myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST_(b); + void* f = vfscanf; + + return ((iFppp_t)f)(stream, fmt, VARARGS_(b)); +} + + + +EXPORT int my_vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) +{ + //myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST_(b); + void* f = vsscanf; + + return ((iFppp_t)f)(stream, fmt, VARARGS_(b)); +} + +EXPORT int my__vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); +EXPORT int my_sscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); + +EXPORT int my__IO_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); +EXPORT int my___isoc99_vsscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vsscanf"))); + +EXPORT int my___isoc99_vfscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); +EXPORT int my___isoc99_fscanf(x64emu_t* emu, void* stream, void* fmt, void* b) __attribute__((alias("my_vfscanf"))); + +EXPORT int my___isoc99_sscanf(x64emu_t* emu, void* stream, void* fmt, void* b) +{ + void* f = sscanf; + PREPARE_VALIST; + + return ((iFppp_t)f)(stream, fmt, VARARGS); +} +#endif + +EXPORT int my_vsnprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vsnprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, VARARGS); + return r; + #else + void* f = vsnprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vsnprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vsnprintf"))); +EXPORT int my___vsnprintf_chk(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vsnprintf"))); + +EXPORT int my_vasprintf(x64emu_t* emu, void* strp, void* fmt, void* b, va_list V) +{ + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, VARARGS); + return r; + #else + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vasprintf_chk(x64emu_t* emu, void* strp, int flags, void* fmt, void* b, va_list V) +{ + #ifndef NOALIGN + // need to align on arm + myStackAlign((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, VARARGS); + return r; + #else + void* f = vasprintf; + int r = ((iFppp_t)f)(strp, fmt, (uint32_t*)b); + return r; + #endif +} + +EXPORT int my___asprintf_chk(x64emu_t* emu, void* result_ptr, int flags, void* fmt, void* b, va_list V) +{ + #ifndef NOALIGN + myStackAlign((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vasprintf; + return ((iFppp_t)f)(result_ptr, fmt, VARARGS); + #else + return vasprintf((char**)result_ptr, (char*)fmt, V); + #endif +} + +EXPORT int my_vswprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) { + #ifndef NOALIGN + // need to align on arm + myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vswprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, VARARGS); + return r; + #else + void* f = vswprintf; + int r = ((iFpupp_t)f)(buff, s, fmt, (uint32_t*)b); + return r; + #endif +} +EXPORT int my___vswprintf(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vswprintf"))); +EXPORT int my___vswprintf_chk(x64emu_t* emu, void* buff, uint32_t s, void * fmt, void * b, va_list V) __attribute__((alias("my_vswprintf"))); + +EXPORT void my_verr(x64emu_t* emu, int eval, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = verr; + ((vFipp_t)f)(eval, fmt, VARARGS); + #else + void* f = verr; + ((vFipp_t)f)(eval, fmt, (uint32_t*)b); + #endif +} + +EXPORT void my_vwarn(x64emu_t* emu, void* fmt, void* b) { + #ifndef NOALIGN + myStackAlignW((const char*)fmt, (uint32_t*)b, emu->scratch); + PREPARE_VALIST; + void* f = vwarn; + ((vFpp_t)f)(fmt, VARARGS); + #else + void* f = vwarn; + ((vFpp_t)f)(fmt, (uint32_t*)b); + #endif +} + +EXPORT int my___swprintf_chk(x64emu_t* emu, void* s, uint32_t n, int32_t flag, uint32_t slen, void* fmt, void * b) +{ + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, VARARGS); + return r; + #else + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, b); + return r; + #endif +} +EXPORT int my_swprintf(x64emu_t* emu, void* s, uint32_t n, void* fmt, void *b) +{ + #ifndef NOALIGN + myStackAlignW((const char*)fmt, b, emu->scratch); + PREPARE_VALIST; + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, VARARGS); + return r; + #else + void* f = vswprintf; + int r = ((iFpupp_t)f)(s, n, fmt, b); + return r; + #endif +} + +EXPORT void my__ITM_addUserCommitAction(x64emu_t* emu, void* cb, uint32_t b, void* c) +{ + // disabled for now... Are all this _ITM_ stuff really mendatory? + #if 0 + // quick and dirty... Should store the callback to be removed later.... + libc_my_t *my = (libc_my_t *)emu->context->libclib->priv.w.p2; + x64emu_t *cbemu = AddCallback(emu, (uintptr_t)cb, 1, c, NULL, NULL, NULL); + my->_ITM_addUserCommitAction(libc1ArgCallback, b, cbemu); + // should keep track of cbemu to remove at some point... + #else + printf("warning _ITM_addUserCommitAction called\n"); + #endif +} +EXPORT void my__ITM_registerTMCloneTable(x64emu_t* emu, void* p, uint32_t s) {} +EXPORT void my__ITM_deregisterTMCloneTable(x64emu_t* emu, void* p) {} + + +struct i386_stat { + uint64_t st_dev; + uint32_t __pad1; + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + uint32_t __pad2; + int32_t st_size; + int32_t st_blksize; + int32_t st_blocks; + int32_t st_atime_sec; + uint32_t st_atime_nsec; + int32_t st_mtime_sec; + uint32_t st_mtime_nsec; + int32_t st_ctime_sec; + uint32_t st_ctime_nsec; + uint32_t __unused4; + uint32_t __unused5; +} __attribute__((packed)); + +static int FillStatFromStat64(int vers, const struct stat64 *st64, void *st32) +{ + struct i386_stat *i386st = (struct i386_stat *)st32; + + if (vers != 3) + { + errno = EINVAL; + return -1; + } + + i386st->st_dev = st64->st_dev; + i386st->__pad1 = 0; + if (fix_64bit_inodes) + { + i386st->st_ino = st64->st_ino ^ (st64->st_ino >> 32); + } + else + { + i386st->st_ino = st64->st_ino; + if ((st64->st_ino >> 32) != 0) + { + errno = EOVERFLOW; + return -1; + } + } + i386st->st_mode = st64->st_mode; + i386st->st_nlink = st64->st_nlink; + i386st->st_uid = st64->st_uid; + i386st->st_gid = st64->st_gid; + i386st->st_rdev = st64->st_rdev; + i386st->__pad2 = 0; + i386st->st_size = st64->st_size; + if ((i386st->st_size >> 31) != (int32_t)(st64->st_size >> 32)) + { + errno = EOVERFLOW; + return -1; + } + i386st->st_blksize = st64->st_blksize; + i386st->st_blocks = st64->st_blocks; + if ((i386st->st_blocks >> 31) != (int32_t)(st64->st_blocks >> 32)) + { + errno = EOVERFLOW; + return -1; + } + i386st->st_atime_sec = st64->st_atim.tv_sec; + i386st->st_atime_nsec = st64->st_atim.tv_nsec; + i386st->st_mtime_sec = st64->st_mtim.tv_sec; + i386st->st_mtime_nsec = st64->st_mtim.tv_nsec; + i386st->st_ctime_sec = st64->st_ctim.tv_sec; + i386st->st_ctime_nsec = st64->st_ctim.tv_nsec; + i386st->__unused4 = 0; + i386st->__unused5 = 0; + return 0; +} + +EXPORT int my___fxstat(x64emu_t *emu, int vers, int fd, void* buf) +{ + if (vers == 1) + { + static iFiip_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + errno = EINVAL; + return -1; + } + f = (iFiip_t)dlsym(lib->priv.w.lib, "__fxstat"); + } + + return f(vers, fd, buf); + } + struct stat64 st; + int r = fstat64(fd, &st); + if (r) return r; + r = FillStatFromStat64(vers, &st, buf); + return r; +} + +EXPORT int my___fxstat64(x64emu_t *emu, int vers, int fd, void* buf) +{ + struct stat64 st; + int r = fstat64(fd, &st); + //int r = syscall(__NR_stat64, fd, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my___xstat(x64emu_t* emu, int v, void* path, void* buf) +{ + if (v == 1) + { + static iFipp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + errno = EINVAL; + return -1; + } + f = (iFipp_t)dlsym(lib->priv.w.lib, "__xstat"); + } + + return f(v, path, buf); + } + struct stat64 st; + int r = stat64((const char*)path, &st); + if (r) return r; + r = FillStatFromStat64(v, &st, buf); + return r; +} + +EXPORT int my___xstat64(x64emu_t* emu, int v, void* path, void* buf) +{ + struct stat64 st; + int r = stat64((const char*)path, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my___lxstat(x64emu_t* emu, int v, void* name, void* buf) +{ + if (v == 1) + { + static iFipp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + errno = EINVAL; + return -1; + } + f = (iFipp_t)dlsym(lib->priv.w.lib, "__lxstat"); + } + + return f(v, name, buf); + } + struct stat64 st; + int r = lstat64((const char*)name, &st); + if (r) return r; + r = FillStatFromStat64(v, &st, buf); + return r; +} + +EXPORT int my___lxstat64(x64emu_t* emu, int v, void* name, void* buf) +{ + struct stat64 st; + int r = lstat64((const char*)name, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my___fxstatat(x64emu_t* emu, int v, int d, void* path, void* buf, int flags) +{ + struct stat64 st; + int r = fstatat64(d, path, &st, flags); + if (r) return r; + r = FillStatFromStat64(v, &st, buf); + return r; +} + +EXPORT int my___fxstatat64(x64emu_t* emu, int v, int d, void* path, void* buf, int flags) +{ + struct stat64 st; + int r = fstatat64(d, path, &st, flags); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my__IO_file_stat(x64emu_t* emu, void* f, void* buf) +{ + struct stat64 st; + libc_my_t *my = (libc_my_t *)emu->context->libclib->priv.w.p2; + int r = my->_IO_file_stat(f, &st); + UnalignStat64(&st, buf); + return r; +} + +EXPORT int my_fstatfs64(int fd, void* buf) +{ + struct statfs64 st; + int r = fstatfs64(fd, &st); + UnalignStatFS64(&st, buf); + return r; +} + +EXPORT int my_statfs64(const char* path, void* buf) +{ + struct statfs64 st; + int r = statfs64(path, &st); + UnalignStatFS64(&st, buf); + return r; +} + + +typedef struct compare_r_s { + x64emu_t* emu; + uintptr_t f; + void* data; + int r; +} compare_r_t; + +static int my_compare_r_cb(void* a, void* b, compare_r_t* arg) +{ + return (int)RunFunctionWithEmu(arg->emu, 0, arg->f, 2+arg->r, a, b, arg->data); +} +EXPORT void my_qsort(x64emu_t* emu, void* base, size_t nmemb, size_t size, void* fnc) +{ + compare_r_t args; + args.emu = emu; args.f = (uintptr_t)fnc; args.r = 0; args.data = NULL; + qsort_r(base, nmemb, size, (__compar_d_fn_t)my_compare_r_cb, &args); +} +EXPORT void my_qsort_r(x64emu_t* emu, void* base, size_t nmemb, size_t size, void* fnc, void* data) +{ + compare_r_t args; + args.emu = emu; args.f = (uintptr_t)fnc; args.r = 1; args.data = data; + qsort_r(base, nmemb, size, (__compar_d_fn_t)my_compare_r_cb, &args); +} + +EXPORT void* my_bsearch(x64emu_t* emu, void* key, void* base, size_t nmemb, size_t size, void* fnc) +{ + return bsearch(key, base, nmemb, size, findcompareFct(fnc)); +} + +EXPORT void* my_lsearch(x64emu_t* emu, void* key, void* base, size_t* nmemb, size_t size, void* fnc) +{ + return lsearch(key, base, nmemb, size, findcompareFct(fnc)); +} +EXPORT void* my_lfind(x64emu_t* emu, void* key, void* base, size_t* nmemb, size_t size, void* fnc) +{ + return lfind(key, base, nmemb, size, findcompareFct(fnc)); +} + + +struct i386_dirent { + uint32_t d_ino; + int32_t d_off; + uint16_t d_reclen; + uint8_t d_type; + char d_name[256]; +}; + +EXPORT void* my_readdir(x64emu_t* emu, void* dirp) +{ + if (fix_64bit_inodes) + { + struct dirent64 *dp64 = readdir64((DIR *)dirp); + if (!dp64) return NULL; + uint32_t ino32 = dp64->d_ino ^ (dp64->d_ino >> 32); + int32_t off32 = dp64->d_off; + struct i386_dirent *dp32 = (struct i386_dirent *)&(dp64->d_off); + dp32->d_ino = ino32; + dp32->d_off = off32; + dp32->d_reclen -= 8; + return dp32; + } + else + { + static pFp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return NULL; + f = (pFp_t)dlsym(lib->priv.w.lib, "readdir"); + } + + return f(dirp); + } +} + +EXPORT int32_t my_readdir_r(x64emu_t* emu, void* dirp, void* entry, void** result) +{ + struct dirent64 d64, *dp64; + if (fix_64bit_inodes && (sizeof(d64.d_name) > 1)) + { + static iFppp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + *result = NULL; + return 0; + } + f = (iFppp_t)dlsym(lib->priv.w.lib, "readdir64_r"); + } + + int r = f(dirp, &d64, &dp64); + if (r || !dp64 || !entry) + { + *result = NULL; + return r; + } + + struct i386_dirent *dp32 = (struct i386_dirent *)entry; + int namelen = dp64->d_reclen - offsetof(struct dirent64, d_name); + if (namelen > sizeof(dp32->d_name)) + { + *result = NULL; + return ENAMETOOLONG; + } + + dp32->d_ino = dp64->d_ino ^ (dp64->d_ino >> 32); + dp32->d_off = dp64->d_off; + dp32->d_reclen = namelen + offsetof(struct i386_dirent, d_name); + dp32->d_type = dp64->d_type; + memcpy(dp32->d_name, dp64->d_name, namelen); + *result = dp32; + return 0; + } + else + { + static iFppp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) + { + *result = NULL; + return 0; + } + f = (iFppp_t)dlsym(lib->priv.w.lib, "readdir_r"); + } + + return f(dirp, entry, result); + } +} + +static int isProcSelf(const char *path, const char* w) +{ + if(strncmp(path, "/proc/", 6)==0) { + char tmp[64]; + // check if self .... + sprintf(tmp, "/proc/self/%s", w); + if(strcmp((const char*)path, tmp)==0) + return 1; + // check if self PID .... + pid_t pid = getpid(); + sprintf(tmp, "/proc/%d/%s", pid, w); + if(strcmp((const char*)path, tmp)==0) + return 1; + } + return 0; +} + +EXPORT int32_t my_readlink(x64emu_t* emu, void* path, void* buf, uint32_t sz) +{ + if(isProcSelf((const char*)path, "exe")) { + // special case for self... + return strlen(strncpy((char*)buf, emu->context->fullpath, sz)); + } + return readlink((const char*)path, (char*)buf, sz); +} +#ifndef NOALIGN + +static int nCPU = 0; +static double bogoMips = 100.; + +void grabNCpu() { + nCPU = 1; // default number of CPU to 1 + FILE *f = fopen("/proc/cpuinfo", "r"); + size_t dummy; + if(f) { + nCPU = 0; + size_t len = 0; + char* line = NULL; + while ((dummy = getline(&line, &len, f)) != -1) { + if(!strncmp(line, "processor\t", strlen("processor\t"))) + ++nCPU; + if(!nCPU && !strncmp(line, "BogoMIPS\t", strlen("BogoMIPS\t"))) { + // grab 1st BogoMIPS + float tmp; + if(sscanf(line, "BogoMIPS\t: %g", &tmp)==1) + bogoMips = tmp; + } + } + if(line) free(line); + fclose(f); + if(!nCPU) nCPU=1; + } +} +void CreateCPUInfoFile(int fd) +{ + size_t dummy; + char buff[600]; + double freq = 600.0; // default to 600 MHz + // try to get actual ARM max speed: + FILE *f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r"); + if(f) { + int r; + if(1==fscanf(f, "%d", &r)) + freq = r/1000.; + fclose(f); + } + if(!nCPU) + grabNCpu(); + int n = nCPU; + // generate fake CPUINFO + int gigahertz=(freq>=1000.); + #define P \ + dummy = write(fd, buff, strlen(buff)) + for (int i=0; i<n; ++i) { + sprintf(buff, "processor\t: %d\n", i); + P; + sprintf(buff, "vendor_id\t: GenuineIntel\n"); + P; + sprintf(buff, "cpu family\t: 6\n"); + P; + sprintf(buff, "model\t\t: 1\n"); + P; + sprintf(buff, "model name\t: Intel Pentium IV @ %g%cHz\n", gigahertz?(freq/1000.):freq, gigahertz?'G':'M'); + P; + sprintf(buff, "stepping\t: 1\nmicrocode\t: 0x10\n"); + P; + sprintf(buff, "cpu MHz\t\t: %g\n", freq); + P; + sprintf(buff, "cache size\t: %d\n", 4096); + P; + sprintf(buff, "physical id\t: %d\nsiblings\t: %d\n", i, n); + P; + sprintf(buff, "core id\t\t:%d\ncpu cores\t: %d\n", i, 1); + P; + sprintf(buff, "bogomips\t: %g\n", bogoMips); + P; + sprintf(buff, "flags\t\t: fpu cx8 sep cmov clflush mmx sse sse2 rdtscp ssse3 fma fxsr cx16 movbe pni\n"); + P; + sprintf(buff, "\n"); + P; + } + (void)dummy; + #undef P +} +static int isCpuTopology(const char* p) { + if(strstr(p, "/sys/devices/system/cpu/cpu")!=p) + return -1; //nope + if( FileExist(p, -1)) + return -1; //no need to fake it + char buf[512]; + const char* p2 = p + strlen("/sys/devices/system/cpu/cpu"); + int n = 0; + while(*p2>='0' && *p2<='9') { + n = n*10+ *p2 - '0'; + ++p2; + } + if(!nCPU) + grabNCpu(); + if(n>=nCPU) // filter for non existing cpu + return -1; + snprintf(buf, 512, "/sys/devices/system/cpu/cpu%d/topology/core_id", n); + if(!strcmp(p, buf)) + return n; + return -1; +} +static void CreateCPUTopologyCoreID(int fd, int cpu) +{ + char buf[512]; + snprintf(buf, 512, "%d\n", cpu); + size_t dummy = write(fd, buf, strlen(buf)); + (void)dummy; +} + + +#define TMP_CPUINFO "box64_tmpcpuinfo" +#define TMP_CPUTOPO "box64_tmpcputopo%d" +#endif +#define TMP_MEMMAP "box64_tmpmemmap" +#define TMP_CMDLINE "box64_tmpcmdline" +EXPORT int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) +{ + if(isProcSelf((const char*) pathname, "cmdline")) { + // special case for self command line... + #if 0 + char tmpcmdline[200] = {0}; + char tmpbuff[100] = {0}; + sprintf(tmpbuff, "%s/cmdlineXXXXXX", getenv("TMP")?getenv("TMP"):"."); + int tmp = mkstemp(tmpbuff); + int dummy; + if(tmp<0) return open(pathname, flags, mode); + dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek(tmp, 0, SEEK_SET); + #else + int tmp = shm_open(TMP_CMDLINE, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open(pathname, flags, mode); + shm_unlink(TMP_CMDLINE); // remove the shm file, but it will still exist because it's currently in use + int dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + (void)dummy; + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek(tmp, 0, SEEK_SET); + #endif + return tmp; + } + if(isProcSelf((const char*)pathname, "exe")) { + return open(emu->context->fullpath, flags, mode); + } + #ifndef NOALIGN + if(strcmp((const char*)pathname, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open(pathname, flags, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + if(isCpuTopology((const char*)pathname)!=-1) { + int n = isCpuTopology((const char*)pathname); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open(pathname, flags, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + #endif + int ret = open(pathname, flags, mode); + return ret; +} +EXPORT int32_t my___open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) __attribute__((alias("my_open"))); + +#ifdef DYNAREC +static int hasDBFromAddress(uintptr_t addr) +{ + int idx = (addr>>DYNAMAP_SHIFT); + return getDB(idx)?1:0; +} +#endif + +EXPORT int32_t my_read(int fd, void* buf, uint32_t count) +{ + int ret = read(fd, buf, count); +#ifdef DYNAREC + if(ret!=count && ret>0) { + // continue reading... + void* p = buf+ret; + if(hasDBFromAddress((uintptr_t)p)) { + // allow writing the whole block (this happens with HalfLife, libMiles load code directly from .mix and other file like that) + unprotectDB((uintptr_t)p, count-ret); + int l; + do { + l = read(fd, p, count-ret); + if(l>0) { + p+=l; ret+=l; + } + } while(l>0); + } + } +#endif + return ret; +} + +EXPORT int32_t my_open64(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode) +{ + if(isProcSelf((const char*)pathname, "cmdline")) { + // special case for self command line... + #if 0 + char tmpcmdline[200] = {0}; + char tmpbuff[100] = {0}; + sprintf(tmpbuff, "%s/cmdlineXXXXXX", getenv("TMP")?getenv("TMP"):"."); + int tmp = mkstemp64(tmpbuff); + int dummy; + if(tmp<0) return open64(pathname, flags, mode); + dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek64(tmp, 0, SEEK_SET); + #else + int tmp = shm_open(TMP_CMDLINE, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open64(pathname, flags, mode); + shm_unlink(TMP_CMDLINE); // remove the shm file, but it will still exist because it's currently in use + int dummy = write(tmp, emu->context->fullpath, strlen(emu->context->fullpath)+1); + (void)dummy; + for (int i=1; i<emu->context->argc; ++i) + dummy = write(tmp, emu->context->argv[i], strlen(emu->context->argv[i])+1); + lseek(tmp, 0, SEEK_SET); + #endif + return tmp; + } + if(isProcSelf((const char*)pathname, "exe")) { + return open64(emu->context->fullpath, flags, mode); + } + #ifndef NOALIGN + if(strcmp((const char*)pathname, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open64(pathname, flags, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + if(isCpuTopology((const char*)pathname)!=-1) { + int n = isCpuTopology((const char*)pathname); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return open64(pathname, flags, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return tmp; + } + #endif + return open64(pathname, flags, mode); +} + +EXPORT FILE* my_fopen(x64emu_t* emu, const char* path, const char* mode) +{ + if(isProcSelf(path, "maps")) { + // special case for self memory map + int tmp = shm_open(TMP_MEMMAP, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(TMP_MEMMAP); // remove the shm file, but it will still exist because it's currently in use + CreateMemorymapFile(emu->context, tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + #ifndef NOALIGN + if(strcmp(path, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + if(isCpuTopology(path)!=-1) { + int n = isCpuTopology(path); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode);; + } + #endif + if(isProcSelf(path, "exe")) { + return fopen(emu->context->fullpath, mode); + } + return fopen(path, mode); +} + +EXPORT FILE* my_fopen64(x64emu_t* emu, const char* path, const char* mode) +{ + if(isProcSelf(path, "maps")) { + // special case for self memory map + int tmp = shm_open(TMP_MEMMAP, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen64(path, mode); // error fallback + shm_unlink(TMP_MEMMAP); // remove the shm file, but it will still exist because it's currently in use + CreateMemorymapFile(emu->context, tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + #ifndef NOALIGN + if(strcmp(path, "/proc/cpuinfo")==0) { + // special case for cpuinfo + int tmp = shm_open(TMP_CPUINFO, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen64(path, mode); // error fallback + shm_unlink(TMP_CPUINFO); // remove the shm file, but it will still exist because it's currently in use + CreateCPUInfoFile(tmp); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode); + } + if(isCpuTopology(path)!=-1) { + int n = isCpuTopology(path); + char buf[512]; + snprintf(buf, 512, TMP_CPUTOPO, n); + int tmp = shm_open(buf, O_RDWR | O_CREAT, S_IRWXU); + if(tmp<0) return fopen(path, mode); // error fallback + shm_unlink(buf); // remove the shm file, but it will still exist because it's currently in use + CreateCPUTopologyCoreID(tmp, n); + lseek(tmp, 0, SEEK_SET); + return fdopen(tmp, mode);; + } + #endif + if(isProcSelf(path, "exe")) { + return fopen64(emu->context->fullpath, mode); + } + return fopen64(path, mode); +} + + +EXPORT int my_mkstemps64(x64emu_t* emu, char* template, int suffixlen) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "mkstemps64"); + if(f) + return ((iFpi_t)f)(template, suffixlen); + // implement own version... + // TODO: check size of template, and if really XXXXXX is there + char* fname = strdup(template); + do { + strcpy(fname, template); + char num[8]; + sprintf(num, "%06d", rand()%999999); + memcpy(fname+strlen(fname)-suffixlen-6, num, 6); + } while(!FileExist(fname, -1)); + int ret = open64(fname, O_EXCL); + free(fname); + return ret; +} + +EXPORT int32_t my_ftw(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd) +{ + static iFppi_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFppi_t)dlsym(lib->priv.w.lib, "ftw"); + } + + return f(pathname, findftwFct(B), nopenfd); +} + +EXPORT int32_t my_nftw(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd, int32_t flags) +{ + static iFppii_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFppii_t)dlsym(lib->priv.w.lib, "nftw"); + } + + return f(pathname, findnftwFct(B), nopenfd, flags); +} + +EXPORT void* my_ldiv(x64emu_t* emu, void* p, int32_t num, int32_t den) +{ + *((ldiv_t*)p) = ldiv(num, den); + return p; +} + +#ifndef NOALIGN +EXPORT int my_epoll_create(x64emu_t* emu, int size) +{ + return epoll_create(size); +} +EXPORT int my_epoll_create1(x64emu_t* emu, int flags) +{ + return epoll_create1(flags); +} +EXPORT int32_t my_epoll_ctl(x64emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event) +{ + struct epoll_event _event[1] = {0}; + if(event && (op!=EPOLL_CTL_DEL)) + AlignEpollEvent(_event, event, 1); + return epoll_ctl(epfd, op, fd, event?_event:event); +} +EXPORT int32_t my_epoll_wait(x64emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout) +{ + struct epoll_event _events[maxevents]; + //AlignEpollEvent(_events, events, maxevents); + int32_t ret = epoll_wait(epfd, events?_events:NULL, maxevents, timeout); + if(ret>0) + UnalignEpollEvent(events, _events, ret); + return ret; +} +#endif + +EXPORT int32_t my_glob(x64emu_t *emu, void* pat, int32_t flags, void* errfnc, void* pglob) +{ + static iFpipp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFpipp_t)dlsym(lib->priv.w.lib, "glob"); + } + + return f(pat, flags, findgloberrFct(errfnc), pglob); +} + +EXPORT int32_t my_glob64(x64emu_t *emu, void* pat, int32_t flags, void* errfnc, void* pglob) +{ + return glob64(pat, flags, findgloberrFct(errfnc), pglob); +} + +EXPORT int my_scandir64(x64emu_t *emu, void* dir, void* namelist, void* sel, void* comp) +{ + return scandir64(dir, namelist, findfilter64Fct(sel), findcompare64Fct(comp)); +} + +EXPORT int my_scandir(x64emu_t *emu, void* dir, void* namelist, void* sel, void* comp) +{ + static iFpppp_t f = NULL; + if(!f) { + library_t* lib = my_lib; + if(!lib) return 0; + f = (iFpppp_t)dlsym(lib->priv.w.lib, "scandir"); + } + + return f(dir, namelist, findfilter_dirFct(sel), findcompare_dirFct(comp)); +} + +EXPORT int my_ftw64(x64emu_t* emu, void* filename, void* func, int descriptors) +{ + return ftw64(filename, findftw64Fct(func), descriptors); +} + +EXPORT int32_t my_nftw64(x64emu_t* emu, void* pathname, void* B, int32_t nopenfd, int32_t flags) +{ + return nftw64(pathname, findnftw64Fct(B), nopenfd, flags); +} + +EXPORT int32_t my_execv(x64emu_t* emu, const char* path, char* const argv[]) +{ + int self = isProcSelf(path, "exe"); + int x86 = FileIsX86ELF(path); + printf_log(LOG_DEBUG, "execv(\"%s\", %p) is x86=%d\n", path, argv, x86); + #if 1 + if ((x86 || self) && argv) { + int skip_first = 0; + if(strlen(path)>=strlen("wine-preloader") && strcmp(path+strlen(path)-strlen("wine-preloader"), "wine-preloader")==0) + skip_first++; + // count argv... + int n=skip_first; + while(argv[n]) ++n; + const char** newargv = (const char**)calloc(n+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + memcpy(newargv+1, argv+skip_first, sizeof(char*)*(n+1)); + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => execv(\"%s\", %p [\"%s\", \"%s\", \"%s\"...:%d])\n", emu->context->box64path, newargv, newargv[0], n?newargv[1]:"", (n>1)?newargv[2]:"",n); + int ret = execv(newargv[0], (char* const*)newargv); + free(newargv); + return ret; + } + #endif + if(self && !argv) + return execv(emu->context->box64path, argv); + return execv(path, argv); +} + +EXPORT int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]) +{ + int self = isProcSelf(path, "exe"); + int x86 = FileIsX86ELF(path); + printf_log(LOG_DEBUG, "execv(\"%s\", %p) is x86=%d\n", path, argv, x86); + #if 1 + if ((x86 || self) && argv) { + int skip_first = 0; + if(strlen(path)>=strlen("wine-preloader") && strcmp(path+strlen(path)-strlen("wine-preloader"), "wine-preloader")==0) + skip_first++; + // count argv... + int n=skip_first; + while(argv[n]) ++n; + const char** newargv = (const char**)calloc(n+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + memcpy(newargv+1, argv+skip_first, sizeof(char*)*(n+1)); + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => execv(\"%s\", %p [\"%s\", \"%s\", \"%s\"...:%d])\n", emu->context->box64path, newargv, newargv[0], n?newargv[1]:"", (n>1)?newargv[2]:"",n); + int ret = execve(newargv[0], (char* const*)newargv, envp); + free(newargv); + return ret; + } + #endif + if(self && !argv) + return execve(emu->context->box64path, argv, envp); + return execve(path, argv, envp); +} + +// execvp should use PATH to search for the program first +EXPORT int32_t my_execvp(x64emu_t* emu, const char* path, char* const argv[]) +{ + // need to use BOX86_PATH / PATH here... + char* fullpath = ResolveFile(path, &my_context->box64_path); + // use fullpath... + int self = isProcSelf(fullpath, "exe"); + int x86 = FileIsX86ELF(fullpath); + printf_log(LOG_DEBUG, "execvp(\"%s\", %p), IsX86=%d / fullpath=\"%s\"\n", path, argv, x86, fullpath); + free(fullpath); + if ((x86 || self) && argv) { + // count argv... + int i=0; + while(argv[i]) ++i; + char** newargv = (char**)calloc(i+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + for (int j=0; j<i; ++j) + newargv[j+1] = argv[j]; + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => execvp(\"%s\", %p [\"%s\", \"%s\"...:%d])\n", newargv[0], newargv, newargv[1], i?newargv[2]:"", i); + int ret = execvp(newargv[0], newargv); + free(newargv); + return ret; + } + if(self && !argv) + return execvp(emu->context->box64path, argv); + // fullpath is gone, so the search will only be on PATH, not on BOX86_PATH (is that an issue?) + return execvp(path, argv); +} + +// execvp should use PATH to search for the program first +EXPORT int32_t my_posix_spawnp(x64emu_t* emu, pid_t* pid, const char* path, + const posix_spawn_file_actions_t *actions, const posix_spawnattr_t* attrp, char* const argv[], char* const envp[]) +{ + // need to use BOX86_PATH / PATH here... + char* fullpath = ResolveFile(path, &my_context->box64_path); + // use fullpath... + int self = isProcSelf(fullpath, "exe"); + int x86 = FileIsX86ELF(fullpath); + printf_log(LOG_DEBUG, "posix_spawnp(%p, \"%s\", %p, %p, %p, %p), IsX86=%d / fullpath=\"%s\"\n", pid, path, actions, attrp, argv, envp, x86, fullpath); + free(fullpath); + if ((x86 || self)) { + // count argv... + int i=0; + while(argv[i]) ++i; + char** newargv = (char**)calloc(i+2, sizeof(char*)); + newargv[0] = emu->context->box64path; + for (int j=0; j<i; ++j) + newargv[j+1] = argv[j]; + if(self) newargv[1] = emu->context->fullpath; + printf_log(LOG_DEBUG, " => posix_spawnp(%p, \"%s\", %p, %p, %p [\"%s\", \"%s\"...:%d], %p)\n", pid, newargv[0], actions, attrp, newargv, newargv[1], i?newargv[2]:"", i, envp); + int ret = posix_spawnp(pid, newargv[0], actions, attrp, newargv, envp); + printf_log(LOG_DEBUG, "posix_spawnp returned %d\n", ret); + //free(newargv); + return ret; + } + // fullpath is gone, so the search will only be on PATH, not on BOX86_PATH (is that an issue?) + return posix_spawnp(pid, path, actions, attrp, argv, envp); +} + +EXPORT void my__Jv_RegisterClasses() {} + +EXPORT int32_t my___cxa_thread_atexit_impl(x64emu_t* emu, void* dtor, void* obj, void* dso) +{ + printf_log(LOG_INFO, "Warning, call to __cxa_thread_atexit_impl(%p, %p, %p) ignored\n", dtor, obj, dso); + return 0; +} + +extern void __chk_fail(); +EXPORT unsigned long int my___fdelt_chk (unsigned long int d) +{ + if (d >= FD_SETSIZE) + __chk_fail (); + + return d / __NFDBITS; +} + +EXPORT int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags) +{ + // not always implemented on old linux version... + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "getrandom"); + if(f) + return ((iFpuu_t)f)(buf, buflen, flags); + // do what should not be done, but it's better then nothing.... + FILE * rnd = fopen("/dev/urandom", "rb"); + uint32_t r = fread(buf, 1, buflen, rnd); + fclose(rnd); + return r; +} + +EXPORT int32_t my_recvmmsg(x64emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags, void* timeout) +{ + // Implemented starting glibc 2.12+ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "recvmmsg"); + if(f) + return ((iFipuup_t)f)(fd, msgvec, vlen, flags, timeout); + // Use the syscall + return syscall(__NR_recvmmsg, fd, msgvec, vlen, flags, timeout); +} + +EXPORT int32_t my___sendmmsg(x64emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags) +{ + // Implemented starting glibc 2.14+ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "__sendmmsg"); + if(f) + return ((iFipuu_t)f)(fd, msgvec, vlen, flags); + // Use the syscall + return syscall(__NR_sendmmsg, fd, msgvec, vlen, flags); +} + +EXPORT int32_t my___register_atfork(x64emu_t *emu, void* prepare, void* parent, void* child, void* handle) +{ + // this is partly incorrect, because the emulated funcionts should be executed by actual fork and not by my_atfork... + if(my_context->atfork_sz==my_context->atfork_cap) { + my_context->atfork_cap += 4; + my_context->atforks = (atfork_fnc_t*)realloc(my_context->atforks, my_context->atfork_cap*sizeof(atfork_fnc_t)); + } + my_context->atforks[my_context->atfork_sz].prepare = (uintptr_t)prepare; + my_context->atforks[my_context->atfork_sz].parent = (uintptr_t)parent; + my_context->atforks[my_context->atfork_sz].child = (uintptr_t)child; + my_context->atforks[my_context->atfork_sz].handle = handle; + return 0; +} + +EXPORT uint64_t my___umoddi3(uint64_t a, uint64_t b) +{ + return a%b; +} +EXPORT uint64_t my___udivdi3(uint64_t a, uint64_t b) +{ + return a/b; +} +EXPORT int64_t my___divdi3(int64_t a, int64_t b) +{ + return a/b; +} + +EXPORT int32_t my___poll_chk(void* a, uint32_t b, int c, int l) +{ + return poll(a, b, c); // no check... +} + +EXPORT int32_t my_fcntl64(x64emu_t* emu, int32_t a, int32_t b, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4, uint32_t d5, uint32_t d6) +{ + // Implemented starting glibc 2.14+ + library_t* lib = my_lib; + if(!lib) return 0; + iFiiV_t f = dlsym(lib->priv.w.lib, "fcntl64"); + if(b==F_SETFL) + d1 = of_convert(d1); + if(b==F_GETLK64 || b==F_SETLK64 || b==F_SETLKW64) + { + my_flock64_t fl; + AlignFlock64(&fl, (void*)d1); + int ret = f?f(a, b, &fl):fcntl(a, b, &fl); + UnalignFlock64((void*)d1, &fl); + return ret; + } + //TODO: check if better to use the syscall or regular fcntl? + //return syscall(__NR_fcntl64, a, b, d1); // should be enough + int ret = f?f(a, b, d1):fcntl(a, b, d1); + + if(b==F_GETFL && ret!=-1) + ret = of_unconvert(ret); + + return ret; +} + +EXPORT int32_t my_fcntl(x64emu_t* emu, int32_t a, int32_t b, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4, uint32_t d5, uint32_t d6) +{ + if(b==F_SETFL && d1==0xFFFFF7FF) { + // special case for ~O_NONBLOCK... + int flags = fcntl(a, F_GETFL); + if(flags&O_NONBLOCK) { + flags &= ~O_NONBLOCK; + return fcntl(a, b, flags); + } + return 0; + } + if(b==F_SETFL) + d1 = of_convert(d1); + if(b==F_GETLK64 || b==F_SETLK64 || b==F_SETLKW64) + { + my_flock64_t fl; + AlignFlock64(&fl, (void*)d1); + int ret = fcntl(a, b, &fl); + UnalignFlock64((void*)d1, &fl); + return ret; + } + int ret = fcntl(a, b, d1); + if(b==F_GETFL && ret!=-1) + ret = of_unconvert(ret); + + return ret; +} +EXPORT int32_t my___fcntl(x64emu_t* emu, int32_t a, int32_t b, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4, uint32_t d5, uint32_t d6) __attribute__((alias("my_fcntl"))); + +EXPORT int32_t my_preadv64(x64emu_t* emu, int32_t fd, void* v, int32_t c, int64_t o) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "preadv64"); + if(f) + return ((iFipiI_t)f)(fd, v, c, o); + return syscall(__NR_preadv, fd, v, c,(uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); +} + +EXPORT int32_t my_pwritev64(x64emu_t* emu, int32_t fd, void* v, int32_t c, int64_t o) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "pwritev64"); + if(f) + return ((iFipiI_t)f)(fd, v, c, o); + #ifdef __arm__ + return syscall(__NR_pwritev, fd, v, c, 0, (uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); + // on arm, 64bits args needs to be on even/odd register, so need to put a 0 for aligment + #else + return syscall(__NR_pwritev, fd, v, c,(uint32_t)(o&0xffffffff), (uint32_t)((o>>32)&0xffffffff)); + #endif +} + +EXPORT int32_t my_accept4(x64emu_t* emu, int32_t fd, void* a, void* l, int32_t flags) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "accept4"); + if(f) + return ((iFippi_t)f)(fd, a, l, flags); + if(!flags) + return accept(fd, a, l); + return syscall(__NR_accept4, fd, a, l, flags); +} + +EXPORT int32_t my_fallocate64(int fd, int mode, int64_t offs, int64_t len) +{ + iFiiII_t f = NULL; + static int done = 0; + if(!done) { + library_t* lib = my_lib; + f = (iFiiII_t)dlsym(lib->priv.w.lib, "fallocate64"); + done = 1; + } + if(f) + return f(fd, mode, offs, len); + else + return syscall(__NR_fallocate, fd, mode, (uint32_t)(offs&0xffffffff), (uint32_t)((offs>>32)&0xffffffff), (uint32_t)(len&0xffffffff), (uint32_t)((len>>32)&0xffffffff)); + //return posix_fallocate64(fd, offs, len); +} + +EXPORT struct __processor_model +{ + unsigned int __cpu_vendor; + unsigned int __cpu_type; + unsigned int __cpu_subtype; + unsigned int __cpu_features[1]; +} my___cpu_model; + +#include "cpu_info.h" +void InitCpuModel() +{ + // some pseudo random cpu info... + my___cpu_model.__cpu_vendor = VENDOR_INTEL; + my___cpu_model.__cpu_type = INTEL_PENTIUM_M; + my___cpu_model.__cpu_subtype = 0; // N/A + my___cpu_model.__cpu_features[0] = (1<<FEATURE_CMOV) + | (1<<FEATURE_MMX) + | (1<<FEATURE_SSE) + | (1<<FEATURE_SSE2) + | (1<<FEATURE_SSE3) + | (1<<FEATURE_SSSE3) + | (1<<FEATURE_MOVBE) + | (1<<FEATURE_ADX); +} +#endif +EXPORT const unsigned short int *my___ctype_b; +EXPORT const int32_t *my___ctype_tolower; +EXPORT const int32_t *my___ctype_toupper; + +void ctSetup() +{ + my___ctype_b = *(__ctype_b_loc()); + my___ctype_toupper = *(__ctype_toupper_loc()); + my___ctype_tolower = *(__ctype_tolower_loc()); +} + +EXPORT void* my___libc_stack_end; +void stSetup(box64context_t* context) +{ + my___libc_stack_end = context->stack; // is this the end, or should I add stasz? +} + +EXPORT void my___register_frame_info(void* a, void* b) +{ + // nothing +} +EXPORT void* my___deregister_frame_info(void* a) +{ + return NULL; +} + +EXPORT void* my____brk_addr = NULL; +#if 0 +// longjmp / setjmp +typedef struct jump_buff_i386_s { + uint32_t save_ebx; + uint32_t save_esi; + uint32_t save_edi; + uint32_t save_ebp; + uint32_t save_esp; + uint32_t save_eip; +} jump_buff_i386_t; + +typedef struct __jmp_buf_tag_s { + jump_buff_i386_t __jmpbuf; + int __mask_was_saved; + __sigset_t __saved_mask; +} __jmp_buf_tag_t; + +void EXPORT my_longjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p, int32_t __val) +{ + jump_buff_i386_t *jpbuff = &((__jmp_buf_tag_t*)p)->__jmpbuf; + //restore regs + R_EBX = jpbuff->save_ebx; + R_ESI = jpbuff->save_esi; + R_EDI = jpbuff->save_edi; + R_EBP = jpbuff->save_ebp; + R_ESP = jpbuff->save_esp; + // jmp to saved location, plus restore val to eax + R_EAX = __val; + R_EIP = jpbuff->save_eip; + if(emu->quitonlongjmp) { + emu->longjmp = 1; + emu->quit = 1; + } +} + +EXPORT int32_t my_setjmp(x64emu_t* emu, /*struct __jmp_buf_tag __env[1]*/void *p) +{ + jump_buff_i386_t *jpbuff = &((__jmp_buf_tag_t*)p)->__jmpbuf; + // save the buffer + jpbuff->save_ebx = R_EBX; + jpbuff->save_esi = R_ESI; + jpbuff->save_edi = R_EDI; + jpbuff->save_ebp = R_EBP; + jpbuff->save_esp = R_ESP+4; // include "return address" + jpbuff->save_eip = *(uint32_t*)(R_ESP); + // and that's it.. Nothing more for now + return 0; +} + +EXPORT void my___explicit_bzero_chk(x64emu_t* emu, void* dst, uint32_t len, uint32_t dstlen) +{ + memset(dst, 0, len); +} + +EXPORT void* my_realpath(x64emu_t* emu, void* path, void* resolved_path) +{ + + if(isProcSelf(path, "exe")) { + return realpath(emu->context->fullpath, resolved_path); + } + return realpath(path, resolved_path); +} + +EXPORT void* my_mmap(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset) +{ + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "mmap(%p, %lu, 0x%x, 0x%x, %d, %d) =>", addr, length, prot, flags, fd, offset);} + void* ret = mmap(addr, length, prot, flags, fd, offset); + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "%p\n", ret);} + #ifdef DYNAREC + if(box64_dynarec && ret!=(void*)-1) { + if(flags&0x100000 && addr!=ret) + { + // program used MAP_FIXED_NOREPLACE but the host linux didn't support it + // and responded with a different address, so ignore it + } else { + if(prot& PROT_EXEC) + addDBFromAddressRange((uintptr_t)ret, length); + else + cleanDBFromAddressRange((uintptr_t)ret, length, prot?0:1); + } + } + #endif + if(ret!=(void*)-1) + setProtection((uintptr_t)ret, length, prot); + return ret; +} + +EXPORT void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset) +{ + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "mmap64(%p, %lu, 0x%x, 0x%x, %d, %lld) =>", addr, length, prot, flags, fd, offset);} + void* ret = mmap64(addr, length, prot, flags, fd, offset); + if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "%p\n", ret);} + #ifdef DYNAREC + if(box64_dynarec && ret!=(void*)-1) { + if(flags&0x100000 && addr!=ret) + { + // program used MAP_FIXED_NOREPLACE but the host linux didn't support it + // and responded with a different address, so ignore it + } else { + if(prot& PROT_EXEC) + addDBFromAddressRange((uintptr_t)ret, length); + else + cleanDBFromAddressRange((uintptr_t)ret, length, prot?0:1); + } + } + #endif + if(ret!=(void*)-1) + setProtection((uintptr_t)ret, length, prot); + return ret; +} + +EXPORT void* my_mremap(x64emu_t* emu, void* old_addr, size_t old_size, size_t new_size, int flags, void* new_addr) +{ + dynarec_log(/*LOG_DEBUG*/LOG_NONE, "mremap(%p, %u, %u, %d, %p)=>", old_addr, old_size, new_size, flags, new_addr); + void* ret = mremap(old_addr, old_size, new_size, flags, new_addr); + if(ret==(void*)-1) + return ret; // failed... + uint32_t prot = getProtection((uintptr_t)old_addr)&~PROT_DYNAREC; + if(ret==old_addr) { + if(old_size && old_size<new_size) { + setProtection((uintptr_t)ret+old_size, new_size-old_size, prot); + #ifdef DYNAREC + if(box64_dynarec) + addDBFromAddressRange((uintptr_t)ret+old_size, new_size-old_size); + #endif + } else if(old_size && new_size<old_size) { + setProtection((uintptr_t)ret+new_size, old_size-new_size, 0); + #ifdef DYNAREC + if(box64_dynarec) + cleanDBFromAddressRange((uintptr_t)ret+new_size, new_size-old_size, 1); + #endif + } else if(!old_size) { + setProtection((uintptr_t)ret, new_size, prot); + #ifdef DYNAREC + if(box64_dynarec) + addDBFromAddressRange((uintptr_t)ret, new_size); + #endif + } + } else { + if(old_size + #ifdef MREMAP_DONTUNMAP + && flags&MREMAP_DONTUNMAP==0 + #endif + ) { + setProtection((uintptr_t)old_addr, old_size, 0); + #ifdef DYNAREC + if(box64_dynarec) + cleanDBFromAddressRange((uintptr_t)old_addr, old_size, 1); + #endif + } + setProtection((uintptr_t)ret, new_size, prot); // should copy the protection from old block + #ifdef DYNAREC + if(box64_dynarec) + addDBFromAddressRange((uintptr_t)ret, new_size); + #endif + } + return ret; +} + +EXPORT int my_munmap(x64emu_t* emu, void* addr, unsigned long length) +{ + dynarec_log(LOG_DEBUG, "munmap(%p, %lu)\n", addr, length); + #ifdef DYNAREC + if(box64_dynarec) { + cleanDBFromAddressRange((uintptr_t)addr, length, 1); + } + #endif + int ret = munmap(addr, length); + if(!ret) + setProtection((uintptr_t)addr, length, 0); + return ret; +} + +EXPORT int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot) +{ + dynarec_log(LOG_DEBUG, "mprotect(%p, %lu, 0x%x)\n", addr, len, prot); + if(prot&PROT_WRITE) + prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 + int ret = mprotect(addr, len, prot); + #ifdef DYNAREC + if(box64_dynarec) { + if(prot& PROT_EXEC) + addDBFromAddressRange((uintptr_t)addr, len); + else + cleanDBFromAddressRange((uintptr_t)addr, len, 0); + } + #endif + if(!ret) + updateProtection((uintptr_t)addr, len, prot); + return ret; +} + +typedef struct my_cookie_s { + uintptr_t r, w, s, c; + void* cookie; +} my_cookie_t; + +static ssize_t my_cookie_read(void *p, char *buf, size_t size) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + return (ssize_t)RunFunction(my_context, cookie->r, 3, cookie->cookie, buf, size); +} +static ssize_t my_cookie_write(void *p, const char *buf, size_t size) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + return (ssize_t)RunFunction(my_context, cookie->w, 3, cookie->cookie, buf, size); +} +static int my_cookie_seek(void *p, off64_t *offset, int whence) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + return RunFunction(my_context, cookie->s, 3, cookie->cookie, offset, whence); +} +static int my_cookie_close(void *p) +{ + my_cookie_t* cookie = (my_cookie_t*)p; + int ret = 0; + if(cookie->c) + ret = RunFunction(my_context, cookie->c, 1, cookie->cookie); + free(cookie); + return ret; +} +EXPORT void* my_fopencookie(x64emu_t* emu, void* cookie, void* mode, void* read, void* write, void* seek, void* close) +{ + cookie_io_functions_t io_funcs = {read?my_cookie_read:NULL, write?my_cookie_write:NULL, seek?my_cookie_seek:NULL, my_cookie_close}; + my_cookie_t *cb = (my_cookie_t*)calloc(1, sizeof(my_cookie_t)); + cb->r = (uintptr_t)read; + cb->w = (uintptr_t)write; + cb->s = (uintptr_t)seek; + cb->c = (uintptr_t)close; + cb->cookie = cookie; + return fopencookie(cb, mode, io_funcs); +} + +EXPORT long my_prlimit64(void* pid, uint32_t res, void* new_rlim, void* old_rlim) +{ + return syscall(__NR_prlimit64, pid, res, new_rlim, old_rlim); +} + +EXPORT void* my_reallocarray(void* ptr, size_t nmemb, size_t size) +{ + return realloc(ptr, nmemb*size); +} + +#ifndef __OPEN_NEEDS_MODE +# define __OPEN_NEEDS_MODE(oflag) \ + (((oflag) & O_CREAT) != 0) +// || ((oflag) & __O_TMPFILE) == __O_TMPFILE) +#endif +EXPORT int my___open_nocancel(x64emu_t* emu, void* file, int oflag, int* b) +{ + int mode = 0; + if (__OPEN_NEEDS_MODE (oflag)) + mode = b[0]; + return openat(AT_FDCWD, file, oflag, mode); +} + +EXPORT int my___libc_alloca_cutoff(x64emu_t* emu, size_t size) +{ + // not always implemented on old linux version... + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "__libc_alloca_cutoff"); + if(f) + return ((iFL_t)f)(size); + // approximate version but it's better than nothing.... + return (size<=(65536*4)); +} + +// DL functions from wrappedlibdl.c +void* my_dlopen(x64emu_t* emu, void *filename, int flag); +int my_dlclose(x64emu_t* emu, void *handle); +void* my_dlsym(x64emu_t* emu, void *handle, void *symbol); +EXPORT int my___libc_dlclose(x64emu_t* emu, void* handle) +{ + return my_dlclose(emu, handle); +} +EXPORT void* my___libc_dlopen_mode(x64emu_t* emu, void* name, int mode) +{ + return my_dlopen(emu, name, mode); +} +EXPORT void* my___libc_dlsym(x64emu_t* emu, void* handle, void* name) +{ + return my_dlsym(emu, handle, name); +} + +// all obstack function defined in obstack.c file +void obstackSetup(); + +EXPORT int my_nanosleep(const struct timespec *req, struct timespec *rem) +{ + if(!req) + return 0; // workaround for some strange calls + return nanosleep(req, rem); +} + +#ifndef NOALIGN +// wrapped malloc using calloc, it seems x86 malloc set alloc'd block to zero somehow +EXPORT void* my_malloc(unsigned long size) +{ + return calloc(1, size); +} +#endif + +#ifdef PANDORA +#define RENAME_NOREPLACE (1 << 0) +#define RENAME_EXCHANGE (1 << 1) +#define RENAME_WHITEOUT (1 << 2) +EXPORT int my_renameat2(int olddirfd, void* oldpath, int newdirfd, void* newpath, uint32_t flags) +{ + // simulate that function, but + if(flags&RENAME_NOREPLACE) { + if(FileExist(newpath, -1)) { + errno = EEXIST; + return -1; + } + flags &= ~RENAME_NOREPLACE; + } + if(!flags) return renameat(olddirfd, oldpath, newdirfd, newpath); + if(flags&RENAME_WHITEOUT) { + errno = EINVAL; + return -1; // not handling that + } + if((flags&RENAME_EXCHANGE) && (olddirfd==-1) && (newdirfd==-1)) { + // cannot do atomically... + char* tmp = (char*)malloc(strlen(oldpath)+10); // create a temp intermediary + tmp = strcat(oldpath, ".tmp"); + int ret = renameat(-1, oldpath, -1, tmp); + if(ret==-1) return -1; + ret = renameat(-1, newpath, -1, oldpath); + if(ret==-1) return -1; + ret = renameat(-1, tmp, -1, newpath); + free(tmp); + return ret; + } + return -1; // unknown flags +} +#endif + +#ifndef __NR_memfd_create +#define MFD_CLOEXEC 0x0001U +#define MFD_ALLOW_SEALING 0x0002U +EXPORT int my_memfd_create(x64emu_t* emu, void* name, uint32_t flags) +{ + // try to simulate that function + uint32_t fl = O_RDWR | O_CREAT; + if(flags&MFD_CLOEXEC) + fl |= O_CLOEXEC; + int tmp = shm_open(name, fl, S_IRWXU); + if(tmp<0) return -1; + shm_unlink(name); // remove the shm file, but it will still exist because it's currently in use + return tmp; +} +#endif + +#ifndef GRND_RANDOM +#define GRND_RANDOM 0x0002 +#endif +EXPORT int my_getentropy(x64emu_t* emu, void* buffer, size_t length) +{ + library_t* lib = my_lib; + if(!lib) return 0; + void* f = dlsym(lib->priv.w.lib, "getentropy"); + if(f) + return ((iFpL_t)f)(buffer, length); + // custom implementation + if(length>256) { + errno = EIO; + return -1; + } + int ret = my_getrandom(emu, buffer, length, GRND_RANDOM); + if(ret!=length) { + errno = EIO; + return -1; + } + return 0; +} + +EXPORT void my_mcount(void* frompc, void* selfpc) +{ + // stub doing nothing... + return; +} + +union semun { + int val; /* Value for SETVAL */ + struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* Array for GETALL, SETALL */ + struct seminfo *__buf; /* Buffer for IPC_INFO + (Linux-specific) */ +}; + +EXPORT int my_semctl(x64emu_t* emu, int semid, int semnum, int cmd, union semun b) +{ + iFiiiV_t f = semctl; + return ((iFiiiV_t)f)(semid, semnum, cmd, b); +} +#endif + +EXPORT char** my_environ = NULL; +EXPORT char** my__environ = NULL; +EXPORT char** my___environ = NULL; // all aliases + +EXPORT char* my___progname = NULL; +EXPORT char* my___progname_full = NULL; +EXPORT char* my_program_invocation_name = NULL; +EXPORT char* my_program_invocation_short_name = NULL; + +#define PRE_INIT\ + if(box64_tcmalloc_minimal) \ + lib->priv.w.lib = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); \ + else + +#define CUSTOM_INIT \ + box64->libclib = lib; \ + my_lib = lib; \ + /*InitCpuModel();*/ \ + ctSetup(); \ + stSetup(box64); \ + /*obstackSetup();*/ \ + my_environ = my__environ = my___environ = box64->envv; \ + my___progname_full = my_program_invocation_name = box64->argv[0]; \ + my___progname = my_program_invocation_short_name = \ + strrchr(box64->argv[0], '/'); \ + lib->priv.w.p2 = getLIBCMy(lib); \ + lib->priv.w.needed = 3; \ + lib->priv.w.neededlibs = (char**)calloc(lib->priv.w.needed, sizeof(char*)); \ + lib->priv.w.neededlibs[0] = strdup("ld-linux-x86-64.so.2"); \ + lib->priv.w.neededlibs[1] = strdup("libpthread.so.0"); \ + lib->priv.w.neededlibs[2] = strdup("librt.so.1"); + +#define CUSTOM_FINI \ + freeLIBCMy(lib->priv.w.p2); \ + free(lib->priv.w.p2); \ + my_lib = NULL; + +#include "wrappedlib_init.h" diff --git a/src/wrapped/wrappedlibc_private.h b/src/wrapped/wrappedlibc_private.h new file mode 100755 index 00000000..4efac07b --- /dev/null +++ b/src/wrapped/wrappedlibc_private.h @@ -0,0 +1,2238 @@ +#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA) && defined(GOS)) +#error Meh... +#endif + +//GO(a64l, +//GO(abort, +//DATAB(__abort_msg, +//GO(abs, +//GO(accept, +//GO(accept4, +//GOW(access, +//GO(acct, +//GOW(addmntent, +//GOW(addseverity, +//GOW(adjtime, +//GO(__adjtimex, +//GOW(adjtimex, +//GOW(advance, +//GO(alarm, +//GOW(aligned_alloc, +//GOW(alphasort, +//GOW(alphasort64, +//GO(__arch_prctl, +//GOW(arch_prctl, +//DATA(argp_err_exit_status, +//GOW(argp_error, +//GOW(argp_failure, +//GOW(argp_help, +//GOW(argp_parse, +//DATAB(argp_program_bug_address, +//DATAB(argp_program_version, +//DATAB(argp_program_version_hook, +//GOW(argp_state_help, +//GOW(argp_usage, +//GOW(argz_add, +//GOW(argz_add_sep, +//GOW(argz_append, +//GO(__argz_count, +//GOW(argz_count, +//GOW(argz_create, +//GOW(argz_create_sep, +//GO(argz_delete, +//GOW(argz_extract, +//GOW(argz_insert, +//GO(__argz_next, +//GOW(argz_next, +//GOW(argz_replace, +//GO(__argz_stringify, +//GOW(argz_stringify, +//GO(asctime, +//GOW(asctime_r, +//GO(__asprintf, +//GOW(asprintf, +//GO(__asprintf_chk, +//GO(__assert, +//GO(__assert_fail, +//GO(__assert_perror_fail, +//GO(atof, +//GO(atoi, +//GO(atol, +//GO(atoll, +//GO(authdes_create, +//GO(authdes_getucred, +//GO(authdes_pk_create, +//GO(_authenticate, +//GO(authnone_create, +//GO(authunix_create, +//GO(authunix_create_default, +//GO(__backtrace, +//GOW(backtrace, +//GO(__backtrace_symbols, +//GOW(backtrace_symbols, +//GO(__backtrace_symbols_fd, +//GOW(backtrace_symbols_fd, +//GOW(basename, +//GO(bcopy, +//GO(bdflush, +//GOW(bind, +//GO(bindresvport, +//GOW(bindtextdomain, +//GOW(bind_textdomain_codeset, +//GOW(brk, +//GO(__bsd_getpgrp, +//GOW(bsd_signal, +//GO(bsearch, +//GOW(btowc, +//GO(__bzero, +//GOW(bzero, +//GO(c16rtomb, +//GOW(c32rtomb, +//GOW(calloc, +//GO(callrpc, +//GO(__call_tls_dtors, +//GOW(canonicalize_file_name, +//GO(capget, +//GO(capset, +//GO(catclose, +//GO(catgets, +//GO(catopen, +//GO(cbc_crypt, +//GO(cfgetispeed, +//GO(cfgetospeed, +//GO(cfmakeraw, +//GO(cfree, +//GO(cfsetispeed, +//GO(cfsetospeed, +//GO(cfsetspeed, +//GOW(chdir, +//DATA(__check_rhosts_file, +//GO(chflags, +//GO(__chk_fail, +//GOW(chmod, +//GOW(chown, +//GO(chroot, +//GOW(clearenv, +//GO(clearerr, +//GO(clearerr_unlocked, +//GO(clnt_broadcast, +//GO(clnt_create, +//GO(clnt_pcreateerror, +//GO(clnt_perrno, +//GO(clnt_perror, +//GO(clntraw_create, +//GO(clnt_spcreateerror, +//GO(clnt_sperrno, +//GO(clnt_sperror, +//GO(clnttcp_create, +//GO(clntudp_bufcreate, +//GO(clntudp_create, +//GO(clntunix_create, +//GO(clock, +//GO(clock_adjtime, +//GO(__clock_getcpuclockid, +//GOW(clock_getcpuclockid, +//GO(__clock_getres, +//GOW(clock_getres, +//GO(__clock_gettime, +//GOW(clock_gettime, +//GO(__clock_nanosleep, +//GOW(clock_nanosleep, +//GO(__clock_settime, +//GOW(clock_settime, +//GO(__clone, +//GOW(clone, +//GO(__close, +//GOW(close, +//GOW(closedir, +//GO(closelog, +//GO(__close_nocancel, +//GO(__cmsg_nxthdr, +//GO(confstr, +//GO(__confstr_chk, +//GOW(__connect, +//GOW(connect, +//GO(copy_file_range, +//GO(__copy_grp, +//GOW(copysign, +//GOW(copysignf, +//GOW(copysignl, +//GOW(creat, +//GOW(creat64, +//GO(create_module, +//GO(ctermid, +//GO(ctime, +//GO(ctime_r, +//DATA(__ctype32_b, +//DATA(__ctype32_tolower, +//DATA(__ctype32_toupper, +//DATA(__ctype_b, +//GO(__ctype_b_loc, +//GOW(__ctype_get_mb_cur_max, +//GO(__ctype_init, +//DATA(__ctype_tolower, +//GO(__ctype_tolower_loc, +//DATA(__ctype_toupper, +//GO(__ctype_toupper_loc, +//DATAB(__curbrk, +//GO(cuserid, +//GO(__cxa_atexit, +//GO(__cxa_at_quick_exit, +//GO(__cxa_finalize, +//GO(__cxa_thread_atexit_impl, +//GO(__cyg_profile_func_enter, +//GO(__cyg_profile_func_exit, +//GO(daemon, +//DATAB(__daylight, +//GO(__dcgettext, +//GOW(dcgettext, +//GOW(dcngettext, +//GO(__default_morecore, +//GO(delete_module, +//GO(des_setparity, +//GO(__dgettext, +//GOW(dgettext, +//GO(difftime, +//GO(dirfd, +//GO(dirname, +//GO(div, +//GO(_dl_addr, +//GO(_dl_catch_error, +//GO(_dl_catch_exception, +//GOW(dl_iterate_phdr, +//GO(_dl_mcount_wrapper, +//GO(_dl_mcount_wrapper_check, +//DATAB(_dl_open_hook, +//DATAB(_dl_open_hook2, +//GO(_dl_signal_error, +//GO(_dl_signal_exception, +//GO(_dl_sym, +//GO(_dl_vsym, +//GOW(dngettext, +//GO(dprintf, +//GO(__dprintf_chk, +//GO(drand48, +//GO(drand48_r, +//GOW(dup, +//GO(__dup2, +//GOW(dup2, +//GOW(dup3, +//GO(__duplocale, +//GOW(duplocale, +//GO(dysize, +//GOW(eaccess, +//GO(ecb_crypt, +//GO(ecvt, +//GOW(ecvt_r, +//GO(endaliasent, +//GO(endfsent, +//GO(endgrent, +//GO(endhostent, +//GO(__endmntent, +//GOW(endmntent, +//GO(endnetent, +//GO(endnetgrent, +//GO(endprotoent, +//GO(endpwent, +//GO(endrpcent, +//GO(endservent, +//GO(endsgent, +//GO(endspent, +//GOW(endttyent, +//GO(endusershell, +//GOW(endutent, +//GO(endutxent, +//DATAB(__environ, +//GO(envz_add, +//GO(envz_entry, +//GO(envz_get, +//GO(envz_merge, +//GO(envz_remove, +//GO(envz_strip, +//GO(epoll_create, +//GO(epoll_create1, +//GO(epoll_ctl, +//GO(epoll_pwait, +//GO(epoll_wait, +//GO(erand48, +//GOW(erand48_r, +//GO(err, +//DATAB(errno, +//GO(__errno_location, +//GOW(error, +//GOW(error_at_line, +//DATAB(error_message_count, +//DATAB(error_one_per_line, +//DATAB(error_print_progname, +//GO(errx, +//GO(ether_aton, +//GO(ether_aton_r, +//GO(ether_hostton, +//GO(ether_line, +//GO(ether_ntoa, +//GO(ether_ntoa_r, +//GO(ether_ntohost, +//GOW(euidaccess, +//GO(eventfd, +//GO(eventfd_read, +//GO(eventfd_write, +//GO(execl, +//GO(execle, +//GO(execlp, +//GO(execv, +//GOW(execve, +//GO(execvp, +//GOW(execvpe, +//GO(_exit, +//GO(exit, +//GOW(_Exit, +//GO(explicit_bzero, +//GO(__explicit_bzero_chk, +//GO(faccessat, +//GOW(fallocate, +//GO(fallocate64, +//GO(fanotify_init, +//GO(fanotify_mark, +//GO(fattach, +//GO(__fbufsize, +//GOW(fchdir, +//GO(fchflags, +//GOW(fchmod, +//GO(fchmodat, +//GOW(fchown, +//GO(fchownat, +//GO(fclose, +//GOW(fcloseall, +//GOW(__fcntl, +//GOW(fcntl, +//GOW(fcntl64, +//GO(fcvt, +//GOW(fcvt_r, +//GO(fdatasync, +//GO(__fdelt_chk, +//GO(__fdelt_warn, +//GO(fdetach, +//GO(fdopen, +//GOW(fdopendir, +//GO(__fentry__, +//GOW(feof, +//GOW(feof_unlocked, +//GOW(ferror, +//GOW(ferror_unlocked, +//GO(fexecve, +//GOW(fflush, +//GOW(fflush_unlocked, +//GO(__ffs, +//GO(ffs, +//GOW(ffsl, +//GO(ffsll, +//GOW(fgetc, +//GOW(fgetc_unlocked, +//GO(fgetgrent, +//GOW(fgetgrent_r, +//GO(fgetpos, +//GO(fgetpos64, +//GO(fgetpwent, +//GOW(fgetpwent_r, +//GOW(fgets, +//GO(__fgets_chk, +//GO(fgetsgent, +//GOW(fgetsgent_r, +//GO(fgetspent, +//GOW(fgetspent_r, +//GOW(fgets_unlocked, +//GO(__fgets_unlocked_chk, +//GOW(fgetwc, +//GOW(fgetwc_unlocked, +//GO(fgetws, +//GO(__fgetws_chk, +//GO(fgetws_unlocked, +//GO(__fgetws_unlocked_chk, +//GO(fgetxattr, +//GOW(fileno, +//GOW(fileno_unlocked, +//GO(__finite, +//GOW(finite, +//GO(__finitef, +//GOW(finitef, +//GO(__finitel, +//GOW(finitel, +//GO(__flbf, +//GO(flistxattr, +//GOW(flock, +//GOW(flockfile, +//GOW(_flushlbf, +//GO(fmemopen, +//GO(fmemopen, +//GO(fmtmsg, +//GO(fnmatch, +//GO(fopen, +//GOW(fopen64, +//GO(fopencookie, +//GO(__fork, +//GOW(fork, +//GO(__fortify_fail, +//GOW(fpathconf, +//GO(__fpending, +//GO(fprintf, +//GO(__fprintf_chk, +//DATA(__fpu_control, +//GO(__fpurge, +//GO(fputc, +//GO(fputc_unlocked, +//GOW(fputs, +//GOW(fputs_unlocked, +//GO(fputwc, +//GO(fputwc_unlocked, +//GO(fputws, +//GO(fputws_unlocked, +//GOW(fread, +//GO(__freadable, +//GO(__fread_chk, +//GO(__freading, +//GOW(fread_unlocked, +//GO(__fread_unlocked_chk, +//GO(free, +//GO(freeaddrinfo, +//GOW(freeifaddrs, +//GO(__freelocale, +//GOW(freelocale, +//GO(fremovexattr, +//GO(freopen, +//GO(freopen64, +//GOW(frexp, +//GOW(frexpf, +//GOW(frexpl, +//GO(fscanf, +//GO(fseek, +//GOW(fseeko, +//GO(__fseeko64, +//GOW(fseeko64, +//GO(__fsetlocking, +//GO(fsetpos, +//GO(fsetpos64, +//GO(fsetxattr, +//GOW(fstatfs, +//GOW(fstatfs64, +//GOW(fstatvfs, +//GOW(fstatvfs64, +//GO(fsync, +//GOW(ftell, +//GOW(ftello, +//GO(__ftello64, +//GOW(ftello64, +//GO(ftime, +//GO(ftok, +//GOW(ftruncate, +//GOW(ftruncate64, +//GOW(ftrylockfile, +//GOW(fts64_children, +//GOW(fts64_close, +//GOW(fts64_open, +//GOW(fts64_read, +//GOW(fts64_set, +//GO(fts_children, +//GO(fts_close, +//GO(fts_open, +//GO(fts_read, +//GO(fts_set, +//GO(ftw, +//GOW(ftw64, +//GOW(funlockfile, +//GO(futimens, +//GOW(futimes, +//GO(futimesat, +//GO(fwide, +//GOW(fwprintf, +//GO(__fwprintf_chk, +//GO(__fwritable, +//GOW(fwrite, +//GO(fwrite_unlocked, +//GO(__fwriting, +//GO(fwscanf, +//GO(__fxstat, +//GO(__fxstat64, +//GO(__fxstatat, +//GO(__fxstatat64, +//GO(__gai_sigqueue, +//GO(gai_strerror, +//GO(__gconv_get_alias_db, +//GO(__gconv_get_cache, +//GO(__gconv_get_modules_db, +//GO(__gconv_transliterate, +//GO(gcvt, +//GO(getaddrinfo, +//GO(getaliasbyname, +//GO(getaliasbyname_r, +//GO(getaliasent, +//GO(getaliasent_r, +//GO(__getauxval, +//GOW(getauxval, +//GOW(get_avphys_pages, +//GOW(getc, +//GO(getchar, +//GO(getchar_unlocked, +//GOW(getcontext, +//GOW(getc_unlocked, +//GO(get_current_dir_name, +//GOW(getcwd, +//GO(__getcwd_chk, +//GO(getdate, +//DATAB(getdate_err, +//GOW(getdate_r, +//GOW(__getdelim, +//GOW(getdelim, +//GOW(getdirentries, +//GO(getdirentries64, +//GO(getdomainname, +//GO(__getdomainname_chk, +//GOW(getdtablesize, +//GOW(getegid, +//GO(getentropy, +//GO(getenv, +//GOW(geteuid, +//GO(getfsent, +//GO(getfsfile, +//GO(getfsspec, +//GOW(getgid, +//GO(getgrent, +//GO(getgrent_r, +//GO(getgrgid, +//GO(getgrgid_r, +//GO(getgrnam, +//GO(getgrnam_r, +//GO(getgrouplist, +//GOW(getgroups, +//GO(__getgroups_chk, +//GO(gethostbyaddr, +//GO(gethostbyaddr_r, +//GO(gethostbyname, +//GO(gethostbyname2, +//GO(gethostbyname2_r, +//GO(gethostbyname_r, +//GO(gethostent, +//GO(gethostent_r, +//GO(gethostid, +//GOW(gethostname, +//GO(__gethostname_chk, +//GOW(getifaddrs, +//GO(getipv4sourcefilter, +//GOW(getitimer, +//GO(get_kernel_syms, +//GOW(getline, +//GO(getloadavg, +//GO(getlogin, +//GOW(getlogin_r, +//GO(__getlogin_r_chk, +//GO(getmntent, +//GO(__getmntent_r, +//GOW(getmntent_r, +//GO(getmsg, +//GO(get_myaddress, +//GO(getnameinfo, +//GO(getnetbyaddr, +//GO(getnetbyaddr_r, +//GO(getnetbyname, +//GO(getnetbyname_r, +//GO(getnetent, +//GO(getnetent_r, +//GO(getnetgrent, +//GOW(getnetgrent_r, +//GO(getnetname, +//GOW(get_nprocs, +//GOW(get_nprocs_conf, +//GO(getopt, +//GO(getopt_long, +//GO(getopt_long_only, +//GO(__getpagesize, +//GOW(getpagesize, +//GO(getpass, +//GOW(getpeername, +//GO(__getpgid, +//GOW(getpgid, +//GO(getpgrp, +//GOW(get_phys_pages, +//GO(__getpid, +//GOW(getpid, +//GO(getpmsg, +//GOW(getppid, +//GOW(getpriority, +//GO(getprotobyname, +//GO(getprotobyname_r, +//GO(getprotobynumber, +//GO(getprotobynumber_r, +//GO(getprotoent, +//GO(getprotoent_r, +//GOW(getpt, +//GO(getpublickey, +//GOW(getpw, +//GO(getpwent, +//GO(getpwent_r, +//GO(getpwnam, +//GO(getpwnam_r, +//GO(getpwuid, +//GO(getpwuid_r, +//GO(getrandom, +//GO(getresgid, +//GO(getresuid, +//GO(__getrlimit, +//GOW(getrlimit, +//GOW(getrlimit64, +//GO(getrpcbyname, +//GO(getrpcbyname_r, +//GO(getrpcbynumber, +//GO(getrpcbynumber_r, +//GO(getrpcent, +//GO(getrpcent_r, +//GO(getrpcport, +//GOW(getrusage, +//GOW(gets, +//GO(__gets_chk, +//GO(getsecretkey, +//GO(getservbyname, +//GO(getservbyname_r, +//GO(getservbyport, +//GO(getservbyport_r, +//GO(getservent, +//GO(getservent_r, +//GO(getsgent, +//GO(getsgent_r, +//GO(getsgnam, +//GO(getsgnam_r, +//GO(getsid, +//GOW(getsockname, +//GOW(getsockopt, +//GO(getsourcefilter, +//GO(getspent, +//GO(getspent_r, +//GO(getspnam, +//GO(getspnam_r, +//GO(getsubopt, +//GOW(gettext, +//GOW(getttyent, +//GOW(getttynam, +//GOW(getuid, +//GO(getusershell, +//GOW(getutent, +//GOW(getutent_r, +//GOW(getutid, +//GOW(getutid_r, +//GOW(getutline, +//GOW(getutline_r, +//GO(getutmp, +//GO(getutmpx, +//GO(getutxent, +//GO(getutxid, +//GO(getutxline, +//GO(getw, +//GOW(getwc, +//GO(getwchar, +//GO(getwchar_unlocked, +//GOW(getwc_unlocked, +//GO(getwd, +//GO(__getwd_chk, +//GO(getxattr, +//GO(glob, +//GO(glob, +//GO(glob64, +//GO(glob64, +//GO(globfree, +//GOW(globfree64, +//GOW(glob_pattern_p, +//GO(gmtime, +//GO(__gmtime_r, +//GOW(gmtime_r, +//GOW(gnu_dev_major, +//GOW(gnu_dev_makedev, +//GOW(gnu_dev_minor, +//GOW(gnu_get_libc_release, +//GOW(gnu_get_libc_version, +//GO(grantpt, +//GOW(group_member, +//GOW(gsignal, +//GO(gtty, +//GOW(hasmntopt, +//GO(hcreate, +//GOW(hcreate_r, +//GOW(hdestroy, +//GOW(hdestroy_r, +//DATA(h_errlist, +//DATAB(__h_errno, +//GO(__h_errno_location, +//GO(herror, +//GO(host2netname, +//GO(hsearch, +//GOW(hsearch_r, +//GO(hstrerror, +//GO(htonl, +//GO(htons, +//GO(iconv, +//GO(iconv_close, +//GO(iconv_open, +//GO(__idna_from_dns_encoding, +//GO(__idna_to_dns_encoding, +//GOW(if_freenameindex, +//GOW(if_indextoname, +//GOW(if_nameindex, +//GOW(if_nametoindex, +//GOW(imaxabs, +//GOW(imaxdiv, +//GO(inet6_opt_append, +//GO(inet6_opt_find, +//GO(inet6_opt_finish, +//GO(inet6_opt_get_val, +//GO(inet6_opt_init, +//GO(inet6_option_alloc, +//GO(inet6_option_append, +//GO(inet6_option_find, +//GO(inet6_option_init, +//GO(inet6_option_next, +//GO(inet6_option_space, +//GO(inet6_opt_next, +//GO(inet6_opt_set_val, +//GO(inet6_rth_add, +//GO(inet6_rth_getaddr, +//GO(inet6_rth_init, +//GO(inet6_rth_reverse, +//GO(inet6_rth_segments, +//GO(inet6_rth_space, +//GO(__inet6_scopeid_pton, +//GOW(inet_addr, +//GOW(inet_aton, +//GO(__inet_aton_exact, +//GO(inet_lnaof, +//GOW(inet_makeaddr, +//GO(inet_netof, +//GO(inet_network, +//GO(inet_nsap_addr, +//GO(inet_nsap_ntoa, +//GO(inet_ntoa, +//GO(inet_ntop, +//GOW(inet_pton, +//GO(__inet_pton_length, +//GO(initgroups, +//GO(init_module, +//GOW(initstate, +//GOW(initstate_r, +//GO(innetgr, +//GO(inotify_add_watch, +//GO(inotify_init, +//GO(inotify_init1, +//GO(inotify_rm_watch, +//GO(insque, +//GO(__internal_endnetgrent, +//GO(__internal_getnetgrent_r, +//GO(__internal_setnetgrent, +//DATA(_IO_2_1_stderr_, +//DATA(_IO_2_1_stdin_, +//DATA(_IO_2_1_stdout_, +//GO(_IO_adjust_column, +//GO(_IO_adjust_wcolumn, +//GOW(ioctl, +//GO(_IO_default_doallocate, +//GO(_IO_default_finish, +//GO(_IO_default_pbackfail, +//GO(_IO_default_uflow, +//GO(_IO_default_xsgetn, +//GO(_IO_default_xsputn, +//GO(_IO_doallocbuf, +//GO(_IO_do_write, +//GO(_IO_enable_locks, +//GO(_IO_fclose, +//GO(_IO_fdopen, +//GO(_IO_feof, +//GO(_IO_ferror, +//GO(_IO_fflush, +//GO(_IO_fgetpos, +//GO(_IO_fgetpos64, +//GO(_IO_fgets, +//GO(_IO_file_attach, +//GO(_IO_file_close, +//GO(_IO_file_close_it, +//GO(_IO_file_doallocate, +//GO(_IO_file_finish, +//GO(_IO_file_fopen, +//GO(_IO_file_init, +//DATA(_IO_file_jumps, +//GO(_IO_file_open, +//GO(_IO_file_overflow, +//GO(_IO_file_read, +//GO(_IO_file_seek, +//GO(_IO_file_seekoff, +//GO(_IO_file_setbuf, +//GO(_IO_file_stat, +//GO(_IO_file_sync, +//GO(_IO_file_underflow, +//GO(_IO_file_write, +//GO(_IO_file_xsputn, +//GO(_IO_flockfile, +//GO(_IO_flush_all, +//GO(_IO_flush_all_linebuffered, +//GO(_IO_fopen, +//GOW(_IO_fprintf, +//GO(_IO_fputs, +//GO(_IO_fread, +//GO(_IO_free_backup_area, +//GO(_IO_free_wbackup_area, +//GO(_IO_fsetpos, +//GO(_IO_fsetpos64, +//GO(_IO_ftell, +//GO(_IO_ftrylockfile, +//GO(_IO_funlockfile, +//GO(_IO_fwrite, +//GO(_IO_getc, +//GO(_IO_getline, +//GO(_IO_getline_info, +//GO(_IO_gets, +//GO(_IO_init, +//GO(_IO_init_marker, +//GO(_IO_init_wmarker, +//GO(_IO_iter_begin, +//GO(_IO_iter_end, +//GO(_IO_iter_file, +//GO(_IO_iter_next, +//GO(_IO_least_wmarker, +//GO(_IO_link_in, +//DATA(_IO_list_all, +//GO(_IO_list_lock, +//GO(_IO_list_resetlock, +//GO(_IO_list_unlock, +//GO(_IO_marker_delta, +//GO(_IO_marker_difference, +//GO(_IO_padn, +//GO(_IO_peekc_locked, +//GO(ioperm, +//GO(iopl, +//GO(_IO_popen, +//GO(_IO_printf, +//GO(_IO_proc_close, +//GO(_IO_proc_open, +//GO(_IO_putc, +//GO(_IO_puts, +//GO(_IO_remove_marker, +//GO(_IO_seekmark, +//GO(_IO_seekoff, +//GO(_IO_seekpos, +//GO(_IO_seekwmark, +//GO(_IO_setb, +//GO(_IO_setbuffer, +//GO(_IO_setvbuf, +//GO(_IO_sgetn, +//GO(_IO_sprintf, +//GO(_IO_sputbackc, +//GO(_IO_sputbackwc, +//GO(_IO_sscanf, +//GO(_IO_str_init_readonly, +//GO(_IO_str_init_static, +//GO(_IO_str_overflow, +//GO(_IO_str_pbackfail, +//GO(_IO_str_seekoff, +//GO(_IO_str_underflow, +//GO(_IO_sungetc, +//GO(_IO_sungetwc, +//GO(_IO_switch_to_get_mode, +//GO(_IO_switch_to_main_wget_area, +//GO(_IO_switch_to_wbackup_area, +//GO(_IO_switch_to_wget_mode, +//GO(_IO_ungetc, +//GO(_IO_un_link, +//GO(_IO_unsave_markers, +//GO(_IO_unsave_wmarkers, +//GO(_IO_vfprintf, +//GO(_IO_vfscanf, +//GO(_IO_vsprintf, +//GO(_IO_wdefault_doallocate, +//GO(_IO_wdefault_finish, +//GO(_IO_wdefault_pbackfail, +//GO(_IO_wdefault_uflow, +//GO(_IO_wdefault_xsgetn, +//GO(_IO_wdefault_xsputn, +//GO(_IO_wdoallocbuf, +//GO(_IO_wdo_write, +//DATA(_IO_wfile_jumps, +//GO(_IO_wfile_overflow, +//GO(_IO_wfile_seekoff, +//GO(_IO_wfile_sync, +//GO(_IO_wfile_underflow, +//GO(_IO_wfile_xsputn, +//GO(_IO_wmarker_delta, +//GO(_IO_wsetb, +//GO(iruserok, +//GO(iruserok_af, +//GO(isalnum, +//GO(__isalnum_l, +//GOW(isalnum_l, +//GO(isalpha, +//GO(__isalpha_l, +//GOW(isalpha_l, +//GO(isascii, +//GOW(__isascii_l, +//GO(isastream, +//GOW(isatty, +//GO(isblank, +//GO(__isblank_l, +//GOW(isblank_l, +//GO(iscntrl, +//GO(__iscntrl_l, +//GOW(iscntrl_l, +//GO(__isctype, +//GOW(isctype, +//GO(isdigit, +//GO(__isdigit_l, +//GOW(isdigit_l, +//GO(isfdtype, +//GO(isgraph, +//GO(__isgraph_l, +//GOW(isgraph_l, +//GO(__isinf, +//GOW(isinf, +//GO(__isinff, +//GOW(isinff, +//GO(__isinfl, +//GOW(isinfl, +//GO(islower, +//GO(__islower_l, +//GOW(islower_l, +//GO(__isnan, +//GOW(isnan, +//GO(__isnanf, +//GOW(isnanf, +//GO(__isnanl, +//GOW(isnanl, +//GO(__isoc99_fscanf, +//GO(__isoc99_fwscanf, +//GO(__isoc99_scanf, +//GO(__isoc99_sscanf, +//GO(__isoc99_swscanf, +//GO(__isoc99_vfscanf, +//GO(__isoc99_vfwscanf, +//GO(__isoc99_vscanf, +//GO(__isoc99_vsscanf, +//GO(__isoc99_vswscanf, +//GO(__isoc99_vwscanf, +//GO(__isoc99_wscanf, +//GO(isprint, +//GO(__isprint_l, +//GOW(isprint_l, +//GO(ispunct, +//GO(__ispunct_l, +//GOW(ispunct_l, +//GO(isspace, +//GO(__isspace_l, +//GOW(isspace_l, +//GO(isupper, +//GO(__isupper_l, +//GOW(isupper_l, +//GOW(iswalnum, +//GO(__iswalnum_l, +//GOW(iswalnum_l, +//GOW(iswalpha, +//GO(__iswalpha_l, +//GOW(iswalpha_l, +//GOW(iswblank, +//GO(__iswblank_l, +//GOW(iswblank_l, +//GOW(iswcntrl, +//GO(__iswcntrl_l, +//GOW(iswcntrl_l, +//GO(__iswctype, +//GOW(iswctype, +//GO(__iswctype_l, +//GOW(iswctype_l, +//GOW(iswdigit, +//GO(__iswdigit_l, +//GOW(iswdigit_l, +//GOW(iswgraph, +//GO(__iswgraph_l, +//GOW(iswgraph_l, +//GOW(iswlower, +//GO(__iswlower_l, +//GOW(iswlower_l, +//GOW(iswprint, +//GO(__iswprint_l, +//GOW(iswprint_l, +//GOW(iswpunct, +//GO(__iswpunct_l, +//GOW(iswpunct_l, +//GOW(iswspace, +//GO(__iswspace_l, +//GOW(iswspace_l, +//GOW(iswupper, +//GO(__iswupper_l, +//GOW(iswupper_l, +//GOW(iswxdigit, +//GO(__iswxdigit_l, +//GOW(iswxdigit_l, +//GO(isxdigit, +//GO(__isxdigit_l, +//GOW(isxdigit_l, +//GO(__ivaliduser, +//GO(jrand48, +//GOW(jrand48_r, +//GO(key_decryptsession, +//GO(key_decryptsession_pk, +//DATAB(__key_decryptsession_pk_LOCAL, +//GO(key_encryptsession, +//GO(key_encryptsession_pk, +//DATAB(__key_encryptsession_pk_LOCAL, +//GO(key_gendes, +//DATAB(__key_gendes_LOCAL, +//GO(key_get_conv, +//GO(key_secretkey_is_set, +//GO(key_setnet, +//GO(key_setsecret, +//GOW(kill, +//GO(killpg, +//GO(klogctl, +//GO(l64a, +//GO(labs, +//GO(lchmod, +//GOW(lchown, +//GOW(lckpwdf, +//GO(lcong48, +//GOW(lcong48_r, +//GOW(ldexp, +//GOW(ldexpf, +//GOW(ldexpl, +//GO(ldiv, +//GO(lfind, +//GO(lgetxattr, +//GO(__libc_alloca_cutoff, +//GO(__libc_allocate_once_slow, +//GO(__libc_allocate_rtsig, +//GO(__libc_allocate_rtsig_private, +//GO(__libc_alloc_buffer_alloc_array, +//GO(__libc_alloc_buffer_allocate, +//GO(__libc_alloc_buffer_copy_bytes, +//GO(__libc_alloc_buffer_copy_string, +//GO(__libc_alloc_buffer_create_failure, +//GO(__libc_calloc, +//GO(__libc_clntudp_bufcreate, +//GO(__libc_current_sigrtmax, +//GO(__libc_current_sigrtmax_private, +//GO(__libc_current_sigrtmin, +//GO(__libc_current_sigrtmin_private, +//GO(__libc_dlclose, +//GO(__libc_dlopen_mode, +//GO(__libc_dlsym, +//GO(__libc_dlvsym, +//GO(__libc_dynarray_at_failure, +//GO(__libc_dynarray_emplace_enlarge, +//GO(__libc_dynarray_finalize, +//GO(__libc_dynarray_resize, +//GO(__libc_dynarray_resize_clear, +//GO(__libc_fatal, +//GO(__libc_fcntl64, +//GO(__libc_fork, +//GO(__libc_free, +//GO(__libc_freeres, +//GO(__libc_ifunc_impl_list, +//GO(__libc_init_first, +//GO(__libc_longjmp, +//GO(__libc_mallinfo, +//GO(__libc_malloc, +//GO(__libc_mallopt, +//GO(__libc_memalign, +//GO(__libc_msgrcv, +//GO(__libc_msgsnd, +//GO(__libc_pread, +//GO(__libc_pthread_init, +//GO(__libc_pvalloc, +//GO(__libc_pwrite, +//GO(__libc_readline_unlocked, +//GO(__libc_realloc, +//GO(__libc_reallocarray, +//GO(__libc_rpc_getport, +//GO(__libc_sa_len, +//GO(__libc_scratch_buffer_grow, +//GO(__libc_scratch_buffer_grow_preserve, +//GO(__libc_scratch_buffer_set_array_size, +//GOW(__libc_secure_getenv, +//GO(__libc_siglongjmp, +//GO(__libc_start_main, +//GO(__libc_system, +//GO(__libc_thread_freeres, +//GO(__libc_valloc, +//GO(__libc_vfork, +//GOW(link, +//GO(linkat, +//GOW(listen, +//GO(listxattr, +//GO(llabs, +//GO(lldiv, +//GO(llistxattr, +//GO(llseek, +//DATAB(loc1, +//DATAB(loc2, +//GO(localeconv, +//GO(localtime, +//GOW(localtime_r, +//GO(lockf, +//GOW(lockf64, +//DATAB(locs, +//GOW(_longjmp, +//GOW(longjmp, +//GO(__longjmp_chk, +//GO(lrand48, +//GO(lrand48_r, +//GO(lremovexattr, +//GO(lsearch, +//GO(__lseek, +//GOW(lseek, +//GOW(lseek64, +//GO(lsetxattr, +//GO(lutimes, +//GO(__lxstat, +//GO(__lxstat64, +//GO(__madvise, +//GOW(madvise, +//GOW(makecontext, +//GOW(mallinfo, +//GO(malloc, +//GO(malloc_get_state, +//GOW(malloc_info, +//GO(malloc_set_state, +//GOW(malloc_stats, +//GOW(malloc_trim, +//GOW(malloc_usable_size, +//GOW(mallopt, +//DATAB(mallwatch, +//GO(mblen, +//GO(__mbrlen, +//GOW(mbrlen, +//GO(mbrtoc16, +//GOW(mbrtoc32, +//GO(__mbrtowc, +//GOW(mbrtowc, +//GOW(mbsinit, +//GOW(mbsnrtowcs, +//GO(__mbsnrtowcs_chk, +//GOW(mbsrtowcs, +//GO(__mbsrtowcs_chk, +//GO(mbstowcs, +//GO(__mbstowcs_chk, +//GO(mbtowc, +//GO(mcheck, +//GO(mcheck_check_all, +//GO(mcheck_pedantic, +//GO(_mcleanup, +//GO(_mcount, +//GOW(mcount, +//GOW(memalign, +//GOW(memccpy, +//GO(memcpy, +//GO(memfd_create, +//GO(memfrob, +//GOW(memmem, +//GO(__mempcpy_small, +//GO(__merge_grp, +//GO(mincore, +//GOW(mkdir, +//GO(mkdirat, +//GO(mkdtemp, +//GO(mkfifo, +//GO(mkfifoat, +//GO(mkostemp, +//GOW(mkostemp64, +//GO(mkostemps, +//GOW(mkostemps64, +//GO(mkstemp, +//GOW(mkstemp64, +//GO(mkstemps, +//GOW(mkstemps64, +//GO(__mktemp, +//GOW(mktemp, +//GO(mktime, +//GO(mlock, +//GO(mlock2, +//GO(mlockall, +//GO(__mmap, +//GOW(mmap, +//GOW(mmap64, +//GOW(modf, +//GOW(modff, +//GOW(modfl, +//GOW(modify_ldt, +//GOW(moncontrol, +//GO(__monstartup, +//GOW(monstartup, +//DATA(__morecore, +//GOW(mount, +//GO(mprobe, +//GO(__mprotect, +//GOW(mprotect, +//GO(mrand48, +//GO(mrand48_r, +//GOW(mremap, +//GO(msgctl, +//GO(msgget, +//GOW(msgrcv, +//GOW(msgsnd, +//GO(msync, +//GO(mtrace, +//GO(munlock, +//GO(munlockall, +//GO(__munmap, +//GOW(munmap, +//GO(muntrace, +GO(name_to_handle_at, iFipppi) +//GO(__nanosleep, +//GOW(nanosleep, +//GO(__nanosleep_nocancel, +//GO(__netlink_assert_response, +//GO(netname2host, +//GO(netname2user, +//GO(__newlocale, +//GOW(newlocale, +//GO(nfsservctl, +//GO(nftw, +//GO(nftw, +//GO(nftw64, +//GO(nftw64, +//GOW(ngettext, +//GO(nice, +//DATAB(_nl_domain_bindings, +//GO(nl_langinfo, +//GO(__nl_langinfo_l, +//GOW(nl_langinfo_l, +//DATAB(_nl_msg_cat_cntr, +//GO(nrand48, +//GOW(nrand48_r, +//GO(__nss_configure_lookup, +//GO(__nss_database_lookup, +//GO(__nss_disable_nscd, +//GO(_nss_files_parse_grent, +//GO(_nss_files_parse_pwent, +//GO(_nss_files_parse_sgent, +//GO(_nss_files_parse_spent, +//GO(__nss_group_lookup, +//GO(__nss_group_lookup2, +//GO(__nss_hash, +//GO(__nss_hostname_digits_dots, +//GO(__nss_hosts_lookup, +//GO(__nss_hosts_lookup2, +//GO(__nss_lookup, +//GO(__nss_lookup_function, +//GO(__nss_next, +//GO(__nss_next2, +//GO(__nss_passwd_lookup, +//GO(__nss_passwd_lookup2, +//GO(__nss_services_lookup2, +//GOW(ntohl, +//GOW(ntohs, +//GOW(ntp_adjtime, +//GO(ntp_gettime, +//GO(ntp_gettimex, +//DATAB(_null_auth, +//DATAB(_obstack, +//GO(_obstack_allocated_p, +//DATA(obstack_alloc_failed_handler, +//GO(_obstack_begin, +//GO(_obstack_begin_1, +//DATA(obstack_exit_failure, +//GO(_obstack_free, +//GO(obstack_free, +//GO(_obstack_memory_used, +//GO(_obstack_newchunk, +//GOW(obstack_printf, +//GO(__obstack_printf_chk, +//GOW(obstack_vprintf, +//GO(__obstack_vprintf_chk, +//GOW(on_exit, +//GOW(__open, +//GOW(open, +//GO(__open_2, +//GOW(__open64, +//GOW(open64, +//GO(__open64_2, +//GO(__open64_nocancel, +//GOW(openat, +//GO(__openat_2, +//GOW(openat64, +//GO(__openat64_2, +//GO(open_by_handle_at, +//GO(__open_catalog, +//GOW(opendir, +//GO(openlog, +//GOW(open_memstream, +//GO(__open_nocancel, +//GO(open_wmemstream, +//DATAB(optarg, +//DATA(opterr, +//DATA(optind, +//DATA(optopt, +//GO(__overflow, +//GO(parse_printf_format, +//GO(passwd2des, +//GOW(pathconf, +//GOW(pause, +//GO(__pause_nocancel, +//GO(pclose, +//GO(perror, +//GOW(personality, +//GO(__pipe, +//GOW(pipe, +//GOW(pipe2, +//GO(pivot_root, +//GO(pkey_alloc, +//GO(pkey_free, +//GO(pkey_get, +//GO(pkey_mprotect, +//GO(pkey_set, +//GO(pmap_getmaps, +//GO(pmap_getport, +//GO(pmap_rmtcall, +//GO(pmap_set, +//GO(pmap_unset, +//GO(__poll, +//GOW(poll, +//GO(__poll_chk, +//GO(popen, +//GO(posix_fadvise, +//GOW(posix_fadvise64, +//GO(posix_fallocate, +//GO(posix_fallocate64, +//GO(__posix_getopt, +//GO(posix_madvise, +//GOW(posix_memalign, +//GOW(posix_openpt, +//GO(posix_spawn, +//GO(posix_spawn, +//GO(posix_spawnattr_destroy, +//GO(posix_spawnattr_getflags, +//GO(posix_spawnattr_getpgroup, +//GO(posix_spawnattr_getschedparam, +//GO(posix_spawnattr_getschedpolicy, +//GO(posix_spawnattr_getsigdefault, +//GO(posix_spawnattr_getsigmask, +//GO(posix_spawnattr_init, +//GO(posix_spawnattr_setflags, +//GO(posix_spawnattr_setpgroup, +//GO(posix_spawnattr_setschedparam, +//GO(posix_spawnattr_setschedpolicy, +//GO(posix_spawnattr_setsigdefault, +//GO(posix_spawnattr_setsigmask, +//GO(posix_spawn_file_actions_addclose, +//GO(posix_spawn_file_actions_adddup2, +//GO(posix_spawn_file_actions_addopen, +//GO(posix_spawn_file_actions_destroy, +//GO(posix_spawn_file_actions_init, +//GO(posix_spawnp, +//GO(posix_spawnp, +//GO(ppoll, +//GO(__ppoll_chk, +//GOW(prctl, +//GOW(pread, +//GOW(__pread64, +//GOW(pread64, +//GO(__pread64_chk, +//GO(__pread_chk, +//GO(preadv, +//GO(preadv2, +//GO(preadv64, +//GO(preadv64v2, +//GO(printf, +//GO(__printf_chk, +//GO(__printf_fp, +//GO(printf_size, +//GO(printf_size_info, +//GO(prlimit, +//GOW(prlimit64, +//GO(process_vm_readv, +//GO(process_vm_writev, +//GOW(profil, +//GO(__profile_frequency, +//DATA(__progname, +//DATA(__progname_full, +//GOW(pselect, +//GO(psiginfo, +//GO(psignal, +//GO(pthread_attr_destroy, +//GO(pthread_attr_getdetachstate, +//GO(pthread_attr_getinheritsched, +//GO(pthread_attr_getschedparam, +//GO(pthread_attr_getschedpolicy, +//GO(pthread_attr_getscope, +//GO(pthread_attr_init, +//GO(pthread_attr_setdetachstate, +//GO(pthread_attr_setinheritsched, +//GO(pthread_attr_setschedparam, +//GO(pthread_attr_setschedpolicy, +//GO(pthread_attr_setscope, +//GO(pthread_condattr_destroy, +//GO(pthread_condattr_init, +//GO(pthread_cond_broadcast, +//GO(pthread_cond_broadcast, +//GO(pthread_cond_destroy, +//GO(pthread_cond_destroy, +//GO(pthread_cond_init, +//GO(pthread_cond_init, +//GO(pthread_cond_signal, +//GO(pthread_cond_signal, +//GO(pthread_cond_timedwait, +//GO(pthread_cond_timedwait, +//GO(pthread_cond_wait, +//GO(pthread_cond_wait, +//GO(pthread_equal, +//GO(pthread_exit, +//GO(pthread_getschedparam, +//GO(pthread_mutex_destroy, +//GO(pthread_mutex_init, +//GO(pthread_mutex_lock, +//GO(pthread_mutex_unlock, +//GO(pthread_self, +//GO(pthread_setcancelstate, +//GO(pthread_setcanceltype, +//GO(pthread_setschedparam, +//GO(ptrace, +//GO(ptsname, +//GOW(ptsname_r, +//GO(__ptsname_r_chk, +//GOW(putc, +//GO(putchar, +//GO(putchar_unlocked, +//GOW(putc_unlocked, +//GO(putenv, +//GO(putgrent, +//GO(putmsg, +//GO(putpmsg, +//GO(putpwent, +//GOW(puts, +//GO(putsgent, +//GO(putspent, +//GOW(pututline, +//GO(pututxline, +//GO(putw, +//GO(putwc, +//GO(putwchar, +//GO(putwchar_unlocked, +//GO(putwc_unlocked, +//GOW(pvalloc, +//GOW(pwrite, +//GOW(__pwrite64, +//GOW(pwrite64, +//GO(pwritev, +//GO(pwritev2, +//GO(pwritev64, +//GO(pwritev64v2, +//GO(qecvt, +//GOW(qecvt_r, +//GO(qfcvt, +//GOW(qfcvt_r, +//GO(qgcvt, +//GO(qsort, +//GOW(qsort_r, +//GO(query_module, +//GO(quick_exit, +//GO(quick_exit, +//GO(quotactl, +//GO(raise, +//GO(rand, +//GOW(random, +//GOW(random_r, +//GO(rand_r, +//GO(rcmd, +//GO(rcmd_af, +//DATAB(__rcmd_errstr, +//GO(__read, +//GO(read, +//GOW(readahead, +//GO(__read_chk, +//GOW(readdir, +//GOW(readdir64, +//GOW(readdir64_r, +//GOW(readdir_r, +//GOW(readlink, +//GO(readlinkat, +//GO(__readlinkat_chk, +//GO(__readlink_chk, +//GO(__read_nocancel, +//GOW(readv, +//GO(realloc, +//GOW(reallocarray, +//GO(realpath, +//GO(realpath, +//GO(__realpath_chk, +//GO(reboot, +//GOW(re_comp, +//GOW(re_compile_fastmap, +//GOW(re_compile_pattern, +//GOW(__recv, +//GOW(recv, +//GO(__recv_chk, +//GOW(recvfrom, +//GO(__recvfrom_chk, +//GO(recvmmsg, +//GOW(recvmsg, +//GOW(re_exec, +//GOW(regcomp, +//GOW(regerror, +//GO(regexec, +//GO(regexec, +//GOW(regfree, +//GO(__register_atfork, +//GOW(register_printf_function, +//GOW(register_printf_modifier, +//GOW(register_printf_specifier, +//GOW(register_printf_type, +//GO(registerrpc, +//GOW(remap_file_pages, +//GOW(re_match, +//GOW(re_match_2, +//DATA(re_max_failures, +//GO(remove, +//GO(removexattr, +//GO(remque, +//GO(rename, +//GOW(renameat, +//GOW(renameat2, +//DATAB(_res, +//GOW(re_search, +//GOW(re_search_2, +//GOW(re_set_registers, +//GOW(re_set_syntax, +//DATAB(_res_hconf, +//GO(__res_iclose, +//GO(__res_init, +//GO(__res_nclose, +//GO(__res_ninit, +//GO(__resolv_context_get, +//GO(__resolv_context_get_override, +//GO(__resolv_context_get_preinit, +//GO(__resolv_context_put, +//DATA(__resp, +//GO(__res_randomid, +//GO(__res_state, +//DATAB(re_syntax_options, +//GOW(revoke, +//GO(rewind, +//GOW(rewinddir, +//GO(rexec, +//GO(rexec_af, +//DATAB(rexecoptions, +//GOW(rmdir, +//DATAB(rpc_createerr, +//GO(_rpc_dtablesize, +//GO(__rpc_thread_createerr, +//GO(__rpc_thread_svc_fdset, +//GO(__rpc_thread_svc_max_pollfd, +//GO(__rpc_thread_svc_pollfd, +//GO(rpmatch, +//GO(rresvport, +//GO(rresvport_af, +//GO(rtime, +//GO(ruserok, +//GO(ruserok_af, +//GO(ruserpass, +//GO(__sbrk, +//GOW(sbrk, +//GOW(scalbn, +//GOW(scalbnf, +//GOW(scalbnl, +//GOW(scandir, +//GOW(scandir64, +//GOW(scandirat, +//GO(scandirat64, +//GO(scanf, +//GO(__sched_cpualloc, +//GO(__sched_cpufree, +//GO(sched_getaffinity, +//GO(sched_getaffinity, +//GO(sched_getcpu, +//GO(__sched_getparam, +//GOW(sched_getparam, +//GO(__sched_get_priority_max, +//GOW(sched_get_priority_max, +//GO(__sched_get_priority_min, +//GOW(sched_get_priority_min, +//GO(__sched_getscheduler, +//GOW(sched_getscheduler, +//GOW(sched_rr_get_interval, +//GO(sched_setaffinity, +//GO(sched_setaffinity, +//GOW(sched_setparam, +//GO(__sched_setscheduler, +//GOW(sched_setscheduler, +//GO(__sched_yield, +//GOW(sched_yield, +//GOW(__secure_getenv, +//GOW(secure_getenv, +//GO(seed48, +//GOW(seed48_r, +//GO(seekdir, +//GO(__select, +//GOW(select, +//GO(semctl, +//GO(semget, +//GO(semop, +//GO(semtimedop, +//GO(__send, +//GOW(send, +//GO(sendfile, +//GOW(sendfile64, +//GO(__sendmmsg, +//GOW(sendmmsg, +//GOW(sendmsg, +//GOW(sendto, +//GO(setaliasent, +//GO(setbuf, +//GOW(setbuffer, +//GOW(setcontext, +//GO(setdomainname, +//GO(setegid, +//GOW(setenv, +//GO(_seterr_reply, +//GO(seteuid, +//GO(setfsent, +//GO(setfsgid, +//GO(setfsuid, +//GOW(setgid, +//GO(setgrent, +//GO(setgroups, +//GO(sethostent, +//GO(sethostid, +//GO(sethostname, +//GO(setipv4sourcefilter, +//GOW(setitimer, +//GO(_setjmp, +//GO(setjmp, +//GO(setlinebuf, +//GO(setlocale, +//GO(setlogin, +//GO(setlogmask, +//GO(__setmntent, +//GOW(setmntent, +//GO(setnetent, +//GO(setnetgrent, +//GO(setns, +//GO(__setpgid, +//GOW(setpgid, +//GO(setpgrp, +//GOW(setpriority, +//GO(setprotoent, +//GO(setpwent, +//GOW(setregid, +//GOW(setresgid, +//GOW(setresuid, +//GOW(setreuid, +//GOW(setrlimit, +//GOW(setrlimit64, +//GO(setrpcent, +//GO(setservent, +//GO(setsgent, +//GOW(setsid, +//GOW(setsockopt, +//GO(setsourcefilter, +//GO(setspent, +//GOW(setstate, +//GOW(setstate_r, +//GOW(settimeofday, +//GOW(setttyent, +//GOW(setuid, +//GO(setusershell, +//GOW(setutent, +//GO(setutxent, +//GOW(setvbuf, +//GO(setxattr, +//GO(sgetsgent, +//GOW(sgetsgent_r, +//GO(sgetspent, +//GOW(sgetspent_r, +//GO(shmat, +//GO(shmctl, +//GO(shmdt, +//GO(shmget, +//GOW(shutdown, +//GOW(__sigaction, +//GOW(sigaction, +//GO(__sigaddset, +//GO(sigaddset, +//GOW(sigaltstack, +//GO(sigandset, +//GOW(sigblock, +//GO(__sigdelset, +//GO(sigdelset, +//GO(sigemptyset, +//GO(sigfillset, +//GO(siggetmask, +//GO(sighold, +//GO(sigignore, +//GO(siginterrupt, +//GO(sigisemptyset, +//GO(__sigismember, +//GO(sigismember, +//GOW(siglongjmp, +//GOW(signal, +//GO(signalfd, +//GO(__signbit, +//GO(__signbitf, +//GO(__signbitl, +//GO(sigorset, +//GO(__sigpause, +//GOW(sigpause, +//GO(sigpending, +//GOW(sigprocmask, +//GOW(sigqueue, +//GO(sigrelse, +//GOW(sigreturn, +//GO(sigset, +//GO(__sigsetjmp, +//GOW(sigsetmask, +//GO(sigstack, +//GO(__sigsuspend, +//GOW(sigsuspend, +//GO(__sigtimedwait, +//GOW(sigtimedwait, +//GO(sigvec, +//GOW(sigwait, +//GOW(sigwaitinfo, +//GOW(sleep, +//GO(__snprintf, +//GOW(snprintf, +//GO(__snprintf_chk, +//GO(sockatmark, +//GO(__socket, +//GOW(socket, +//GOW(socketpair, +//GO(splice, +//GO(sprintf, +//GO(__sprintf_chk, +//GOW(sprofil, +//GOW(srand, +//GO(srand48, +//GOW(srand48_r, +//GOW(srandom, +//GOW(srandom_r, +//GO(sscanf, +//GOW(ssignal, +//GO(sstk, +GOM(__stack_chk_fail, vFE) +//GO(__statfs, +//GOW(statfs, +//GOW(statfs64, +//GOW(statvfs, +//GOW(statvfs64, +//GO(statx, +//DATA(stderr, +//DATA(stdin, +//DATA(stdout, +//GOW(step, +//GO(stime, +//GO(__stpcpy_chk, +//GO(__stpcpy_small, +//GO(__stpncpy_chk, +//GO(__strcasestr, +//GOW(strcasestr, +//GO(__strcat_chk, +//GO(strcoll, +//GO(__strcoll_l, +//GOW(strcoll_l, +//GO(__strcpy_chk, +//GO(__strcpy_small, +//GO(__strcspn_c1, +//GO(__strcspn_c2, +//GO(__strcspn_c3, +//GO(__strdup, +//GOW(strdup, +//GO(strerror, +//GO(strerror_l, +//GO(__strerror_r, +//GOW(strerror_r, +//GO(strfmon, +//GO(__strfmon_l, +//GOW(strfmon_l, +//GO(strfromd, +//GO(strfromf, +//GO(strfromf128, +//GOW(strfromf32, +//GOW(strfromf32x, +//GOW(strfromf64, +//GOW(strfromf64x, +//GO(strfroml, +//GO(strfry, +//GO(strftime, +//GO(__strftime_l, +//GOW(strftime_l, +//GO(__strncat_chk, +//GO(__strncpy_chk, +//GO(__strndup, +//GOW(strndup, +//GO(__strpbrk_c2, +//GO(__strpbrk_c3, +//GO(strptime, +//GOW(strptime_l, +//GOW(strsep, +//GO(__strsep_1c, +//GO(__strsep_2c, +//GO(__strsep_3c, +//GO(__strsep_g, +//GO(strsignal, +//GO(__strspn_c1, +//GO(__strspn_c2, +//GO(__strspn_c3, +//GO(strtod, +//GO(__strtod_internal, +//GO(__strtod_l, +//GOW(strtod_l, +//GO(__strtod_nan, +//GO(strtof, +//GO(strtof128, +//GO(__strtof128_internal, +//GOW(strtof128_l, +//GO(__strtof128_nan, +//GOW(strtof32, +//GOW(strtof32_l, +//GOW(strtof32x, +//GOW(strtof32x_l, +//GOW(strtof64, +//GOW(strtof64_l, +//GOW(strtof64x, +//GOW(strtof64x_l, +//GO(__strtof_internal, +//GO(__strtof_l, +//GOW(strtof_l, +//GO(__strtof_nan, +//GO(strtoimax, +//GO(strtok, +//GO(__strtok_r, +//GOW(strtok_r, +//GO(__strtok_r_1c, +//GOW(strtol, +//GO(strtold, +//GO(__strtold_internal, +//GO(__strtold_l, +//GOW(strtold_l, +//GO(__strtold_nan, +//GO(__strtol_internal, +//GO(__strtol_l, +//GOW(strtol_l, +//GOW(strtoll, +//GO(__strtoll_internal, +//GOW(__strtoll_l, +//GOW(strtoll_l, +//GOW(strtoq, +//GOW(strtoul, +//GO(__strtoul_internal, +//GO(__strtoul_l, +//GOW(strtoul_l, +//GOW(strtoull, +//GO(__strtoull_internal, +//GOW(__strtoull_l, +//GOW(strtoull_l, +//GO(strtoumax, +//GOW(strtouq, +//GO(__strverscmp, +//GOW(strverscmp, +//GO(strxfrm, +//GO(__strxfrm_l, +//GOW(strxfrm_l, +//GO(stty, +//DATAB(svcauthdes_stats, +//GO(svcerr_auth, +//GO(svcerr_decode, +//GO(svcerr_noproc, +//GO(svcerr_noprog, +//GO(svcerr_progvers, +//GO(svcerr_systemerr, +//GO(svcerr_weakauth, +//GO(svc_exit, +//GO(svcfd_create, +//DATAB(svc_fdset, +//GO(svc_getreq, +//GO(svc_getreq_common, +//GO(svc_getreq_poll, +//GO(svc_getreqset, +//DATAB(svc_max_pollfd, +//DATAB(svc_pollfd, +//GO(svcraw_create, +//GO(svc_register, +//GO(svc_run, +//GO(svc_sendreply, +//GO(svctcp_create, +//GO(svcudp_bufcreate, +//GO(svcudp_create, +//GO(svcudp_enablecache, +//GO(svcunix_create, +//GO(svcunixfd_create, +//GO(svc_unregister, +//GO(swab, +//GOW(swapcontext, +//GOW(swapoff, +//GOW(swapon, +//GO(swprintf, +//GO(__swprintf_chk, +//GO(swscanf, +//GOW(symlink, +//GO(symlinkat, +//GO(sync, +//GO(sync_file_range, +//GO(syncfs, +//GO(syscall, +//GO(__sysconf, +//GOW(sysconf, +//GO(__sysctl, +//GOW(sysctl, +//DATA(_sys_errlist, +//DATA(_sys_errlist, +//DATA(_sys_errlist, +//DATA(_sys_errlist, +//DATA(sys_errlist, +//DATA(sys_errlist, +//DATA(sys_errlist, +//DATA(sys_errlist, +//GOW(sysinfo, +//GO(syslog, +//GO(__syslog_chk, +//DATA(sys_sigabbrev, +//DATA(sys_sigabbrev, +//DATA(_sys_siglist, +//DATA(_sys_siglist, +//DATA(sys_siglist, +//DATA(sys_siglist, +//GOW(system, +//GO(__sysv_signal, +//GOW(sysv_signal, +//GOW(tcdrain, +//GO(tcflow, +//GO(tcflush, +//GOW(tcgetattr, +//GO(tcgetpgrp, +//GO(tcgetsid, +//GO(tcsendbreak, +//GO(tcsetattr, +//GO(tcsetpgrp, +//GO(__tdelete, +//GOW(tdelete, +//GOW(tdestroy, +//GO(tee, +//GO(telldir, +//GO(tempnam, +//GOW(textdomain, +//GO(__tfind, +//GOW(tfind, +//GO(thrd_current, +//GO(thrd_equal, +//GO(thrd_sleep, +//GO(thrd_yield, +//GO(timegm, +//GOW(timelocal, +//GO(timerfd_create, +//GO(timerfd_gettime, +//GO(timerfd_settime, +//GOW(times, +//GO(timespec_get, +//DATAB(__timezone, +//GO(tmpfile, +//GOW(tmpfile64, +//GO(tmpnam, +//GO(tmpnam_r, +//GO(toascii, +//GOW(__toascii_l, +//GO(_tolower, +//GO(tolower, +//GO(__tolower_l, +//GOW(tolower_l, +//GO(_toupper, +//GO(toupper, +//GO(__toupper_l, +//GOW(toupper_l, +//GO(__towctrans, +//GOW(towctrans, +//GO(__towctrans_l, +//GOW(towctrans_l, +//GOW(towlower, +//GO(__towlower_l, +//GOW(towlower_l, +//GOW(towupper, +//GO(__towupper_l, +//GOW(towupper_l, +//GO(tr_break, +//GOW(truncate, +//GOW(truncate64, +//GO(__tsearch, +//GOW(tsearch, +//GO(ttyname, +//GOW(ttyname_r, +//GO(__ttyname_r_chk, +//GO(ttyslot, +//GO(__twalk, +//GOW(twalk, +DATA(__tzname, 4) +GOW(tzset, vFv) +//GO(ualarm, +//GO(__uflow, +//GOW(ulckpwdf, +//GOW(ulimit, +//GOW(umask, +//GOW(umount, +//GOW(umount2, +//GOW(uname, +//GO(__underflow, +//GOW(ungetc, +//GO(ungetwc, +//GOW(unlink, +//GO(unlinkat, +//GO(unlockpt, +//GOW(unsetenv, +//GO(unshare, +//GOW(updwtmp, +//GO(updwtmpx, +//GO(uselib, +//GO(__uselocale, +//GOW(uselocale, +//GO(user2netname, +//GO(usleep, +//GO(ustat, +//GO(utime, +//GO(utimensat, +//GOW(utimes, +//GOW(utmpname, +//GO(utmpxname, +//GOW(valloc, +//GOW(vasprintf, +//GO(__vasprintf_chk, +//GOW(vdprintf, +//GO(__vdprintf_chk, +//GO(verr, +//GO(verrx, +//GOW(versionsort, +//GOW(versionsort64, +//GO(__vfork, +//GOW(vfork, +//GO(vfprintf, +//GO(__vfprintf_chk, +//GO(__vfscanf, +//GOW(vfscanf, +//GOW(vfwprintf, +//GO(__vfwprintf_chk, +//GOW(vfwscanf, +//GO(vhangup, +//GO(vlimit, +//GO(vmsplice, +//GO(vprintf, +//GO(__vprintf_chk, +//GOW(vscanf, +//GOW(__vsnprintf, +//GOW(vsnprintf, +//GO(__vsnprintf_chk, +//GOW(vsprintf, +//GO(__vsprintf_chk, +//GOW(__vsscanf, +//GOW(vsscanf, +//GOW(vswprintf, +//GO(__vswprintf_chk, +//GO(vswscanf, +//GO(vsyslog, +//GO(__vsyslog_chk, +//GO(vtimes, +//GO(vwarn, +//GO(vwarnx, +//GO(vwprintf, +//GO(__vwprintf_chk, +//GO(vwscanf, +//GOW(__wait, +//GOW(wait, +//GOW(wait3, +//GOW(wait4, +//GOW(waitid, +//GO(__waitpid, +//GOW(waitpid, +//GO(warn, +//GO(warnx, +//GOW(wcpcpy, +//GO(__wcpcpy_chk, +//GOW(wcpncpy, +//GO(__wcpncpy_chk, +//GOW(wcrtomb, +//GO(__wcrtomb_chk, +//GOW(wcscasecmp, +//GO(__wcscasecmp_l, +//GOW(wcscasecmp_l, +//GOW(wcscat, +//GO(__wcscat_chk, +//GOW(wcschrnul, +//GOW(wcscoll, +//GO(__wcscoll_l, +//GOW(wcscoll_l, +//GO(__wcscpy_chk, +//GO(wcscspn, +//GO(wcsdup, +//GO(wcsftime, +//GO(__wcsftime_l, +//GOW(wcsftime_l, +//GOW(wcsncasecmp, +//GO(__wcsncasecmp_l, +//GOW(wcsncasecmp_l, +//GO(wcsncat, +//GO(__wcsncat_chk, +//GOW(wcsncpy, +//GO(__wcsncpy_chk, +//GOW(wcsnrtombs, +//GO(__wcsnrtombs_chk, +//GO(wcspbrk, +//GOW(wcsrtombs, +//GO(__wcsrtombs_chk, +//GO(wcsspn, +//GO(wcsstr, +//GO(wcstod, +//GO(__wcstod_internal, +//GO(__wcstod_l, +//GOW(wcstod_l, +//GO(wcstof, +//GO(wcstof128, +//GO(__wcstof128_internal, +//GOW(wcstof128_l, +//GOW(wcstof32, +//GOW(wcstof32_l, +//GOW(wcstof32x, +//GOW(wcstof32x_l, +//GOW(wcstof64, +//GOW(wcstof64_l, +//GOW(wcstof64x, +//GOW(wcstof64x_l, +//GO(__wcstof_internal, +//GO(__wcstof_l, +//GOW(wcstof_l, +//GO(wcstoimax, +//GO(wcstok, +//GOW(wcstol, +//GO(wcstold, +//GO(__wcstold_internal, +//GO(__wcstold_l, +//GOW(wcstold_l, +//GO(__wcstol_internal, +//GO(__wcstol_l, +//GOW(wcstol_l, +//GOW(wcstoll, +//GO(__wcstoll_internal, +//GOW(__wcstoll_l, +//GOW(wcstoll_l, +//GO(wcstombs, +//GO(__wcstombs_chk, +//GOW(wcstoq, +//GOW(wcstoul, +//GO(__wcstoul_internal, +//GO(__wcstoul_l, +//GOW(wcstoul_l, +//GOW(wcstoull, +//GO(__wcstoull_internal, +//GOW(__wcstoull_l, +//GOW(wcstoull_l, +//GO(wcstoumax, +//GOW(wcstouq, +//GOW(wcswcs, +//GO(wcswidth, +//GO(wcsxfrm, +//GO(__wcsxfrm_l, +//GOW(wcsxfrm_l, +//GO(wctob, +//GO(wctomb, +//GO(__wctomb_chk, +//GOW(wctrans, +//GO(__wctrans_l, +//GOW(wctrans_l, +//GOW(wctype, +//GO(__wctype_l, +//GOW(wctype_l, +//GO(wcwidth, +//GOW(wmemcpy, +//GO(__wmemcpy_chk, +//GOW(wmemmove, +//GO(__wmemmove_chk, +//GOW(wmempcpy, +//GO(__wmempcpy_chk, +//GO(wordexp, +//GO(wordfree, +//GO(__woverflow, +//GO(wprintf, +//GO(__wprintf_chk, +//GOW(__write, +//GOW(write, +//GO(__write_nocancel, +//GOW(writev, +//GO(wscanf, +//GO(__wuflow, +//GO(__wunderflow, +//GO(xdecrypt, +//GO(xdr_accepted_reply, +//GO(xdr_array, +//GO(xdr_authdes_cred, +//GO(xdr_authdes_verf, +//GO(xdr_authunix_parms, +//GO(xdr_bool, +//GO(xdr_bytes, +//GO(xdr_callhdr, +//GO(xdr_callmsg, +//GO(xdr_char, +//GO(xdr_cryptkeyarg, +//GO(xdr_cryptkeyarg2, +//GO(xdr_cryptkeyres, +//GO(xdr_des_block, +//GO(xdr_double, +//GO(xdr_enum, +//GO(xdr_float, +//GO(xdr_free, +//GO(xdr_getcredres, +//GO(xdr_hyper, +//GO(xdr_int, +//GO(xdr_int16_t, +//GO(xdr_int32_t, +//GO(xdr_int64_t, +//GO(xdr_int8_t, +//GO(xdr_keybuf, +//GO(xdr_key_netstarg, +//GO(xdr_key_netstres, +//GO(xdr_keystatus, +//GO(xdr_long, +//GO(xdr_longlong_t, +//GO(xdrmem_create, +//GO(xdr_netnamestr, +//GO(xdr_netobj, +//GO(xdr_opaque, +//GO(xdr_opaque_auth, +//GO(xdr_pmap, +//GO(xdr_pmaplist, +//GO(xdr_pointer, +//GO(xdr_quad_t, +//GO(xdrrec_create, +//GO(xdrrec_endofrecord, +//GO(xdrrec_eof, +//GO(xdrrec_skiprecord, +//GO(xdr_reference, +//GO(xdr_rejected_reply, +//GO(xdr_replymsg, +//GO(xdr_rmtcall_args, +//GO(xdr_rmtcallres, +//GO(xdr_short, +//GO(xdr_sizeof, +//GO(xdrstdio_create, +//GO(xdr_string, +//GO(xdr_u_char, +//GO(xdr_u_hyper, +//GO(xdr_u_int, +//GO(xdr_uint16_t, +//GO(xdr_uint32_t, +//GO(xdr_uint64_t, +//GO(xdr_uint8_t, +//GO(xdr_u_long, +//GO(xdr_u_longlong_t, +//GO(xdr_union, +//GO(xdr_unixcred, +//GO(xdr_u_quad_t, +//GO(xdr_u_short, +//GO(xdr_vector, +//GO(xdr_void, +//GO(xdr_wrapstring, +//GO(xencrypt, +//GO(__xmknod, +//GO(__xmknodat, +//GO(__xpg_basename, +//GOW(__xpg_sigpause, +//GO(__xpg_strerror_r, +//GO(xprt_register, +//GO(xprt_unregister, +//GO(__xstat, +//GO(__xstat64, + +GOM(__register_frame_info, vFpp) // faked function +GOM(__deregister_frame_info, pFp) diff --git a/src/wrapped/wrappedlibdl.c b/src/wrapped/wrappedlibdl.c new file mode 100755 index 00000000..95c23f7f --- /dev/null +++ b/src/wrapped/wrappedlibdl.c @@ -0,0 +1,415 @@ +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <elf.h> + +#include "wrappedlibs.h" + +#include "debug.h" +#include "wrapper.h" +#include "bridge.h" +#include "librarian/library_private.h" +#include "emu/x64emu_private.h" +#include "library.h" +#include "librarian.h" +#include "box64context.h" +#include "elfloader.h" +#include "elfs/elfloader_private.h" + +typedef struct dlprivate_s { + library_t **libs; + size_t *count; + size_t *dlopened; + size_t lib_sz; + size_t lib_cap; + char* last_error; +} dlprivate_t; + +dlprivate_t *NewDLPrivate() { + dlprivate_t* dl = (dlprivate_t*)calloc(1, sizeof(dlprivate_t)); + return dl; +} +void FreeDLPrivate(dlprivate_t **lib) { + free((*lib)->last_error); + free(*lib); +} + +void* my_dlopen(x64emu_t* emu, void *filename, int flag) EXPORT; +void* my_dlmopen(x64emu_t* emu, void* mlid, void *filename, int flag) EXPORT; +char* my_dlerror(x64emu_t* emu) EXPORT; +void* my_dlsym(x64emu_t* emu, void *handle, void *symbol) EXPORT; +int my_dlclose(x64emu_t* emu, void *handle) EXPORT; +int my_dladdr(x64emu_t* emu, void *addr, void *info) EXPORT; +void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, void *version) EXPORT; +int my_dlinfo(x64emu_t* emu, void* handle, int request, void* info) EXPORT; + +#define LIBNAME libdl +const char* libdlName = "libdl.so.2"; + +// define all standard library functions +#include "wrappedlib_init.h" + +#define CLEARERR if(dl->last_error) free(dl->last_error); dl->last_error = NULL; + +extern int box64_zoom; +// Implementation +void* my_dlopen(x64emu_t* emu, void *filename, int flag) +{ + //void *dlopen(const char *filename, int flag); + // TODO, handling special values for filename, like RTLD_SELF? + // TODO, handling flags? + library_t *lib = NULL; + dlprivate_t *dl = emu->context->dlprivate; + size_t dlopened = 0; + int is_local = (flag&0x100)?0:1; // if not global, then local, and that means symbols are not put in the global "pot" for pther libs + CLEARERR + if(filename) { + char* rfilename = (char*)filename; + if(box64_zoom && strstr(rfilename, "/libturbojpeg.so")) { + void* sys = my_dlopen(emu, "libturbojpeg.so.0", flag); + if(sys) + return sys; + } + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + } + printf_log(LOG_DEBUG, "Call to dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + // check if alread dlopenned... + for (size_t i=0; i<dl->lib_sz; ++i) { + if(IsSameLib(dl->libs[i], rfilename)) { + if(dl->count[i]==0 && dl->dlopened[i]) { // need to lauch init again! + int idx = GetElfIndex(dl->libs[i]); + if(idx!=-1) { + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlopen: Recycling, calling Init for %p (%s)\n", (void*)(i+1), rfilename); + } + ReloadLibrary(dl->libs[i], emu); // reset memory image, redo reloc, run inits + } + } + dl->count[i] = dl->count[i]+1; + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlopen: Recycling %s/%p count=%ld (dlopened=%ld, elf_index=%d)\n", rfilename, (void*)(i+1), dl->count[i], dl->dlopened[i], GetElfIndex(dl->libs[i])); + } + return (void*)(i+1); + } + } + dlopened = (GetLibInternal(rfilename)==NULL); + // Then open the lib + if(AddNeededLib(NULL, NULL, is_local, rfilename, emu->context, emu)) { + printf_log(LOG_INFO, "Warning: Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag); + return NULL; + } + lib = GetLibInternal(rfilename); + } else { + // check if already dlopenned... + for (size_t i=0; i<dl->lib_sz; ++i) { + if(!dl->libs[i]) { + dl->count[i] = dl->count[i]+1; + return (void*)(i+1); + } + } + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlopen(NULL, %X)\n", flag); + } + printf_log(LOG_DEBUG, "Call to dlopen(NULL, %X)\n", flag); + } + //get the lib and add it to the collection + + if(dl->lib_sz == dl->lib_cap) { + dl->lib_cap += 4; + dl->libs = (library_t**)realloc(dl->libs, sizeof(library_t*)*dl->lib_cap); + dl->count = (size_t*)realloc(dl->count, sizeof(size_t)*dl->lib_cap); + dl->dlopened = (size_t*)realloc(dl->dlopened, sizeof(size_t)*dl->lib_cap); + // memset count... + memset(dl->count+dl->lib_sz, 0, (dl->lib_cap-dl->lib_sz)*sizeof(size_t)); + } + dl->libs[dl->lib_sz] = lib; + dl->count[dl->lib_sz] = dl->count[dl->lib_sz]+1; + dl->dlopened[dl->lib_sz] = dlopened; + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlopen: New handle %p (%s), dlopened=%ld\n", (void*)(dl->lib_sz+1), (char*)filename, dlopened); + } + return (void*)(++dl->lib_sz); +} +void* my_dlmopen(x64emu_t* emu, void* lmid, void *filename, int flag) +{ + if(lmid) { + printf_log(LOG_INFO, "Warning, dlmopen(%p, %p(\"%s\"), 0x%x) called with lmid not LMID_ID_BASE (unsupported)\n", lmid, filename, filename?(char*)filename:"self", flag); + } + // lmid is ignored for now... + return my_dlopen(emu, filename, flag); +} +char* my_dlerror(x64emu_t* emu) +{ + dlprivate_t *dl = emu->context->dlprivate; + return dl->last_error; +} + +KHASH_SET_INIT_INT(libs); + +int recursive_dlsym_lib(kh_libs_t* collection, library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end) +{ + if(!lib) + return 0; + khint_t k = kh_get(libs, collection, (uintptr_t)lib); + if(k != kh_end(collection)) + return 0; + int ret; + kh_put(libs, collection, (uintptr_t)lib, &ret); + // look in the library itself + if(lib->get(lib, rsymbol, start, end)) + return 1; + // look in other libs + int n = GetNeededLibN(lib); + for (int i=0; i<n; ++i) { + library_t *l = GetNeededLib(lib, i); + if(recursive_dlsym_lib(collection, l, rsymbol, start, end)) + return 1; + } + + return 0; +} + +int my_dlsym_lib(library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end) +{ + kh_libs_t *collection = kh_init(libs); + int ret = recursive_dlsym_lib(collection, lib, rsymbol, start, end); + kh_destroy(libs, collection); + + return ret; +} +void* my_dlsym(x64emu_t* emu, void *handle, void *symbol) +{ + dlprivate_t *dl = emu->context->dlprivate; + uintptr_t start, end; + char* rsymbol = (char*)symbol; + CLEARERR + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlsym(%p, %s) :", handle, rsymbol); + } + printf_log(LOG_DEBUG, "Call to dlsym(%p, \"%s\")\n", handle, rsymbol); + if(handle==NULL) { + // special case, look globably + if(GetGlobalSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p)\n", rsymbol, handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", NULL); + } + return NULL; + } + if(handle==(void*)0xFFFFFFFF) { + // special case, look globably but no self (RTLD_NEXT) + elfheader_t *elf = FindElfAddress(emu->context, *(uint32_t*)R_RSP); // use return address to guess "self" + if(GetNoSelfSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, elf)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p)\n", rsymbol, handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", NULL); + } + return NULL; + } + size_t nlib = (size_t)handle; + --nlib; + if(nlib<0 || nlib>=dl->lib_sz) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p)\n", handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", NULL); + } + return NULL; + } + if(dl->count[nlib]==0) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle); + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)NULL); + } + return NULL; + } + if(dl->libs[nlib]) { + if(my_dlsym_lib(dl->libs[nlib], rsymbol, &start, &end)==0) { + // not found + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\nCall to dlsym(%s, \"%s\") Symbol not found\n", NULL, GetNameLib(dl->libs[nlib]), rsymbol); + } + printf_log(LOG_DEBUG, " Symbol not found\n"); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p(%s)", rsymbol, handle, GetNameLib(dl->libs[nlib])); + return NULL; + } + } else { + // still usefull? + if(GetSymbolStartEnd(GetLocalSymbol(emu->context->maplib), rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(GetSymbolStartEnd(GetWeakSymbol(emu->context->maplib), rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + if(GetSymbolStartEnd(GetMapSymbol(emu->context->maplib), rsymbol, &start, &end)) { + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; + } + // not found + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\nCall to dlsym(%s, \"%s\") Symbol not found\n", NULL, "Self", rsymbol); + } + printf_log(LOG_DEBUG, " Symbol not found\n"); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p)\n", rsymbol, handle); + return NULL; + } + if(dlsym_error && box64_log<LOG_DEBUG) { + printf_log(LOG_NONE, "%p\n", (void*)start); + } + return (void*)start; +} +int my_dlclose(x64emu_t* emu, void *handle) +{ + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlclose(%p)\n", handle); + } + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + size_t nlib = (size_t)handle; + --nlib; + if(nlib<0 || nlib>=dl->lib_sz) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p)\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlclose: %s\n", dl->last_error); + } + return -1; + } + if(dl->count[nlib]==0) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlclose: %s\n", dl->last_error); + } + return -1; + } + dl->count[nlib] = dl->count[nlib]-1; + if(dl->count[nlib]==0 && dl->dlopened[nlib]) { // need to call Fini... + int idx = GetElfIndex(dl->libs[nlib]); + if(idx!=-1) { + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlclose: Call to Fini for %p\n", handle); + } + RunElfFini(emu->context->elfs[idx], emu); + InactiveLibrary(dl->libs[nlib]); + } + } + return 0; +} +int my_dladdr(x64emu_t* emu, void *addr, void *i) +{ + //int dladdr(void *addr, Dl_info *info); + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + Dl_info *info = (Dl_info*)i; + printf_log(LOG_DEBUG, "Warning: partially unimplement call to dladdr(%p, %p)\n", addr, info); + + //emu->quit = 1; + info->dli_saddr = NULL; + info->dli_fname = NULL; + info->dli_sname = FindSymbolName(emu->context->maplib, addr, &info->dli_saddr, NULL, &info->dli_fname, &info->dli_fbase); + printf_log(LOG_DEBUG, " dladdr return saddr=%p, fname=\"%s\", sname=\"%s\"\n", info->dli_saddr, info->dli_sname?info->dli_sname:"", info->dli_fname?info->dli_fname:""); + return (info->dli_sname)?1:0; // success is non-null here... +} +void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, void *version) +{ + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + //void *dlvsym(void *handle, char *symbol, char *version); + char* rsymbol = (char*)symbol; + char* rversion = (char*)version; + printf_log(LOG_INFO, "Warning: unimplement call to dlvsym(%p, %s, %s), fallback to dlsym\n", handle, rsymbol, rversion); + + return my_dlsym(emu, handle, symbol); +} + +typedef struct link_map_s { + uintptr_t l_addr; + char* l_name; + Elf64_Dyn* l_ld; +} link_map_t; + +int my_dlinfo(x64emu_t* emu, void* handle, int request, void* info) +{ + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "Call to dlinfo(%p, %d, %p)\n", handle, request, info); + } + dlprivate_t *dl = emu->context->dlprivate; + CLEARERR + size_t nlib = (size_t)handle; + --nlib; + if(nlib<0 || nlib>=dl->lib_sz) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p)\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlinfo: %s\n", dl->last_error); + } + return -1; + } + if(dl->count[nlib]==0) { + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle); + if(dlsym_error || box64_log>=LOG_DEBUG) { + printf_log(LOG_NONE, "dlinfo: %s\n", dl->last_error); + } + return -1; + } + library_t *lib = dl->libs[nlib]; + elfheader_t *h = (GetElfIndex(lib)>-1)?my_context->elfs[GetElfIndex(lib)]:NULL; + switch(request) { + case 2: // RTLD_DI_LINKMAP + { + static link_map_t map = {0}; //cheating, creating a structure on demand... + *(link_map_t**)info = ↦ + map.l_addr = h?h->delta:0; + map.l_name = lib->path; + map.l_ld = h?h->Dynamic:NULL; + } + return 0; + default: + printf_log(LOG_NONE, "Warning, unsupported call to dlinfo(%p, %d, %p)\n", handle, request, info); + if(!dl->last_error) + dl->last_error = malloc(129); + snprintf(dl->last_error, 129, "unsupported call to dlinfo request:%d\n", request); + } + return -1; +} \ No newline at end of file diff --git a/src/wrapped/wrappedlibdl_private.h b/src/wrapped/wrappedlibdl_private.h new file mode 100755 index 00000000..35a45d49 --- /dev/null +++ b/src/wrapped/wrappedlibdl_private.h @@ -0,0 +1,14 @@ +#if defined(GO) && defined(GOM) && defined(GO2) && defined(DATA) + +GOM(dladdr, iFEpp) +// dladdr1 +GOM(dlclose, iFEp) +GOM(dlerror, pFE) +DATAB(_dlfcn_hook, 4) +GOM(dlinfo, iFEpip) +GOM(dlmopen, pFEppi) +GOM(dlopen, pFEpi) +GOM(dlsym, pFEpp) +GOM(dlvsym, pFEppp) // Weak + +#endif \ No newline at end of file |