# backtrace 1. `loadEmulatedLib` ```gdb #0 loadEmulatedLib ( libname=libname@entry=0xffffffffc7e0 "/opt/wine-devel/bin/../lib64/wine/x86_64-unix/ntdll.so", lib=lib@entry=0x36d1a220, context=context@entry=0x36d14fc0, verneeded=verneeded@entry=0x0) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:310 #1 0x0000000034896a80 in loadEmulatedLib ( libname=0xffffffffc7e0 "/opt/wine-devel/bin/../lib64/wine/x86_64-unix/ntdll.so", lib=0x36d1a220, context=0x36d14fc0, verneeded=0x0) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:308 #2 initEmulatedLib (path=path@entry=0xffffffffd910 "/opt/wine-devel/bin/../lib64/wine/x86_64-unix/ntdll.so", lib=lib@entry=0x36d1a220, context=0x36d14fc0, verneeded=0x0) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:395 #3 0x0000000034899f9c in NewLibrary ( path=path@entry=0xffffffffd910 "/opt/wine-devel/bin/../lib64/wine/x86_64-unix/ntdll.so", context=<optimized out>, verneeded=<optimized out>) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:532 #4 0x0000000034894950 in AddNeededLib_add (maplib=<synthetic pointer>, local=1, needed=0x36d255e0, n=0, verneeded=0x0, box64=0x36d14fc0, emu=0x36d174a0) at /home/chiu/devarajabc_box64/box64/src/librarian/librarian.c:226 #5 AddNeededLib (maplib=maplib@entry=0x0, local=local@entry=1, bindnow=<optimized out>, deepbind=deepbind@entry=0, needed=needed@entry=0x36d255e0, verneeded=verneeded@entry=0x0, box64=<optimized out>, emu=emu@entry=0x36d174a0) at /home/chiu/devarajabc_box64/box64/src/librarian/librarian.c:340 #6 0x0000000034e5f478 in my_dlopen (emu=<error reading variable: value has been optimized out>, filename=<error reading variable: value has been optimized out>, flag=2, flag@entry=<error reading variable: value has been optimized out>) at /home/chiu/devarajabc_box64/box64/src/wrapped/wrappedlibdl.c:234 #7 0x00000000348d4260 in pFEpi (emu=0x36d174a0, fcn=<optimized out>) at /home/chiu/devarajabc_box64/box64/src/wrapped/generated/wrapper.c:4293 #8 0x0000fffff70026e0 in ?? () #9 0x00000000360550a0 in my_alternates () Backtrace stopped: previous frame identical to this frame (corrupt stack?) ``` 2. `initWrappedLib` ```gdb #0 initWrappedLib (lib=lib@entry=0x36d19ba0, context=context@entry=0x36d14fc0) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:262 #1 0x000000003489a128 in NewLibrary (path=path@entry=0x36d170a0 "libdl.so.2", context=<optimized out>, verneeded=<optimized out>) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:529 #2 0x0000000034894950 in AddNeededLib_add (maplib=<synthetic pointer>, local=0, needed=0x36d16200, n=0, verneeded=0x36d184b0, box64=0x36d14fc0, emu=0x36d174a0) at /home/chiu/devarajabc_box64/box64/src/librarian/librarian.c:226 #3 AddNeededLib (maplib=0x36d0ff30, local=local@entry=0, bindnow=bindnow@entry=0, deepbind=deepbind@entry=0, needed=needed@entry=0x36d16200, verneeded=<optimized out>, box64=<optimized out>, emu=emu@entry=0x36d174a0) at /home/chiu/devarajabc_box64/box64/src/librarian/librarian.c:340 #4 0x000000003486f7b8 in initialize (argc=<optimized out>, argv=<optimized out>, env=<optimized out>, emulator=emulator@entry=0xffffffffef10, elfheader=elfheader@entry=0xffffffffef18, exec=exec@entry=1) at /home/chiu/devarajabc_box64/box64/src/core.c:1498 #5 0x0000000034824f0c in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>) at /home/chiu/devarajabc_box64/box64/src/main.c:7 ``` 3. `initEmulatedLib` ```gdb #0 initEmulatedLib (path=path@entry=0xffffffffd910 "/opt/wine-devel/bin/../lib64/wine/x86_64-unix/ntdll.so", lib=lib@entry=0x36d1a220, context=0x36d14fc0, verneeded=0x0) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:392 #1 0x0000000034899f9c in NewLibrary ( path=path@entry=0xffffffffd910 "/opt/wine-devel/bin/../lib64/wine/x86_64-unix/ntdll.so", context=<optimized out>, verneeded=<optimized out>) at /home/chiu/devarajabc_box64/box64/src/librarian/library.c:532 #2 0x0000000034894950 in AddNeededLib_add (maplib=<synthetic pointer>, local=1, needed=0x36d255e0, n=0, verneeded=0x0, box64=0x36d14fc0, emu=0x36d174a0) at /home/chiu/devarajabc_box64/box64/src/librarian/librarian.c:226 #3 AddNeededLib (maplib=maplib@entry=0x0, local=local@entry=1, bindnow=<optimized out>, deepbind=deepbind@entry=0, needed=needed@entry=0x36d255e0, verneeded=verneeded@entry=0x0, box64=<optimized out>, emu=emu@entry=0x36d174a0) at /home/chiu/devarajabc_box64/box64/src/librarian/librarian.c:340 #4 0x0000000034e5f478 in my_dlopen (emu=<error reading variable: value has been optimized out>, filename=<error reading variable: value has been optimized out>, flag=2, flag@entry=<error reading variable: value has been optimized out>) at /home/chiu/devarajabc_box64/box64/src/wrapped/wrappedlibdl.c:234 #5 0x00000000348d4260 in pFEpi (emu=0x36d174a0, fcn=<optimized out>) at /home/chiu/devarajabc_box64/box64/src/wrapped/generated/wrapper.c:4293 #6 0x0000fffff70026e0 in ?? () #7 0x00000000360550a0 in my_alternates () Backtrace stopped: previous frame identical to this frame (corrupt stack?) ``` ## `library_t` ```c typedef struct library_s { char* name; // <> path char* path; // original path int8_t nbdot; // number of "." after .so int8_t type; // 0: native(wrapped) 1: emulated(elf) -1: undetermined uint8_t deepbind; wrappedlib_fini_t fini; wrappedlib_get_t getglobal; // get global (non-weak) wrappedlib_get_t getweak; // get weak symbol wrappedlib_get_t getlocal; // get local symbol union { wlib_t w; elib_t e; }; // private lib data lib_t *maplib; // local maplib, for dlopen'd library with LOCAL binding (most of the dlopen) int maplib_ref; // ref to maplib (not owned) size_t dlopen; // idx to the dlopen idx (or 0 if not dlopen) } library_t; ``` ```c #define LIB_WRAPPED 0 #define LIB_EMULATED 1 #define LIB_UNNKNOW -1 ``` ```c int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elfheader_t** elfheader, int exec) { #ifndef STATICBUILD init_malloc_hook(); #endif init_auxval(argc, argv, environ?environ:env); // analogue to QEMU_VERSION in qemu-user-mode emulation if(getenv("BOX64_VERSION")) { PrintBox64Version(0); exit(0); } // trying to open and load 1st arg if(argc==1) { /*PrintBox64Version(1); PrintHelp(); return 1;*/ printf("[BOX64] Missing operand after 'box64'\n"); printf("See 'box64 --help' for more information.\n"); exit(0); } if(argc>1 && !strcmp(argv[1], "/usr/bin/gdb") && BOX64ENV(trace_file)) exit(0); // uname -m is redirected to box64 -m if(argc==2 && (!strcmp(argv[1], "-m") || !strcmp(argv[1], "-p") || !strcmp(argv[1], "-i"))) { printf("x86_64\n"); exit(0); } ftrace = stdout; LoadEnvVariables(); InitializeEnvFiles(); const char* prog = argv[1]; int nextarg = 1; // check if some options are passed while(prog && prog[0]=='-') { if(!strcmp(prog, "-v") || !strcmp(prog, "--version")) { PrintBox64Version(0); exit(0); } if(!strcmp(prog, "-h") || !strcmp(prog, "--help")) { PrintHelp(); exit(0); } // other options? if(!strcmp(prog, "--")) { prog = argv[++nextarg]; break; } printf("Warning, Unrecognized option '%s'\n", prog); prog = argv[++nextarg]; } if(!prog || nextarg==argc) { printf("[BOX64] Nothing to run\n"); exit(0); } if (!BOX64ENV(nobanner)) PrintBox64Version(1); displayMiscInfo(); hookMangoHud(); char* bashpath = NULL; { char* p = BOX64ENV(bash); if(p) { if(FileIsX64ELF(p)) { bashpath = p; printf_log(LOG_INFO, "Using bash \"%s\"\n", bashpath); } else { printf_log(LOG_INFO, "The x86_64 bash \"%s\" is not an x86_64 binary.\n", p); } } } // precheck, for win-preload const char* prog_ = strrchr(prog, '/'); if(!prog_) prog_ = prog; else ++prog_; if(!strcmp(prog_, "wine-preloader") || !strcmp(prog_, "wine64-preloader")) { // wine-preloader detecter, skipping it if next arg exist and is an x86 binary int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0; #ifdef BOX32 int x86 = (nextarg<argc)?FileIsX86ELF(argv[nextarg]):0; #else int x86 = 0; #endif if(x64 || x86) { prog = argv[++nextarg]; printf_log(LOG_INFO, "Wine preloader detected, loading \"%s\" directly\n", prog); wine_preloaded = 1; prog_ = strrchr(prog, '/'); if(!prog_) prog_ = prog; else ++prog_; } } #ifndef STATICBUILD // pre-check for pressure-vessel-wrap if(!strcmp(prog_, "pressure-vessel-wrap")) { printf_log(LOG_INFO, "pressure-vessel-wrap detected\n"); pressure_vessel(argc, argv, nextarg+1, prog); } #endif int ld_libs_args = -1; int is_custom_gstreamer = 0; // check if this is wine if(!strcmp(prog_, "wine64") || !strcmp(prog_, "wine64-development") || !strcmp(prog_, "wine")) { const char* prereserve = getenv("WINEPRELOADRESERVE"); printf_log(LOG_INFO, "Wine64 detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:""); if(wine_preloaded || 1) { wine_prereserve(prereserve); } // special case for winedbg, doesn't work anyway if(argv[nextarg+1] && strstr(argv[nextarg+1], "winedbg")==argv[nextarg+1]) { if(getenv("BOX64_WINEDBG")) { SET_BOX64ENV(nobanner, 1); BOX64ENV(log) = 0; } else { printf_log(LOG_NONE, "winedbg detected, not launching it!\n"); exit(0); // exiting, it doesn't work anyway } } box64_wine = 1; // check if it's proton, with it's custom gstreamer build, to disable gtk3 loading char tmp[strlen(prog)+100]; strcpy(tmp, prog); char* pp = strrchr(tmp, '/'); if(pp) { *pp = '\0'; // remove the wine binary call strcat(tmp, "/../lib64/gstreamer-1.0"); // check if it exist if(FileExist(tmp, 0)) { box64_custom_gstreamer = box_strdup(tmp); } } // Try to get the name of the exe being run, to ApplyEnvFileEntry laters if(argv[nextarg+1] && argv[nextarg+1][0]!='-' && strlen(argv[nextarg+1])>4 /*&& !strcasecmp(argv[nextarg+1]+strlen(argv[nextarg+1])-4, ".exe")*/) { const char* pp = strrchr(argv[nextarg+1], '/'); if(pp) box64_wine_guest_name = pp + 1; else { pp = strrchr(argv[nextarg+1], '\\'); if(pp) box64_wine_guest_name = pp + 1; else box64_wine_guest_name = argv[nextarg + 1]; } } if (box64_wine_guest_name) printf_log(LOG_INFO, "Detected running wine with \"%s\"\n", box64_wine_guest_name); } else if(strstr(prog, "ld-musl-x86_64.so.1")) { // check if ld-musl-x86_64.so.1 is used printf_log(LOG_INFO, "ld-musl detected. Trying to workaround and use system ld-linux\n"); box64_musl = 1; // skip ld-musl and go through args unti "--" is found, handling "--library-path" to add some libs to BOX64_LD_LIBRARY ++nextarg; while(strcmp(argv[nextarg], "--")) { if(!strcmp(argv[nextarg], "--library-path")) { ++nextarg; ld_libs_args = nextarg; } ++nextarg; } ++nextarg; prog = argv[nextarg]; } else if(!strcmp(prog_, "steam") ) { printf_log(LOG_INFO, "steam detected\n"); box64_steam = 1; } else if(!strcmp(prog_, "steamcmd")) { printf_log(LOG_INFO, "steamcmd detected\n"); box64_steamcmd = 1; } else if(!strcmp(prog_, "wineserver")) { // check if this is wineserver box64_wine = 1; } // Create a new context my_context = NewBox64Context(argc - nextarg); addLibPaths(my_context); // Append ld_list if it exist if(ld_libs_args!=-1) PrependList(&my_context->box64_ld_lib, argv[ld_libs_args], 1); if(is_custom_gstreamer) //TODO: is this still needed? AddPath("libwayland-client.so.0", &my_context->box64_emulated_libs, 0); my_context->box64path = ResolveFile(argv[0], &my_context->box64_path); // prepare all other env. var my_context->envc = CountEnv(environ?environ:env); printf_log(LOG_INFO, "Counted %d Env var\n", my_context->envc); // allocate extra space for new environment variables such as BOX64_PATH my_context->envv = (char**)box_calloc(my_context->envc+1, sizeof(char*)); path_collection_t ld_preload = {0}; if(getenv("BOX64_LD_PRELOAD")) { char* p = getenv("BOX64_LD_PRELOAD"); ParseList(p, &ld_preload, 0); if (ld_preload.size && BOX64ENV(log)) { printf_log(LOG_INFO, "BOX64 trying to Preload "); for (int i=0; i<ld_preload.size; ++i) printf_log_prefix(0, LOG_INFO, "%s ", ld_preload.paths[i]); printf_log_prefix(0, LOG_INFO, "\n"); } } if(getenv("LD_PRELOAD")) { char* p = getenv("LD_PRELOAD"); if(strstr(p, "libtcmalloc_minimal.so.0")) box64_tcmalloc_minimal = 1; if(strstr(p, "libtcmalloc_minimal.so.4")) box64_tcmalloc_minimal = 1; if(strstr(p, "libtcmalloc_minimal_debug.so.4")) box64_tcmalloc_minimal = 1; if(strstr(p, "libasan.so")) box64_tcmalloc_minimal = 1; // it seems Address Sanitizer doesn't handle dlsym'd malloc very well AppendList(&ld_preload, p, 0); if (ld_preload.size && BOX64ENV(log)) { printf_log(LOG_INFO, "BOX64 trying to Preload "); for (int i=0; i<ld_preload.size; ++i) printf_log_prefix(0, LOG_INFO, "%s ", ld_preload.paths[i]); printf_log_prefix(0, LOG_INFO, "\n"); } } // print PATH and LD_LIB used PrintCollection(&my_context->box64_ld_lib, "Library search path"); PrintCollection(&my_context->box64_path, "Binary search path"); // lets build argc/argv stuff printf_log(LOG_INFO, "Looking for %s\n", prog); if(strchr(prog, '/')) my_context->argv[0] = box_strdup(prog); else my_context->argv[0] = ResolveFileSoft(prog, &my_context->box64_path); // GatherEnv(&my_context->envv, environ?environ:env, my_context->argv[0]); if (BOX64ENV(dump) || BOX64ENV(log)<=LOG_DEBUG) { for (int i=0; i<my_context->envc; ++i) printf_dump(LOG_DEBUG, " Env[%02d]: %s\n", i, my_context->envv[i]); } // check if box86 is present { my_context->box86path = box_strdup(my_context->box64path); #ifndef BOX32 if(strstr(my_context->box86path, "box64")) { char* p = strrchr(my_context->box86path, '6'); // get the 6 of box64 p[0] = '8'; p[1] = '6'; // change 64 to 86 } else { box_free(my_context->box86path); my_context->box86path = ResolveFileSoft("box86", &my_context->box64_path); } if(my_context->box86path && !FileExist(my_context->box86path, IS_FILE)) { box_free(my_context->box86path); my_context->box86path = NULL; } #endif } box64_guest_name = strrchr(prog, '/'); if (!box64_guest_name) box64_guest_name = prog; else ++box64_guest_name; if(box64_wine) { #ifdef ANDROID AddPath("libdl.so", &ld_preload, 0); #else AddPath("libdl.so.2", &ld_preload, 0); #endif } // special case for zoom if (strstr(box64_guest_name, "zoom") == box64_guest_name) { printf_log(LOG_INFO, "Zoom detected, Trying to use system libturbojpeg if possible\n"); box64_zoom = 1; } // special case for bash if (!strcmp(box64_guest_name, "bash") || !strcmp(box64_guest_name, "box64-bash")) { printf_log(LOG_INFO, "Bash detected, disabling banner\n"); if (!BOX64ENV(nobanner)) { setenv("BOX86_NOBANNER", "1", 0); setenv("BOX64_NOBANNER", "1", 0); } if (!bashpath) { bashpath = (char*)prog; setenv("BOX64_BASH", prog, 1); } } if(!bashpath) bashpath = ResolveFile("box64-bash", &my_context->box64_path); if(bashpath) my_context->bashpath = box_strdup(bashpath); ApplyEnvFileEntry(box64_guest_name); if (box64_wine && box64_wine_guest_name) { ApplyEnvFileEntry(box64_wine_guest_name); box64_wine_guest_name = NULL; } openFTrace(0); setupZydis(my_context); PrintEnvVariables(&box64env, LOG_INFO); for(int i=1; i<my_context->argc; ++i) { my_context->argv[i] = box_strdup(argv[i+nextarg]); printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]); } if(BOX64ENV(nosandbox)) { add_argv("--no-sandbox"); } if(BOX64ENV(inprocessgpu)) { add_argv("--in-process-gpu"); } if(BOX64ENV(cefdisablegpu)) { add_argv("-cef-disable-gpu"); } if(BOX64ENV(cefdisablegpucompositor)) { add_argv("-cef-disable-gpu-compositor"); } // add new args only if there is no args already if(BOX64ENV(args)) { char tmp[256]; char* p = BOX64ENV(args); int state = 0; char* p2 = p; if(my_context->argc==1 || (my_context->argc==2 && box64_wine)) while(state>=0) { switch(*p2) { case 0: // end of flux if(state && (p2!=p)) add_argv(p); state = -1; break; case '"': // start/end of quotes if(state<2) {if(!state) p=p2; state=2;} else state=1; break; case ' ': if(state==1) {strncpy(tmp, p, p2-p); tmp[p2-p]='\0'; add_argv(tmp); state=0;} break; default: if(state==0) {state=1; p=p2;} break; } ++p2; } } if(BOX64ENV(insert_args)) { char tmp[256]; char* p = BOX64ENV(insert_args); int state = 0; char* p2 = p; while(state>=0) { switch(*p2) { case 0: // end of flux if(state && (p2!=p)) add_argv(p); state = -1; break; case '"': // start/end of quotes if(state<2) {if(!state) p=p2; state=2;} else state=1; break; case ' ': if(state==1) {strncpy(tmp, p, p2-p); tmp[p2-p]='\0'; add_argv(tmp); state=0;} break; default: if(state==0) {state=1; p=p2;} break; } ++p2; } } // check if file exist if(!my_context->argv[0] || !FileExist(my_context->argv[0], IS_FILE)) { printf_log(LOG_NONE, "Error: File is not found. (%s)\n", my_context->argv[0]); free_contextargv(); FreeBox64Context(&my_context); FreeCollection(&ld_preload); return -1; } if(!FileExist(my_context->argv[0], IS_FILE|IS_EXECUTABLE)) { printf_log(LOG_NONE, "Error: %s is not an executable file.\n", my_context->argv[0]); free_contextargv(); FreeBox64Context(&my_context); FreeCollection(&ld_preload); return -1; } if(!(my_context->fullpath = box_realpath(my_context->argv[0], NULL))) my_context->fullpath = box_strdup(my_context->argv[0]); if(getenv("BOX64_ARG0")) my_context->argv[0] = box_strdup(getenv("BOX64_ARG0")); FILE *f = fopen(my_context->fullpath, "rb"); if(!f) { printf_log(LOG_NONE, "Error: Cannot open %s\n", my_context->fullpath); free_contextargv(); FreeBox64Context(&my_context); FreeCollection(&ld_preload); return -1; } #ifdef BOX32 box64_is32bits = FileIsX86ELF(my_context->fullpath); if(box64_is32bits) { printf_log(LOG_INFO, "Using Box32 to load 32bits elf\n"); loadProtectionFromMap(); reserveHighMem(); init_pthread_helper_32(); } #endif LoadLDPath(my_context); elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1); if(!elf_header) { int x86 = my_context->box86path?FileIsX86ELF(my_context->fullpath):0; int script = my_context->bashpath?FileIsShell(my_context->fullpath):0; printf_log(LOG_NONE, "Error: Reading elf header of %s, Try to launch %s instead\n", my_context->fullpath, x86?"using box86":(script?"using bash":"natively")); fclose(f); FreeCollection(&ld_preload); int ret; if(x86) { // duplicate the array and insert 1st arg as box86 const char** newargv = (const char**)box_calloc(my_context->argc+2, sizeof(char*)); newargv[0] = my_context->box86path; for(int i=0; i<my_context->argc; ++i) newargv[i+1] = my_context->argv[i]; ret = execvp(newargv[0], (char * const*)newargv); } else if (script) { // duplicate the array and insert 1st arg as box64, 2nd is bash const char** newargv = (const char**)box_calloc(my_context->argc+3, sizeof(char*)); newargv[0] = my_context->box64path; newargv[1] = my_context->bashpath; for(int i=0; i<my_context->argc; ++i) newargv[i+2] = my_context->argv[i]; ret = execvp(newargv[0], (char * const*)newargv); } else { const char** newargv = (const char**)box_calloc(my_context->argc+1, sizeof(char*)); for(int i=0; i<my_context->argc; ++i) newargv[i] = my_context->argv[i]; ret = execvp(newargv[0], (char * const*)newargv); } free_contextargv(); FreeBox64Context(&my_context); return ret; } AddElfHeader(my_context, elf_header); *elfheader = elf_header; if(CalcLoadAddr(elf_header)) { printf_log(LOG_NONE, "Error: Reading elf header of %s\n", my_context->fullpath); FreeElfHeader(&elf_header); free_contextargv(); FreeBox64Context(&my_context); FreeCollection(&ld_preload); return -1; } // allocate memory and load elf if(AllocLoadElfMemory(my_context, elf_header, 1)) { printf_log(LOG_NONE, "Error: Loading elf %s\n", my_context->fullpath); FreeElfHeader(&elf_header); free_contextargv(); FreeBox64Context(&my_context); FreeCollection(&ld_preload); return -1; } if (!strcmp(box64_guest_name, "heroic")) { // check if heroic needs patching (for the 2.15.1 version) uint8_t* address = GetBaseAddress(elf_header); if(address[0x422f6e1]==0x72 && address[0x422f6e2]==0x44 && address[0x422f6e0]==0xF8 && address[0x422f727]==0xcc) { printf_log(LOG_INFO, "Patched heroic!\n"); uintptr_t page = ((uintptr_t)&address[0x422f6e1])&~(box64_pagesize-1); int prot = getProtection(page); mprotect((void*)page, box64_pagesize, PROT_READ|PROT_WRITE|PROT_EXEC); address[0x422f6e1]=0x90; address[0x422f6e2]=0x90; mprotect((void*)page, box64_pagesize, prot); } } if(ElfCheckIfUseTCMallocMinimal(elf_header)) { if(!box64_tcmalloc_minimal) { // need to reload with tcmalloc_minimal as a LD_PRELOAD! printf_log(LOG_INFO, "tcmalloc_minimal.so.4 used. Reloading box64 with the lib preladed\n"); // need to get a new envv variable. so first count it and check if LD_PRELOAD is there int preload=(getenv("LD_PRELOAD"))?1:0; int nenv = 0; while(env[nenv]) nenv++; // alloc + "LD_PRELOAD" if needd + last NULL ending char** newenv = (char**)box_calloc(nenv+1+((preload)?0:1), sizeof(char*)); // copy strings for (int i=0; i<nenv; ++i) newenv[i] = box_strdup(env[i]); // add ld_preload if(preload) { // find the line int l = 0; while(l<nenv) { if(strstr(newenv[l], "LD_PRELOAD=")==newenv[l]) { // found it! char *old = newenv[l]; newenv[l] = (char*)box_calloc(strlen(old)+strlen("libtcmalloc_minimal.so.4:")+1, sizeof(char)); strcpy(newenv[l], "LD_PRELOAD=libtcmalloc_minimal.so.4:"); strcat(newenv[l], old + strlen("LD_PRELOAD=")); box_free(old); // done, end loop l = nenv; } else ++l; } } else { //move last one newenv[nenv] = box_strdup(newenv[nenv-1]); box_free(newenv[nenv-1]); newenv[nenv-1] = box_strdup("LD_PRELOAD=libtcmalloc_minimal.so.4"); } // duplicate argv too char** newargv = box_calloc(argc+1, sizeof(char*)); int narg = 0; while(argv[narg]) {newargv[narg] = box_strdup(argv[narg]); narg++;} // launch with new env... if(execve(newargv[0], newargv, newenv)<0) printf_log(LOG_NONE, "Failed to relaunch. Error is %d/%s\n", errno, strerror(errno)); } else { printf_log(LOG_INFO, "Using tcmalloc_minimal.so.4, and it's in the LD_PRELOAD command\n"); } } #if defined(RPI) || defined(RK3399) || defined(RK3326) // before launching emulation, let's check if this is a mojosetup from GOG if (((strstr(prog, "bin/linux/x86_64/mojosetup") && getenv("MOJOSETUP_BASE")) || strstr(prog, ".mojosetup/mojosetup")) && getenv("GTK2_RC_FILES")) { sanitize_mojosetup_gtk_background(); } #endif // change process name { char* p = strrchr(my_context->fullpath, '/'); if(p) ++p; else p = my_context->fullpath; if(prctl(PR_SET_NAME, p)==-1) printf_log(LOG_NONE, "Error setting process name (%s)\n", strerror(errno)); else printf_log(LOG_INFO, "Rename process to \"%s\"\n", p); if (strcmp(box64_guest_name, p)) { ApplyEnvFileEntry(p); } // and now all change the argv (so libs libs mesa find the correct program names) char* endp = (char*)argv[argc-1]; while(*endp) ++endp; // find last argv[] address uintptr_t diff = prog - argv[0]; // this is the difference we need to compensate for(p=(char*)prog; p<=endp; ++p) *(p - diff) = *p; // copy all element at argv[nextarg] to argv[0] memset(endp - diff, 0, diff); // fill reminder with NULL for(int i=nextarg; i<argc; ++i) argv[i] -= diff; // adjust strings my_context->orig_argc = argc; my_context->orig_argv = (char**)argv; } box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34"); if(box64_isglibc234) printf_log(LOG_DEBUG, "Program linked with GLIBC 2.34+\n"); // get and alloc stack size and align if(CalcStackSize(my_context)) { printf_log(LOG_NONE, "Error: Allocating stack\n"); free_contextargv(); FreeBox64Context(&my_context); FreeCollection(&ld_preload); return -1; } // init x86_64 emu x64emu_t *emu = NewX64Emu(my_context, my_context->ep, (uintptr_t)my_context->stack, my_context->stacksz, 0); // stack setup is much more complicated then just that! SetupInitialStack(emu); // starting here, the argv[] don't need free anymore SetupX64Emu(emu, NULL); if(box64_is32bits) { SetEAX(emu, my_context->argc); SetEBX(emu, my_context->argv32); } else { SetRSI(emu, my_context->argc); SetRDX(emu, (uint64_t)my_context->argv); SetRCX(emu, (uint64_t)my_context->envv); SetRBP(emu, 0); // Frame pointer so to "No more frame pointer" } // child fork to handle traces //pthread_atfork(my_prepare_fork, my_parent_fork, my_child_fork); thread_set_emu(emu); // export symbols AddSymbols(my_context->maplib, elf_header); if(wine_preloaded) { uintptr_t wineinfo = 0; int ver = -1, veropt = 0; const char* vername = NULL; if(!ElfGetGlobalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt)) if(!ElfGetWeakSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt)) ElfGetLocalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt); if(!wineinfo) {printf_log(LOG_DEBUG, "Warning, Symbol wine_main_preload_info not found\n");} else { *(void**)wineinfo = get_wine_prereserve(); printf_log(LOG_DEBUG, "WINE wine_main_preload_info found and updated %p -> %p\n", get_wine_prereserve(), *(void**)wineinfo); } #ifdef DYNAREC dynarec_wine_prereserve(); #endif } AddMainElfToLinkmap(elf_header); //TODO: LinkMap seems incorect // pre-load lib if needed if(ld_preload.size) { my_context->preload = new_neededlib(0); for(int i=0; i<ld_preload.size; ++i) { needed_libs_t* tmp = new_neededlib(1); tmp->names[0] = ld_preload.paths[i]; if(AddNeededLib(my_context->maplib, 0, 0, 0, tmp, elf_header, my_context, emu)) { printf_log(LOG_INFO, "Warning, cannot pre-load %s\n", tmp->names[0]); RemoveNeededLib(my_context->maplib, 0, tmp, my_context, emu); } else { for(int j=0; j<tmp->size; ++j) add1lib_neededlib(my_context->preload, tmp->libs[j], tmp->names[j]); } free_neededlib(tmp); } } FreeCollection(&ld_preload); // Call librarian to load all dependant elf if(LoadNeededLibs(elf_header, my_context->maplib, 0, 0, 0, my_context, emu)) { printf_log(LOG_NONE, "Error: Loading needed libs in elf %s\n", my_context->argv[0]); FreeBox64Context(&my_context); return -1; } // reloc... printf_log(LOG_DEBUG, "And now export symbols / relocation for %s...\n", ElfName(elf_header)); if(RelocateElf(my_context->maplib, NULL, 0, 0, elf_header)) { printf_log(LOG_NONE, "Error: Relocating symbols in elf %s\n", my_context->argv[0]); FreeBox64Context(&my_context); return -1; } // and handle PLT RelocateElfPlt(my_context->maplib, NULL, 0, 0, elf_header); // deferred init setupTraceInit(); RunDeferredElfInit(emu); // update TLS of main elf RefreshElfTLS(elf_header); // do some special case check, _IO_2_1_stderr_ and friends, that are setup by libc, but it's already done here, so need to do a copy ResetSpecialCaseMainElf(elf_header); // init... setupTrace(); *emulator = emu; return 0; } ``` RelocateElfRELA (maplib=maplib@entry=0x36f68fa0, local_maplib=local_maplib@entry=0x0, bindnow=bindnow@entry=1, deepbind=deepbind@entry=0, head=head@entry=0x36f71800, cnt=cnt@entry=9, rela=<optimized out>, need_resolv=need_resolv@entry=0x0) at /root/box64/src/elfs/elfloader.c:634 634 if(!offs && !end && local_maplib && !deepbind) (gdb) n 638 sym_elf = FindElfSymbol(my_context, elfsym); (gdb) n 639 if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) (gdb) n 645 switch(t) { (gdb) n 687 if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { (gdb) n 695 if (!offs) { (gdb) n 699 printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, (void*)(p?(*p):0), (void*)(offs + rela[i].r_addend), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)"); (gdb) n 700 *p = offs + rela[i].r_addend; (gdb) n 701 if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); (gdb) n 581 for (int i=0; i<cnt; ++i) { (gdb) n 582 int t = ELF64_R_TYPE(rela[i].r_info); (gdb) n 584 int bind = ELF64_ST_BIND(sym->st_info); (gdb) n 586 const char* symname = SymName64(head, sym); (gdb) n 593 int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; (gdb) n 594 if(version!=-1) version &=0x7fff; (gdb) n 595 const char* vername = GetSymbolVersion(head, version); (gdb) n 596 Elf64_Half flags = GetSymbolVersionFlag(head, version); (gdb) n 600 if(vis==STV_PROTECTED) { (gdb) n 608 if(bind==STB_GNU_UNIQUE) { (gdb) n 612 } else if(bind==STB_LOCAL) { (gdb) 630 if(!offs && !end && local_maplib && deepbind) (gdb) n 633 GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); (gdb) n 634 if(!offs && !end && local_maplib && !deepbind) (gdb) n 638 sym_elf = FindElfSymbol(my_context, elfsym); (gdb) n 639 if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) (gdb) n 645 switch(t) { (gdb) n 687 if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { (gdb) n 695 if (!offs) { (gdb) n 699 printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, (void*)(p?(*p):0), (void*)(offs + rela[i].r_addend), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)"); (gdb) n 700 *p = offs + rela[i].r_addend; (gdb) n 701 if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); (gdb) n 581 for (int i=0; i<cnt; ++i) { (gdb) n 582 int t = ELF64_R_TYPE(rela[i].r_info); (gdb) 584 int bind = ELF64_ST_BIND(sym->st_info); (gdb) n 586 const char* symname = SymName64(head, sym); (gdb) n 593 int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; (gdb) n 594 if(version!=-1) version &=0x7fff; (gdb) n 595 const char* vername = GetSymbolVersion(head, version); (gdb) n 596 Elf64_Half flags = GetSymbolVersionFlag(head, version); (gdb) n 600 if(vis==STV_PROTECTED) { (gdb) n 608 if(bind==STB_GNU_UNIQUE) { (gdb) 612 } else if(bind==STB_LOCAL) { (gdb) n 630 if(!offs && !end && local_maplib && deepbind) (gdb) n 633 GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); (gdb) n 634 if(!offs && !end && local_maplib && !deepbind) (gdb) n 638 sym_elf = FindElfSymbol(my_context, elfsym); (gdb) n 639 if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) (gdb) n 645 switch(t) { (gdb) n 687 if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { (gdb) 695 if (!offs) { (gdb) n 696 if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start") && strcmp(symname, "collector_func_load")) (gdb) n 581 for (int i=0; i<cnt; ++i) { (gdb) n 582 int t = ELF64_R_TYPE(rela[i].r_info); (gdb) n 584 int bind = ELF64_ST_BIND(sym->st_info); (gdb) 586 const char* symname = SymName64(head, sym); (gdb) n 593 int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; (gdb) n 594 if(version!=-1) version &=0x7fff; (gdb) n 595 const char* vername = GetSymbolVersion(head, version); (gdb) n 596 Elf64_Half flags = GetSymbolVersionFlag(head, version); (gdb) 600 if(vis==STV_PROTECTED) { (gdb) n 608 if(bind==STB_GNU_UNIQUE) { (gdb) n 612 } else if(bind==STB_LOCAL) { (gdb) n 630 if(!offs && !end && local_maplib && deepbind) (gdb) n 633 GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); (gdb) 634 if(!offs && !end && local_maplib && !deepbind) (gdb) n 638 sym_elf = FindElfSymbol(my_context, elfsym); (gdb) n 639 if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) (gdb) n 645 switch(t) { (gdb) 687 if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { (gdb) n 695 if (!offs) { (gdb) n 699 printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, (void*)(p?(*p):0), (void*)(offs + rela[i].r_addend), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)"); (gdb) 700 *p = offs + rela[i].r_addend; (gdb) n 701 if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); (gdb) n 581 for (int i=0; i<cnt; ++i) { (gdb) n 582 int t = ELF64_R_TYPE(rela[i].r_info); (gdb) 584 int bind = ELF64_ST_BIND(sym->st_info); (gdb) n 586 const char* symname = SymName64(head, sym); (gdb) n 593 int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; (gdb) n 594 if(version!=-1) version &=0x7fff; (gdb) n 595 const char* vername = GetSymbolVersion(head, version); (gdb) 596 Elf64_Half flags = GetSymbolVersionFlag(head, version); (gdb) n 600 if(vis==STV_PROTECTED) { (gdb) n 608 if(bind==STB_GNU_UNIQUE) { (gdb) 612 } else if(bind==STB_LOCAL) { (gdb) n 630 if(!offs && !end && local_maplib && deepbind) (gdb) n 633 GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); (gdb) 634 if(!offs && !end && local_maplib && !deepbind) (gdb) n 638 sym_elf = FindElfSymbol(my_context, elfsym); (gdb) n 639 if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) (gdb) n 645 switch(t) { (gdb) 687 if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) { (gdb) nn Undefined command: "nn". Try "help". (gdb) n 695 if (!offs) { (gdb) n 699 printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, (void*)(p?(*p):0), (void*)(offs + rela[i].r_addend), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)"); (gdb) n 700 *p = offs + rela[i].r_addend; (gdb) n 701 if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); (gdb) n 581 for (int i=0; i<cnt; ++i) { (gdb) n 582 int t = ELF64_R_TYPE(rela[i].r_info); (gdb) n 584 int bind = ELF64_ST_BIND(sym->st_info); (gdb) n 586 const char* symname = SymName64(head, sym); (gdb) n 593 int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1; (gdb) n 594 if(version!=-1) version &=0x7fff; (gdb) n 595 const char* vername = GetSymbolVersion(head, version); (gdb) n 596 Elf64_Half flags = GetSymbolVersionFlag(head, version); (gdb) n 600 if(vis==STV_PROTECTED) { (gdb) n 608 if(bind==STB_GNU_UNIQUE) { (gdb) n 612 } else if(bind==STB_LOCAL) { (gdb) n 630 if(!offs && !end && local_maplib && deepbind) (gdb) n 633 GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym); (gdb) n 634 if(!offs && !end && local_maplib && !deepbind) (gdb) n 638 sym_elf = FindElfSymbol(my_context, elfsym); (gdb) n 639 if(elfsym && (ELF64_ST_TYPE(elfsym->st_info)==STT_TLS)) (gdb) n 645 switch(t) { (gdb) n 665 globoffs = offs; (gdb) n 668 if(!offs && local_maplib && deepbind) (gdb) n 671 GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL); (gdb) n 672 if(!offs && local_maplib && !deepbind) (gdb) nn Undefined command: "nn". Try "help". (gdb) n 677 printf_dump(LOG_NEVER, "Apply R_X86_64_COPY @%p with sym=%s (%sver=%d/%s), @%p+0x%lx size=%ld\n", p, symname, veropt?"opt":"", version, vername?vername:"(none)", (void*)offs, rela[i].r_addend, sym->st_size); (gdb) n 678 if(p!=(void*)(offs+rela[i].r_addend)) (gdb) n 679 memmove(p, (void*)(offs+rela[i].r_addend), sym->st_size); (gdb) n 680 sym_elf = FindElfAddress(my_context, offs); (gdb) n 681 if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib); (gdb) n 581 for (int i=0; i<cnt; ++i) { (gdb) n ninitialize (argc=<optimized out>, argv=<optimized out>, env=<optimized out>, emulator=emulator@entry=0x3ffffff360, elfheader=elfheader@entry=0x3ffffff368, exec=exec@entry=1) at /root/box64/src/core.c:1528 1528 RelocateElfPlt(my_context->maplib, NULL, 0, 0, elf_header); (gdb) n 1531 RunDeferredElfInit(emu); (gdb) n 1533 RefreshElfTLS(elf_header); (gdb) n 1535 ResetSpecialCaseMainElf(elf_header); (gdb) 1539 *emulator = emu; (gdb) n 1540 return 0; (gdb) n main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>) at /root/box64/src/main.c:11 11 return emulate(emu, elf_header); (gdb) n Program received signal SIGSEGV, Segmentation fault. 0x0000003ff7236060 in ?? () ``` AddBridge ### src/dynarec/dynarec_native_pass.c Below is a structured walkthrough of native_pass, the core “one‐pass” routine in Box64’s dynarec that scans x86(-64) instructions, emits RISC-V code, and decides where to stop or extend the translated block.