# 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.