Added some minimal set of source (now box64 compile and say hello at least)

This commit is contained in:
ptitSeb 2021-02-28 14:19:04 +01:00
parent 7b50468b61
commit e753c19da1
17 changed files with 2590 additions and 0 deletions

273
CMakeLists.txt Executable file
View File

@ -0,0 +1,273 @@
cmake_minimum_required(VERSION 3.0)
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
find_package(PythonInterp 3)
if(NOT PYTHONINTERP_FOUND)
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
endif()
if(${PYTHON_VERSION_MAJOR} LESS 3)
message( FATAL_ERROR "You need a Python 3 interpretor, CMake will exit." )
endif()
else()
find_package(Python3)
if(NOT Python3_Interpreter_FOUND)
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
endif()
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
endif()
project(box64 C ASM)
enable_testing()
set(default_build_type "RelwithDebInfo")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
if(RPI4ARM64)
add_definitions(-DRPI)
add_definitions(-DRPI4ARM64)
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8")
endif()
if(RK3399)
add_definitions(-DRK3399)
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto")
endif()
if(NOGIT)
add_definitions(-DNOGIT)
endif()
if(HAVE_TRACE)
set(BOX64 box64t)
else()
set(BOX64 box64)
endif()
set(BOX64_ELF_ADDRESS "0x50062800000") #random load address...
if(LD80BITS)
add_definitions(-DHAVE_LD80BITS)
endif()
if(NOALIGN)
add_definitions(-DNOALIGN)
endif()
if(HAVE_TRACE)
add_definitions(-DHAVE_TRACE)
endif()
set(BOX64_ROOT ${CMAKE_SOURCE_DIR})
add_definitions(-std=gnu11 -funwind-tables -fvisibility=hidden)
if(USE_CCACHE)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif()
endif()
include_directories(
"${BOX64_ROOT}/src/include"
"${BOX64_ROOT}/src"
"${BOX64_ROOT}/src/wrapped/generated"
)
# git_head.h is a generated file
set_source_files_properties(
"${BOX64_ROOT}/src/git_head.h"
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
set(ELFLOADER_SRC
"${BOX64_ROOT}/src/main.c"
"${BOX64_ROOT}/src/box64context.c"
"${BOX64_ROOT}/src/build_info.c"
"${BOX64_ROOT}/src/tools/pathcoll.c"
"${BOX64_ROOT}/src/tools/fileutils.c"
"${BOX64_ROOT}/src/tools/wine_tools.c"
)
#set(WRAPPEDS
# "${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
#)
#set(WRAPPEDS_HEAD "${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9_gen.h")
#foreach(A ${WRAPPEDS})
# string(REPLACE ".c" "_private.h" B ${A})
# set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
# set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
#endforeach()
#set(WRAPPER "${BOX64_ROOT}/src/wrapped/generated/wrapper.c" "${BOX64_ROOT}/src/wrapped/generated/wrapper.h")
#add_custom_command(
# OUTPUT "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt"
# COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
# "${BOX64_ROOT}"
# "PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "--"
# ${WRAPPEDS_HEAD}
# MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers.py"
# DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
# BYPRODUCTS ${WRAPPER}
#)
#add_custom_command(
# OUTPUT "${BOX64_ROOT}/src/dynarec/last_run.txt"
# COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_printer.py" "${BOX64_ROOT}"
# MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_printer.py"
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm_instructions.txt"
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm_printer.c"
#)
#add_custom_target(WRAPPERS DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt")
#add_custom_target(PRINTER DEPENDS "${BOX64_ROOT}/src/dynarec/last_run.txt")
# creates git_head.h
#if(ARM_DYNAREC)
# add_custom_command(
# OUTPUT "${BOX64_ROOT}/src/git_head.h"
# COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
# DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
# VERBATIM)
#else()
add_custom_command(
OUTPUT "${BOX64_ROOT}/src/git_head.h"
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
VERBATIM)
#endif()
add_executable(${BOX64} ${ELFLOADER_SRC} "${BOX64_ROOT}/src/git_head.h")
#add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head.h")
#add_dependencies(${BOX64} WRAPPERS)
#add_dependencies(${BOX64} PRINTER)
target_link_libraries(${BOX64} m dl rt pthread)
if(ARM_DYNAREC)
target_link_libraries(${BOX64} dynarec)
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.13")
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
else()
target_link_options(${BOX64} PUBLIC -rdynamic)
target_link_options(${BOX64} PUBLIC -Wl,-Ttext-segment,${BOX64_ELF_ADDRESS})
endif()
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
if(NOT _x86 AND NOT _x86_64)
install(TARGETS ${BOX64}
RUNTIME DESTINATION bin)
#configure_file(system/box64.conf.cmake system/box64.conf)
#install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
endif()
if(NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test14 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
endforeach()

21
cmake_uninstall.cmake.in Normal file
View File

@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

50
runTest.cmake Executable file
View File

@ -0,0 +1,50 @@
# arguments checking
if( NOT TEST_PROGRAM )
message( FATAL_ERROR "Require TEST_PROGRAM to be defined" )
endif( NOT TEST_PROGRAM )
if( NOT TEST_ARGS )
message( FATAL_ERROR "Require TEST_ARGS to be defined" )
endif( NOT TEST_ARGS )
if( NOT TEST_OUTPUT )
message( FATAL_ERROR "Require TEST_OUTPUT to be defined" )
endif( NOT TEST_OUTPUT )
if( NOT TEST_REFERENCE )
message( FATAL_ERROR "Require TEST_REFERENCE to be defined" )
endif( NOT TEST_REFERENCE )
set(ENV{BOX64_LOG} 0)
set(ENV{BOX64_NOBANNER} 1)
if( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
# we are inside box64 folder
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x64lib)
else()
# we are inside build folder
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
endif( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
# run the test program, capture the stdout/stderr and the result var
execute_process(
COMMAND ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
OUTPUT_FILE ${TEST_OUTPUT}
ERROR_VARIABLE TEST_ERROR
RESULT_VARIABLE TEST_RESULT
)
# if the return value is !=0 bail out
if( TEST_RESULT )
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
endif( TEST_RESULT )
# now compare the output with the reference
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_OUTPUT} ${TEST_REFERENCE}
RESULT_VARIABLE TEST_RESULT
)
# again, if return value is !=0 scream and shout
if( TEST_RESULT )
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
endif( TEST_RESULT )
# everything went fine...
message( "Passed: The output of ${TEST_PROGRAM} matches ${TEST_REFERENCE}" )

200
src/box64context.c Executable file
View File

@ -0,0 +1,200 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <signal.h>
#include <sys/mman.h>
#include "box64context.h"
#include "debug.h"
EXPORTDYN
void initAllHelpers(box64context_t* context)
{
static int inited = 0;
if(inited)
return;
my_context = context;
//init_pthread_helper();
//init_signal_helper(context);
inited = 1;
}
EXPORTDYN
void finiAllHelpers(box64context_t* context)
{
static int finied = 0;
if(finied)
return;
//fini_pthread_helper(context);
//fini_signal_helper();
//cleanAlternate();
//fini_custommem_helper(context);
finied = 1;
}
/// maxval not inclusive
int getrand(int maxval)
{
if(maxval<1024) {
return ((random()&0x7fff)*maxval)/0x7fff;
}
uint64_t r = random();
r = (r*maxval) / RAND_MAX;
return r;
}
void free_tlsdatasize(void* p)
{
if(!p)
return;
tlsdatasize_t *data = (tlsdatasize_t*)p;
free(data->tlsdata);
free(p);
}
EXPORTDYN
box64context_t *NewBox64Context(int argc)
{
#ifdef BUILD_DYNAMIC
if(my_context) {
++my_context->count;
return my_context;
}
#endif
// init and put default values
box64context_t *context = my_context = (box64context_t*)calloc(1, sizeof(box64context_t));
context->deferedInit = 1;
context->sel_serial = 1;
//init_custommem_helper(context);
context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
//context->dlprivate = NewDLPrivate();
context->argc = argc;
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255);
context->canary[getrand(4)] = 0;
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
initAllHelpers(context);
return context;
}
EXPORTDYN
void FreeBox64Context(box64context_t** context)
{
if(!context)
return;
box64context_t* ctx = *context; // local copy to do the cleanning
FreeCollection(&ctx->box64_path);
FreeCollection(&ctx->box64_ld_lib);
FreeCollection(&ctx->box64_emulated_libs);
// stop trace now
/*if(ctx->dec)
DeleteX86TraceDecoder(&ctx->dec);
if(ctx->zydis)
DeleteX86Trace(ctx);*/
free(ctx->argv);
for (int i=0; i<ctx->envc; ++i)
free(ctx->envv[i]);
free(ctx->envv);
for(int i=0; i<MAX_SIGNAL; ++i)
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
signal(i, SIG_DFL);
}
*context = NULL; // bye bye my_context
//CleanStackSize(ctx);
#ifndef BUILD_LIB
if(ctx->box64lib)
dlclose(ctx->box64lib);
#endif
//FreeDLPrivate(&ctx->dlprivate);
free(ctx->stack);
free(ctx->fullpath);
free(ctx->box64path);
void* ptr;
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
free_tlsdatasize(ptr);
pthread_setspecific(ctx->tlskey, NULL);
}
pthread_key_delete(ctx->tlskey);
if(ctx->tlsdata)
free(ctx->tlsdata);
finiAllHelpers(ctx);
free(ctx);
}
/*
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
int idx = ctx->elfsize;
if(idx==ctx->elfcap) {
// resize...
ctx->elfcap += 16;
ctx->elfs = (elfheader_t**)realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
}
ctx->elfs[idx] = head;
ctx->elfsize++;
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
return idx;
}
*/
int AddTLSPartition(box64context_t* context, int tlssize) {
int oldsize = context->tlssize;
context->tlssize += tlssize;
context->tlsdata = realloc(context->tlsdata, context->tlssize);
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
// clean GS segment for current emu
if(my_context) {
//ResetSegmentsCache(thread_get_emu());
if(!(++context->sel_serial))
++context->sel_serial;
}
return -context->tlssize; // negative offset
}
/*
void add_neededlib(needed_libs_t* needed, library_t* lib)
{
if(!needed)
return;
if(needed->size == needed->cap) {
needed->cap += 8;
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
}
needed->libs[needed->size++] = lib;
}
void free_neededlib(needed_libs_t* needed)
{
if(!needed)
return;
needed->cap = 0;
needed->size = 0;
if(needed->libs)
free(needed->libs);
needed->libs = NULL;
}
*/

8
src/box64version.h Executable file
View File

@ -0,0 +1,8 @@
#ifndef __BOX64_VERSION_H_
#define __BOX64_VERSION_H_
#define BOX64_MAJOR 0
#define BOX64_MINOR 0
#define BOX64_REVISION 1
#endif //__BOX64_VERSION_H_

27
src/build_info.c Executable file
View File

@ -0,0 +1,27 @@
#include <stdio.h>
#include "debug.h"
#include "box64version.h"
#ifdef NOGIT
#define GITREV "nogit"
#else
#include "git_head.h"
#endif
void PrintBox64Version()
{
printf("Box64%s%s v%d.%d.%d %s built on %s %s\n",
#ifdef HAVE_TRACE
" with trace",
#else
"",
#endif
#ifdef DYNAREC
" with Dynarec",
#else
"",
#endif
BOX64_MAJOR, BOX64_MINOR, BOX64_REVISION,
GITREV,
__DATE__, __TIME__);
}

6
src/build_info.h Executable file
View File

@ -0,0 +1,6 @@
#ifndef __BUILD_INFO_H__
#define __BUILD_INFO_H__
void PrintBox64Version();
#endif //__BUILD_INFO_H__

74
src/include/box64context.h Executable file
View File

@ -0,0 +1,74 @@
#ifndef __BOX64CONTEXT_H_
#define __BOX64CONTEXT_H_
#include <stdint.h>
#include <pthread.h>
#include "pathcoll.h"
typedef void* (*procaddess_t)(const char* name);
typedef void* (*vkprocaddess_t)(void* instance, const char* name);
#define MAX_SIGNAL 64
typedef struct tlsdatasize_s {
int32_t tlssize;
void* tlsdata;
} tlsdatasize_t;
void free_tlsdatasize(void* p);
typedef struct box64context_s {
path_collection_t box64_path; // PATH env. variable
path_collection_t box64_ld_lib; // LD_LIBRARY_PATH env. variable
path_collection_t box64_emulated_libs; // Collection of libs that should not be wrapped
int x86trace;
int trace_tid;
uint32_t sel_serial; // will be increment each time selectors changes
//zydis_t *zydis; // dlopen the zydis dissasembler
void* box64lib; // dlopen on box86 itself
int argc;
char** argv;
int envc;
char** envv;
char* fullpath;
char* box64path; // path of current box86 executable
uint32_t stacksz;
int stackalign;
void* stack; // alocated stack
int deferedInit;
pthread_key_t tlskey; // then tls key to have actual tlsdata
void* tlsdata; // the initial global tlsdata
int32_t tlssize; // wanted size of tlsdata
//zydis_dec_t *dec; // trace
uint8_t canary[4];
uintptr_t signals[MAX_SIGNAL];
uintptr_t restorer[MAX_SIGNAL];
int onstack[MAX_SIGNAL];
int is_sigaction[MAX_SIGNAL];
int no_sigsegv;
int no_sigill;
} box64context_t;
extern box64context_t *my_context; // global context
box64context_t *NewBox64Context(int argc);
void FreeBox64Context(box64context_t** context);
// return the tlsbase (negative) for the new TLS partition created (no partition index is stored in the context)
int AddTLSPartition(box64context_t* context, int tlssize);
#endif //__BOX64CONTEXT_H_

42
src/include/debug.h Executable file
View File

@ -0,0 +1,42 @@
#ifndef __DEBUG_H_
#define __DEBUG_H_
#include <stdint.h>
typedef struct box64context_s box64context_t;
extern int box64_log; // log level
extern int box64_dynarec_log;
extern int box64_dynarec;
extern int box64_pagesize;
extern int dlsym_error; // log dlsym error
extern int trace_xmm; // include XMM reg in trace?
extern int trace_emm; // include EMM reg in trace?
extern int allow_missing_libs;
extern int box64_steam;
extern int box64_nopulse; // disabling the use of wrapped pulseaudio
extern int box64_nogtk; // disabling the use of wrapped gtk
extern int box64_novulkan; // disabling the use of wrapped vulkan
extern uintptr_t trace_start, trace_end;
extern char* trace_func;
extern uintptr_t fmod_smc_start, fmod_smc_end; // to handle libfmod (from Unreal) SMC (self modifying code)
extern uint32_t default_fs;
extern int jit_gdb; // launch gdb when a segfault is trapped
extern int box64_tcmalloc_minimal; // when using tcmalloc_minimal
#define LOG_NONE 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#define LOG_DUMP 3
extern FILE* ftrace;
#define printf_log(L, ...) do {if(L<=box64_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
#define dynarec_log(L, ...) do {if(L<=box64_dynarec_log) {fprintf(ftrace, __VA_ARGS__); /*fflush(ftrace);*/}} while(0)
#define EXPORT __attribute__((visibility("default")))
#ifdef BUILD_DYNAMIC
#define EXPORTDYN __attribute__((visibility("default")))
#else
#define EXPORTDYN
#endif
#endif //__DEBUG_H_

23
src/include/fileutils.h Executable file
View File

@ -0,0 +1,23 @@
#ifndef __FILEUTILS_H_
#define __FILEUTILS_H_
#include "pathcoll.h"
#define IS_EXECUTABLE (1<<0)
#define IS_FILE (1<<1)
// 0 : doesn't exist, 1: Does exist
int FileExist(const char* filename, int flags);
// find a file, using Path if needed
char* ResolveFile(const char* filename, path_collection_t* paths);
// 1: if file is an x86 elf, 0: if not (or not found)
int FileIsX64ELF(const char* filename);
#if defined(RPI) || defined(RK3399)
void sanitize_mojosetup_gtk_background();
#endif
#endif //__FILEUTILS_H_

678
src/include/khash.h Executable file
View File

@ -0,0 +1,678 @@
/* The MIT License
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "khash.h"
KHASH_MAP_INIT_INT(32, char)
int main() {
int ret, is_missing;
khiter_t k;
khash_t(32) *h = kh_init(32);
k = kh_put(32, h, 5, &ret);
kh_value(h, k) = 10;
k = kh_get(32, h, 10);
is_missing = (k == kh_end(h));
k = kh_get(32, h, 5);
kh_del(32, h, k);
for (k = kh_begin(h); k != kh_end(h); ++k)
if (kh_exist(h, k)) kh_value(h, k) = 1;
kh_destroy(32, h);
return 0;
}
*/
/*
2013-05-02 (0.2.8):
* Use quadratic probing. When the capacity is power of 2, stepping function
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
hashing on cache performance and is more robust than linear probing.
In theory, double hashing should be more robust than quadratic probing.
However, my implementation is probably not for large hash tables, because
the second hash function is closely tied to the first hash function,
which reduce the effectiveness of double hashing.
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
2011-12-29 (0.2.7):
* Minor code clean up; no actual effect.
2011-09-16 (0.2.6):
* The capacity is a power of 2. This seems to dramatically improve the
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
- http://code.google.com/p/ulib/
- http://nothings.org/computer/judy/
* Allow to optionally use linear probing which usually has better
performance for random input. Double hashing is still the default as it
is more robust to certain non-random input.
* Added Wang's integer hash function (not used by default). This hash
function is more robust to certain non-random input.
2011-02-14 (0.2.5):
* Allow to declare global functions.
2009-09-26 (0.2.4):
* Improve portability
2008-09-19 (0.2.3):
* Corrected the example
* Improved interfaces
2008-09-11 (0.2.2):
* Improved speed a little in kh_put()
2008-09-10 (0.2.1):
* Added kh_clear()
* Fixed a compiling error
2008-09-02 (0.2.0):
* Changed to token concatenation which increases flexibility.
2008-08-31 (0.1.2):
* Fixed a bug in kh_get(), which has not been tested previously.
2008-08-31 (0.1.1):
* Added destructor
*/
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
/*!
@header
Generic hash table library.
*/
#define AC_VERSION_KHASH_H "0.2.8"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
/* compiler specific configuration */
#if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t;
#elif ULONG_MAX == 0xffffffffu
typedef unsigned long khint32_t;
#endif
#if ULONG_MAX == ULLONG_MAX
typedef unsigned long khint64_t;
#else
typedef unsigned long long khint64_t;
#endif
#ifdef _MSC_VER
#define kh_inline __inline
#else
#define kh_inline inline
#endif
typedef khint32_t khint_t;
typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#endif
#ifndef kcalloc
#define kcalloc(N,Z) calloc(N,Z)
#endif
#ifndef kmalloc
#define kmalloc(Z) malloc(Z)
#endif
#ifndef krealloc
#define krealloc(P,Z) realloc(P,Z)
#endif
#ifndef kfree
#define kfree(P) free(P)
#endif
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct kh_##name##_s{ \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
kfree((void *)h->keys); kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \
} \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \
} \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) return -1; \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) return -1; \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size<<1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \
i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
else x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; ++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */
/*! @function
@abstract Integer hash function
@param key The integer [khint32_t]
@return The hash value [khint_t]
*/
#define kh_int_hash_func(key) (khint32_t)(key)
/*! @function
@abstract Integer comparison function
*/
#define kh_int_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract 64-bit integer hash function
@param key The integer [khint64_t]
@return The hash value [khint_t]
*/
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
/*! @function
@abstract 64-bit integer comparison function
*/
#define kh_int64_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract const char* hash function
@param s Pointer to a null terminated string
@return The hash value
*/
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
return h;
}
/*! @function
@abstract Another interface to const char* hash function
@param key Pointer to a null terminated string [const char*]
@return The hash value [khint_t]
*/
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
/*! @function
@abstract Const char* comparison function
*/
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
/* --- END OF HASH FUNCTIONS --- */
/* Other convenient macros... */
/*!
@abstract Type of the hash table.
@param name Name of the hash table [symbol]
*/
#define khash_t(name) kh_##name##_t
/*! @function
@abstract Initiate a hash table.
@param name Name of the hash table [symbol]
@return Pointer to the hash table [khash_t(name)*]
*/
#define kh_init(name) kh_init_##name()
/*! @function
@abstract Destroy a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_destroy(name, h) kh_destroy_##name(h)
/*! @function
@abstract Reset a hash table without deallocating memory.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_clear(name, h) kh_clear_##name(h)
/*! @function
@abstract Resize a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param s New size [khint_t]
*/
#define kh_resize(name, h, s) kh_resize_##name(h, s)
/*! @function
@abstract Insert a key to the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@param r Extra return code: 0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
/*! @function
@abstract Retrieve a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/
#define kh_get(name, h, k) kh_get_##name(h, k)
/*! @function
@abstract Remove a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Iterator to the element to be deleted [khint_t]
*/
#define kh_del(name, h, k) kh_del_##name(h, k)
/*! @function
@abstract Test whether a bucket contains data.
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return 1 if containing data; 0 otherwise [int]
*/
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
/*! @function
@abstract Get key given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Key [type of keys]
*/
#define kh_key(h, x) ((h)->keys[x])
/*! @function
@abstract Get value given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
#define kh_val(h, x) ((h)->vals[x])
/*! @function
@abstract Alias of kh_val()
*/
#define kh_value(h, x) ((h)->vals[x])
/*! @function
@abstract Get the start iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The start iterator [khint_t]
*/
#define kh_begin(h) (khint_t)(0)
/*! @function
@abstract Get the end iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The end iterator [khint_t]
*/
#define kh_end(h) ((h)->n_buckets)
/*! @function
@abstract Get the number of elements in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of elements in the hash table [khint_t]
*/
#define kh_size(h) ((h)->size)
/*! @function
@abstract Get the number of buckets in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of buckets in the hash table [khint_t]
*/
#define kh_n_buckets(h) ((h)->n_buckets)
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
(vvar) = kh_val(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param code Block of code to execute
*/
#define kh_foreach_key(h, kvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(vvar) = kh_val(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param rvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value_ref(h, rvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(rvar) = &kh_val(h,__i); \
code; \
} }
/* More conenient interfaces */
/*! @function
@abstract Instantiate a hash set containing integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT(name) \
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
#define KHASH_SET_DECLARE_INT(name) \
KHASH_DECLARE(name, khint32_t, char)
#define KHASH_SET_IMPL_INT(name) \
__KHASH_IMPL(name, , khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT(name, khval_t) \
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
#define KHASH_MAP_DECLARE_INT(name, khval_t) \
KHASH_DECLARE(name, khint32_t, khval_t)
#define KHASH_MAP_IMPL_INT(name, khval_t) \
__KHASH_IMPL(name, , khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT64(name) \
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
#define KHASH_SET_DECLARE_INT64(name) \
KHASH_DECLARE(name, khint64_t, char)
#define KHASH_SET_IMPL_INT64(name) \
__KHASH_IMPL(name, , khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
#define KHASH_MAP_DECLARE_INT64(name, khval_t) \
KHASH_DECLARE(name, khint64_t, khval_t)
#define KHASH_MAP_IMPL_INT64(name, khval_t) \
__KHASH_IMPL(name, , khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t;
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_STR(name) \
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
#define KHASH_SET_DECLARE_STR(name) \
KHASH_DECLARE(name, kh_cstr_t, char)
#define KHASH_SET_IMPL_STR(name) \
__KHASH_IMPL(name, , kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_STR(name, khval_t) \
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#define KHASH_MAP_DECLARE_STR(name, khval_t) \
KHASH_DECLARE(name, kh_cstr_t, khval_t)
#define KHASH_MAP_IMPL_STR(name, khval_t) \
__KHASH_IMPL(name, , kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#endif /* __AC_KHASH_H */

23
src/include/pathcoll.h Executable file
View File

@ -0,0 +1,23 @@
#ifndef __PATHCOLL_H_
#define __PATHCOLL_H_
// utility to handle path collection (like BOX86_PATH or BOX86_LD_LIBRARY_PATH)
// paths can be resized with realloc, so don't take address as invariant
typedef struct path_collection_s
{
int size;
int cap;
char** paths;
} path_collection_t;
void ParseList(const char* List, path_collection_t* collection, int folder);
void FreeCollection(path_collection_t* collection);
void CopyCollection(path_collection_t* to, path_collection_t* from);
void AddPath(const char* path, path_collection_t* collection, int folder);
void PrependPath(const char* path, path_collection_t* collection, int folder);
void AppendList(path_collection_t* collection, const char* List, int folder);
void PrependList(path_collection_t* collection, const char* List, int folder);
int FindInCollection(const char* path, path_collection_t* collection);
#endif //__PATHCOLL_H_

13
src/include/wine_tools.h Executable file
View File

@ -0,0 +1,13 @@
#ifndef __WINE_TOOLS_H__
#define __WINE_TOOLS_H__
void wine_prereserve(const char* reserve);
extern int wine_preloaded;
void* get_wine_prereserve();
#ifdef DYNAREC
void dynarec_wine_prereserve();
#endif
#endif //__WINE_TOOLS_H__

734
src/main.c Executable file
View File

@ -0,0 +1,734 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <signal.h>
#include <sys/syscall.h>
#include "build_info.h"
#include "debug.h"
#include "fileutils.h"
#include "box64context.h"
#include "wine_tools.h"
box64context_t *my_context = NULL;
int box64_log = LOG_NONE;
int box64_nobanner = 0;
int box64_dynarec_log = LOG_INFO; //LOG_NONE;
int box64_pagesize;
int box64_dynarec = 0;
int dlsym_error = 0;
int trace_xmm = 0;
int trace_emm = 0;
#ifdef HAVE_TRACE
uint64_t start_cnt = 0;
#ifdef DYNAREC
int box64_dynarec_trace = 0;
#endif
#endif
int box64_zoom = 0;
int x11threads = 0;
int x11glx = 1;
int allow_missing_libs = 0;
int fix_64bit_inodes = 0;
int box64_steam = 0;
int box64_nopulse = 0;
int box64_nogtk = 0;
int box64_novulkan = 0;
char* libGL = NULL;
uintptr_t trace_start = 0, trace_end = 0;
char* trace_func = NULL;
uintptr_t fmod_smc_start = 0;
uintptr_t fmod_smc_end = 0;
uint32_t default_fs = 0;
int jit_gdb = 0;
int box64_tcmalloc_minimal = 0;
FILE* ftrace = NULL;
int ftrace_has_pid = 0;
void openFTrace()
{
char* t = getenv("BOX64_TRACE_FILE");
char tmp[500];
char* p = t;
if(p && strstr(t, "%pid")) {
strcpy(tmp, p);
char* c = strstr(tmp, "%pid");
*c = 0; // cut
char pid[10];
sprintf(pid, "%d", getpid());
strcat(tmp, pid);
c = strstr(p, "%pid") + strlen("%pid");
strcat(tmp, c);
p = tmp;
ftrace_has_pid = 1;
}
if(p) {
ftrace = fopen(p, "w");
if(!ftrace) {
ftrace = stdout;
printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s)\n", p, strerror(errno));
} else {
if(!box64_nobanner)
printf("BOX64 Trace redirected to \"%s\"\n", p);
}
}
}
void my_child_fork()
{
if(ftrace_has_pid) {
// open a new ftrace...
fclose(ftrace);
openFTrace();
}
}
EXPORTDYN
void LoadLogEnv()
{
ftrace = stdout;
const char *p = getenv("BOX64_NOBANNER");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='1')
box64_nobanner = p[0]-'0';
}
}
p = getenv("BOX64_LOG");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0'+LOG_NONE && p[1]<='0'+LOG_DEBUG)
box64_log = p[0]-'0';
} else {
if(!strcasecmp(p, "NONE"))
box64_log = LOG_NONE;
else if(!strcasecmp(p, "INFO"))
box64_log = LOG_INFO;
else if(!strcasecmp(p, "DEBUG"))
box64_log = LOG_DEBUG;
else if(!strcasecmp(p, "DUMP"))
box64_log = LOG_DUMP;
}
if(!box64_nobanner)
printf_log(LOG_INFO, "Debug level is %d\n", box64_log);
}
#ifdef HAVE_TRACE
p = getenv("BOX64_TRACE_XMM");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
trace_xmm = p[0]-'0';
}
}
p = getenv("BOX64_TRACE_EMM");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
trace_emm = p[0]-'0';
}
}
p = getenv("BOX64_TRACE_START");
if(p) {
char* p2;
start_cnt = strtoll(p, &p2, 10);
printf_log(LOG_INFO, "Will start trace only after %llu instructions\n", start_cnt);
}
#endif
// grab BOX64_TRACE_FILE envvar, and change %pid to actual pid is present in the name
openFTrace();
// Other BOX64 env. var.
p = getenv("BOX64_DLSYM_ERROR");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
dlsym_error = p[0]-'0';
}
}
p = getenv("BOX64_X11THREADS");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
x11threads = p[0]-'0';
}
if(x11threads)
printf_log(LOG_INFO, "Try to Call XInitThreads if libX11 is loaded\n");
}
p = getenv("BOX64_X11GLX");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
x11glx = p[0]-'0';
}
if(x11glx)
printf_log(LOG_INFO, "Hack to force libX11 GLX extension present\n");
else
printf_log(LOG_INFO, "Disabled Hack to force libX11 GLX extension present\n");
}
p = getenv("BOX64_LIBGL");
if(p)
libGL = strdup(p);
if(!libGL) {
p = getenv("SDL_VIDEO_GL_DRIVER");
if(p)
libGL = strdup(p);
}
if(libGL) {
printf_log(LOG_INFO, "BOX64 using \"%s\" as libGL.so.1\n", p);
}
p = getenv("BOX64_ALLOWMISSINGLIBS");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
allow_missing_libs = p[0]-'0';
}
if(allow_missing_libs)
printf_log(LOG_INFO, "Allow missing needed libs\n");
}
p = getenv("BOX64_NOPULSE");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
box64_nopulse = p[0]-'0';
}
if(box64_nopulse)
printf_log(LOG_INFO, "Disable the use of pulseaudio libs\n");
}
p = getenv("BOX64_NOGTK");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
box64_nogtk = p[0]-'0';
}
if(box64_nogtk)
printf_log(LOG_INFO, "Disable the use of wrapped gtk libs\n");
}
p = getenv("BOX64_NOVULKAN");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
box64_novulkan = p[0]-'0';
}
if(box64_novulkan)
printf_log(LOG_INFO, "Disable the use of wrapped vulkan libs\n");
}
p = getenv("BOX64_FIX_64BIT_INODES");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
fix_64bit_inodes = p[0]-'0';
}
if(fix_64bit_inodes)
printf_log(LOG_INFO, "Fix 64bit inodes\n");
}
p = getenv("BOX64_JITGDB");
if(p) {
if(strlen(p)==1) {
if(p[0]>='0' && p[1]<='0'+1)
jit_gdb = p[0]-'0';
}
if(jit_gdb)
printf_log(LOG_INFO, "Launch %s on segfault\n", (jit_gdb==2)?"gdbserver":"gdb");
}
box64_pagesize = sysconf(_SC_PAGESIZE);
if(!box64_pagesize)
box64_pagesize = 4096;
}
EXPORTDYN
void LoadEnvPath(path_collection_t *col, const char* defpath, const char* env)
{
const char* p = getenv(env);
if(p) {
printf_log(LOG_INFO, "%s: ", env);
ParseList(p, col, 1);
} else {
printf_log(LOG_INFO, "Using default %s: ", env);
ParseList(defpath, col, 1);
}
if(LOG_INFO<=box64_log) {
for(int i=0; i<col->size; i++)
printf_log(LOG_INFO, "%s%s", col->paths[i], (i==col->size-1)?"\n":":");
}
}
EXPORTDYN
int CountEnv(const char** env)
{
// count, but remove all BOX64_* environnement
// also remove PATH and LD_LIBRARY_PATH
// but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH
const char** p = env;
int c = 0;
while(*p) {
if(strncmp(*p, "BOX64_", 6)!=0)
//if(!(strncmp(*p, "PATH=", 5)==0 || strncmp(*p, "LD_LIBRARY_PATH=", 16)==0))
++c;
++p;
}
return c+2;
}
EXPORTDYN
int GatherEnv(char*** dest, const char** env, const char* prog)
{
// Add all but BOX64_* environnement
// but add 2 for default BOX64_PATH and BOX64_LD_LIBRARY_PATH
const char** p = env;
int idx = 0;
int path = 0;
int ld_path = 0;
while(*p) {
if(strncmp(*p, "BOX64_PATH=", 11)==0) {
(*dest)[idx++] = strdup(*p+6);
path = 1;
} else if(strncmp(*p, "BOX64_LD_LIBRARY_PATH=", 22)==0) {
(*dest)[idx++] = strdup(*p+6);
ld_path = 1;
} else if(strncmp(*p, "_=", 2)==0) {
/*int l = strlen(prog);
char tmp[l+3];
strcpy(tmp, "_=");
strcat(tmp, prog);
(*dest)[idx++] = strdup(tmp);*/
} else if(strncmp(*p, "BOX64_", 6)!=0) {
(*dest)[idx++] = strdup(*p);
/*if(!(strncmp(*p, "PATH=", 5)==0 || strncmp(*p, "LD_LIBRARY_PATH=", 16)==0)) {
}*/
}
++p;
}
// update the calloc of envv when adding new variables here
if(!path) {
(*dest)[idx++] = strdup("BOX64_PATH=.:bin");
}
if(!ld_path) {
(*dest)[idx++] = strdup("BOX64_LD_LIBRARY_PATH=.:lib");
}
// add "_=prog" at the end...
if(prog) {
int l = strlen(prog);
char tmp[l+3];
strcpy(tmp, "_=");
strcat(tmp, prog);
(*dest)[idx++] = strdup(tmp);
}
// and a final NULL
(*dest)[idx++] = 0;
return 0;
}
void PrintHelp() {
printf("\n\nThis is Box86, the Linux x86 emulator with a twist\n");
printf("\nUsage is box86 [options] path/to/software [args]\n");
printf("to launch x86 software\n");
printf(" options can be :\n");
printf(" '-v'|'--version' to print box86 version and quit\n");
printf(" '-h'|'--help' to print box86 help and quit\n");
printf("You can also set some environment variables:\n");
printf(" BOX64_PATH is the box86 version of PATH (default is '.:bin')\n");
printf(" BOX64_LD_LIBRARY_PATH is the box86 version LD_LIBRARY_PATH (default is '.:lib')\n");
printf(" BOX64_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed debug info\n");
printf(" BOX64_NOBANNER with 0/1 to enable/disable the printing of box86 version and build at start\n");
#ifdef HAVE_TRACE
printf(" BOX64_TRACE with 1 to enable x86 execution trace\n");
printf(" or with XXXXXX-YYYYYY to enable x86 execution trace only between address\n");
printf(" or with FunctionName to enable x86 execution trace only in one specific function\n");
printf(" use BOX64_TRACE_INIT instead of BOX_TRACE to start trace before init of Libs and main program\n\t (function name will probably not work then)\n");
printf(" BOX64_TRACE_XMM with 1 to enable dump of SSE/SSE2 register along with regular registers\n");
printf(" BOX64_TRACE_START with N to enable trace after N instructions\n");
#endif
printf(" BOX64_TRACE_FILE with FileName to redirect logs in a file");
printf(" BOX64_DLSYM_ERROR with 1 to log dlsym errors\n");
printf(" BOX64_LOAD_ADDR=0xXXXXXX try to load at 0xXXXXXX main binary (if binary is a PIE)\n");
printf(" BOX64_NOSIGSEGV=1 to disable handling of SigSEGV\n");
printf(" BOX64_NOSIGILL=1 to disable handling of SigILL\n");
printf(" BOX64_X11THREADS=1 to call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)");
printf(" BOX64_LIBGL=libXXXX set the name (and optionnaly full path) for libGL.so.1\n");
printf(" BOX64_LD_PRELOAD=XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary\n");
printf(" BOX64_ALLOWMISSINGLIBS with 1 to allow to continue even if a lib is missing (unadvised, will probably crash later)\n");
printf(" BOX64_NOPULSE=1 to disable the loading of pulseaudio libs\n");
printf(" BOX64_NOGTK=1 to disable the loading of wrapped gtk libs\n");
printf(" BOX64_NOVULKAN=1 to disable the loading of wrapped vulkan libs\n");
printf(" BOX64_JITGDB with 1 to launch \"gdb\" when a segfault is trapped, attached to the offending process\n");
}
EXPORTDYN
void LoadEnvVars(box64context_t *context)
{
// check BOX64_LD_LIBRARY_PATH and load it
LoadEnvPath(&context->box64_ld_lib, ".:lib:lib64:x86_64", "BOX64_LD_LIBRARY_PATH");
if(FileExist("/lib/x86_64-linux-gnu", 0))
AddPath("/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
if(FileExist("/usr/lib/x86_64-linux-gnu", 0))
AddPath("/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
if(FileExist("/lib/i686-pc-linux-gnu", 0))
AddPath("/lib/i686-pc-linux-gnu", &context->box64_ld_lib, 1);
if(FileExist("/usr/lib/i686-pc-linux-gnu", 0))
AddPath("/usr/lib/i686-pc-linux-gnu", &context->box64_ld_lib, 1);
if(FileExist("/usr/lib32", 0))
AddPath("/usr/lib32", &context->box64_ld_lib, 1);
if(getenv("LD_LIBRARY_PATH"))
PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world
if(getenv("BOX64_EMULATED_LIBS")) {
char* p = getenv("BOX64_EMULATED_LIBS");
ParseList(p, &context->box64_emulated_libs, 0);
if (my_context->box64_emulated_libs.size && box64_log) {
printf_log(LOG_INFO, "BOX64 will force the used of emulated libs for ");
for (int i=0; i<context->box64_emulated_libs.size; ++i)
printf_log(LOG_INFO, "%s ", context->box64_emulated_libs.paths[i]);
printf_log(LOG_INFO, "\n");
}
}
if(getenv("BOX64_NOSIGSEGV")) {
if (strcmp(getenv("BOX64_NOSIGSEGV"), "1")==0)
context->no_sigsegv = 1;
printf_log(LOG_INFO, "BOX64: Disabling handling of SigSEGV\n");
}
if(getenv("BOX64_NOSIGILL")) {
if (strcmp(getenv("BOX64_NOSIGILL"), "1")==0)
context->no_sigill = 1;
printf_log(LOG_INFO, "BOX64: Disabling handling of SigILL\n");
}
// check BOX64_PATH and load it
LoadEnvPath(&context->box64_path, ".:bin", "BOX64_PATH");
if(getenv("PATH"))
AppendList(&context->box64_path, getenv("PATH"), 1); // in case some of the path are for x86 world
#ifdef HAVE_TRACE
char* p = getenv("BOX64_TRACE");
if(p) {
if (strcmp(p, "0"))
context->x86trace = 1;
}
p = getenv("BOX64_TRACE_INIT");
if(p) {
if (strcmp(p, "0"))
context->x86trace = 1;
}
if(my_context->x86trace) {
/*printf_log(LOG_INFO, "Initializing Zydis lib\n");
if(InitX86Trace(my_context)) {
printf_log(LOG_INFO, "Zydis init failed, no x86 trace activated\n");
context->x86trace = 0;
}*/
context->x86trace = 0; // not implemented yet
}
#endif
}
EXPORTDYN
void setupTraceInit(box64context_t* context)
{
#ifdef HAVE_TRACE
char* p = getenv("BOX64_TRACE_INIT");
if(p) {
setbuf(stdout, NULL);
uintptr_t trace_start=0, trace_end=0;
if (strcmp(p, "1")==0)
SetTraceEmu(0, 0);
else if (strchr(p,'-')) {
if(sscanf(p, "%d-%d", &trace_start, &trace_end)!=2) {
if(sscanf(p, "0x%X-0x%X", &trace_start, &trace_end)!=2)
sscanf(p, "%x-%x", &trace_start, &trace_end);
}
if(trace_start || trace_end)
SetTraceEmu(trace_start, trace_end);
} else {
if (0/*GetSymbolStartEnd(GetMapSymbol(my_context->maplib), p, &trace_start, &trace_end)*/) {
SetTraceEmu(trace_start, trace_end);
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
} else {
printf_log(LOG_NONE, "Warning, symbol to Traced (\"%s\") not found, disabling trace\n", p);
SetTraceEmu(0, 100); // disabling trace, mostly
}
}
} else {
p = getenv("BOX64_TRACE");
if(p)
if (strcmp(p, "0"))
SetTraceEmu(0, 1);
}
#endif
}
EXPORTDYN
void setupTrace(box64context_t* context)
{
#ifdef HAVE_TRACE
char* p = getenv("BOX64_TRACE");
if(p) {
setbuf(stdout, NULL);
uintptr_t trace_start=0, trace_end=0;
if (strcmp(p, "1")==0)
SetTraceEmu(0, 0);
else if (strchr(p,'-')) {
if(sscanf(p, "%d-%d", &trace_start, &trace_end)!=2) {
if(sscanf(p, "0x%X-0x%X", &trace_start, &trace_end)!=2)
sscanf(p, "%x-%x", &trace_start, &trace_end);
}
if(trace_start || trace_end) {
SetTraceEmu(trace_start, trace_end);
if(!trace_start && trace_end==1) {
printf_log(LOG_INFO, "TRACE enabled but inactive\n");
} else {
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
}
}
} else {
if (0/*GetGlobalSymbolStartEnd(my_context->maplib, p, &trace_start, &trace_end)*/) {
SetTraceEmu(trace_start, trace_end);
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
} else if(0/*GetLocalSymbolStartEnd(my_context->maplib, p, &trace_start, &trace_end, NULL)*/) {
SetTraceEmu(trace_start, trace_end);
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)trace_start, (void*)trace_end);
} else {
printf_log(LOG_NONE, "Warning, symbol to Traced (\"%s\") not found, trying to set trace later\n", p);
SetTraceEmu(0, 1); // disabling trace, mostly
trace_func = strdup(p);
}
}
}
#endif
}
void endBox86()
{
if(!my_context)
return;
// all done, free context
FreeBox64Context(&my_context);
if(libGL) {
free(libGL);
libGL = NULL;
}
}
static void free_contextargv()
{
for(int i=0; i<my_context->argc; ++i)
free(my_context->argv[i]);
}
const char **environ __attribute__((weak)) = NULL;
int main(int argc, const char **argv, const char **env) {
//init_auxval(argc, argv, environ?environ:env);
// trying to open and load 1st arg
if(argc==1) {
PrintBox64Version();
PrintHelp();
return 1;
}
// init random seed
srandom(time(NULL));
// check BOX64_LOG debug level
LoadLogEnv();
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();
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(!box64_nobanner)
PrintBox64Version();
// precheck, for win-preload
if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader"))) {
// wine-preloader detecter, skipping it if next arg exist and is an x86 binary
int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0;
if(x64) {
prog = argv[++nextarg];
printf_log(LOG_INFO, "BOX64: Wine preloader detected, loading \"%s\" directly\n", prog);
//wine_preloaded = 1;
}
}
// check if this is wine
if(!strcmp(prog, "wine") || (strlen(prog)>5 && !strcmp(prog+strlen(prog)-strlen("/wine"), "/wine"))) {
const char* prereserve = getenv("WINEPRELOADRESERVE");
printf_log(LOG_INFO, "BOX64: Wine detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:"");
if(wine_preloaded)
wine_prereserve(prereserve);
// special case for winedbg, doesn't work anyway
if(argv[nextarg+1] && strstr(argv[nextarg+1], "winedbg")==argv[nextarg+1]) {
printf_log(LOG_NONE, "winedbg detected, not launching it!\n");
exit(0); // exiting, it doesn't work anyway
}
}
// Create a new context
my_context = NewBox64Context(argc - nextarg);
// check BOX64_LD_LIBRARY_PATH and load it
LoadEnvVars(my_context);
if(argv[0][0]=='/')
my_context->box64path = strdup(argv[0]);
else
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**)calloc(my_context->envc+4, sizeof(char*));
GatherEnv(&my_context->envv, environ?environ:env, my_context->box64path);
if(box64_log>=LOG_DUMP) {
for (int i=0; i<my_context->envc; ++i)
printf_log(LOG_DUMP, " Env[%02d]: %s\n", i, my_context->envv[i]);
}
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 && box64_log) {
printf_log(LOG_INFO, "BOX64 try to Preload ");
for (int i=0; i<ld_preload.size; ++i)
printf_log(LOG_INFO, "%s ", ld_preload.paths[i]);
printf_log(LOG_INFO, "\n");
}
} else {
if(getenv("LD_PRELOAD")) {
char* p = getenv("LD_PRELOAD");
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
ParseList(p, &ld_preload, 0);
if (ld_preload.size && box64_log) {
printf_log(LOG_INFO, "BOX64 try to Preload ");
for (int i=0; i<ld_preload.size; ++i)
printf_log(LOG_INFO, "%s ", ld_preload.paths[i]);
printf_log(LOG_INFO, "\n");
}
}
}
// lets build argc/argv stuff
printf_log(LOG_INFO, "Looking for %s\n", prog);
if(strchr(prog, '/'))
my_context->argv[0] = strdup(prog);
else
my_context->argv[0] = ResolveFile(prog, &my_context->box64_path);
const char* prgname = strrchr(prog, '/');
if(!prgname)
prgname = prog;
else
++prgname;
// special case for LittleInferno that use an old libvorbis
if(strstr(prgname, "LittleInferno.bin.x86")==prgname) {
printf_log(LOG_INFO, "LittleInferno detected, forcing emulated libvorbis\n");
AddPath("libvorbis.so.0", &my_context->box64_emulated_libs, 0);
}
// special case for dontstarve that use an old SDL2
if(strstr(prgname, "dontstarve")) {
printf_log(LOG_INFO, "Dontstarve* detected, forcing emulated SDL2\n");
AddPath("libSDL2-2.0.so.0", &my_context->box64_emulated_libs, 0);
}
// special case for steam that somehow seems to alter libudev opaque pointer (udev_monitor)
if(strstr(prgname, "steam")==prgname) {
printf_log(LOG_INFO, "steam detected, forcing emulated libudev\n");
AddPath("libudev.so.0", &my_context->box64_emulated_libs, 0);
box64_steam = 1;
}
// special case for steam-runtime-check-requirements to fake 64bits suport
if(strstr(prgname, "steam-runtime-check-requirements")==prgname) {
printf_log(LOG_INFO, "steam-runtime-check-requirements detected, faking All is good!\n");
exit(0); // exiting, not testing anything
}
// special case for UnrealLinux.bin, it doesn't like "full path resolution"
if(!strcmp(prog, "UnrealLinux.bin") && my_context->argv[0]) {
free(my_context->argv[0]);
my_context->argv[0] = strdup("./UnrealLinux.bin");
}
#ifdef RPI
// special case for TokiTori 2+, that check if texture max size is > = 8192
if(strstr(prgname, "TokiTori2.bin.x86")==prgname) {
printf_log(LOG_INFO, "TokiTori 2+ detected, runtime patch to fix GPU non-power-of-two faillure\n");
box64_tokitori2 = 1;
}
#endif
// special case for zoom
if(strstr(prgname, "zoom")==prgname) {
printf_log(LOG_INFO, "Zoom detected, trying to use system libturbojpeg if possible\n");
box64_zoom = 1;
}
/*if(strstr(prgname, "awesomium_process")==prgname) {
printf_log(LOG_INFO, "awesomium_process detected, forcing emulated libpng12\n");
AddPath("libpng12.so.0", &my_context->box64_emulated_libs, 0);
}*/
/*if(!strcmp(prgname, "gdb")) {
exit(-1);
}*/
for(int i=1; i<my_context->argc; ++i) {
my_context->argv[i] = strdup(argv[i+nextarg]);
printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]);
}
// 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 (check BOX64_PATH)\n");
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 = realpath(my_context->argv[0], NULL)))
my_context->fullpath = strdup(my_context->argv[0]);
FILE *f = fopen(my_context->argv[0], "rb");
if(!f) {
printf_log(LOG_NONE, "Error: Cannot open %s\n", my_context->argv[0]);
free_contextargv();
FreeBox64Context(&my_context);
FreeCollection(&ld_preload);
return -1;
}
/*elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->argv[0], 1);
if(!elf_header) {
printf_log(LOG_NONE, "Error: reading elf header of %s, try to launch natively instead\n", my_context->argv[0]);
fclose(f);
free_contextargv();
FreeBox64Context(&my_context);
FreeCollection(&ld_preload);
return execvp(argv[1], (char * const*)(argv+1));
}
AddElfHeader(my_context, elf_header);*/
return 0;
}

129
src/tools/fileutils.c Executable file
View File

@ -0,0 +1,129 @@
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#ifndef MAX_PATH
#define MAX_PATH 4096
#endif
#include "debug.h"
#include "fileutils.h"
static const char* x64sign = "\x7f" "ELF" "\x02" "\x01" "\x01" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x02" "\x00" "\x3e" "\x00";
int FileExist(const char* filename, int flags)
{
struct stat sb;
if (stat(filename, &sb) == -1)
return 0;
if(flags==-1)
return 1;
// check type of file? should be executable, or folder
if(flags&IS_FILE) {
if(!S_ISREG(sb.st_mode))
return 0;
} else if(!S_ISDIR(sb.st_mode))
return 0;
if(flags&IS_EXECUTABLE) {
if((sb.st_mode&S_IXUSR)!=S_IXUSR)
return 0; // nope
}
return 1;
}
char* ResolveFile(const char* filename, path_collection_t* paths)
{
char p[MAX_PATH];
if(filename[0]=='/')
return strdup(filename);
for (int i=0; i<paths->size; ++i) {
if(paths->paths[i][0]!='/') {
// not an absolute path...
getcwd(p, sizeof(p));
if(p[strlen(p)-1]!='/')
strcat(p, "/");
strcat(p, paths->paths[i]);
} else
strcpy(p, paths->paths[i]);
strcat(p, filename);
if(FileExist(p, IS_FILE))
return realpath(p, NULL);
}
return NULL;
}
int FileIsX64ELF(const char* filename)
{
FILE *f = fopen(filename, "rb");
if(!f)
return 0;
char head[sizeof(*x64sign)] = {0};
int sz = fread(head, sizeof(*x64sign), 1, f);
if(sz!=1) {
fclose(f);
return 0;
}
fclose(f);
if(memcmp(head, x64sign, sizeof(*x64sign))==0)
return 1;
return 0;
}
#if defined(RPI) || defined(RK3399)
void sanitize_mojosetup_gtk_background()
{
// get GTK2_RC_FILES folder
const char* gtk2_rc = getenv("GTK2_RC_FILES");
// check if $GTK2_RC_FILES/pixmaps/background.png exist
char background[1000] = {0};
strcpy(background, gtk2_rc);
char* p = strrchr(background, '/'); // remove "/gtkrc"
// every error will just silently abort
if(!p)
return;
*p = 0;
strcat(background, "/pixmaps/background.png");
if(!FileExist(background, IS_FILE))
return;
// now open are read the header of the PNG to grab the width and height
//very crude reading here!
FILE* f = fopen(background, "rb");
if(!f)
return;
char sign[8];
if(fread(sign, 8, 1, f)!=1) {
fclose(f); return;
}
const char ref[8] = {'\211', 'P', 'N', 'G', '\r', '\n', '\032', '\n' };
if (memcmp(sign, ref, 8)) {
fclose(f); return;
}
int32_t width, height;
fseek(f, 16, SEEK_SET);
if(fread(&width, sizeof(width), 1, f)!=1) {
fclose(f); return;
}
if(fread(&height, sizeof(height), 1, f)!=1) {
fclose(f); return;
}
fclose(f);
// need to swap bitness!
width = __builtin_bswap32(width);
height = __builtin_bswap32(height);
printf_log(LOG_INFO, "Mojosetup detected, size of background picture is %dx%d\n", width, height);
if(width!=5000 || height!=3000)
return; // not a background that will cause any issue
// delete the file!
f = fopen(background, "r+b");
remove(background);
printf_log(LOG_INFO, "background deleted!\n");
}
#endif

182
src/tools/pathcoll.c Executable file
View File

@ -0,0 +1,182 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#ifndef MAX_PATH
#define MAX_PATH 4096
#endif
#include "debug.h"
#include "pathcoll.h"
void FreeCollection(path_collection_t* collection)
{
if(!collection)
return;
if(collection->cap) {
for(int i=0; i<collection->size; ++i)
free(collection->paths[i]);
free(collection->paths);
}
collection->paths = NULL;
collection->size = 0;
collection->cap = 0;
return;
}
void ParseList(const char* List, path_collection_t* collection, int folder)
{
if(collection->cap)
FreeCollection(collection);
// count the stings (basically count(':') + 1) to define cap
int cnt = 1;
{
const char* p = List;
while(p) {
p = strchr(p, ':');
++cnt;
if(p) ++p;
}
}
// alloc empty strings
collection->cap = cnt;
collection->paths = (char**)calloc(cnt, sizeof(char*));
// and now split the paths...
char tmp[MAX_PATH];
const char *p = List;
int idx = 0;
while(p) {
const char *p2 = strchr(p, ':');
if(!p2) {
strncpy(tmp, p, MAX_PATH - 1);
p=NULL;
} else {
int l = (uintptr_t)p2 - (uintptr_t)p;
strncpy(tmp, p, l);
tmp[l]='\0';
p=p2+1;
}
// check if there is terminal '/', add it if not
int l = strlen(tmp);
// skip empty strings
if(l) {
if(folder && tmp[l-1]!='/')
strcat(tmp, "/");
collection->paths[idx] =strdup(tmp);
collection->size=++idx;
}
}
}
void CopyCollection(path_collection_t* to, path_collection_t* from)
{
to->cap = from->cap;
to->paths = (char**)calloc(to->cap, sizeof(char*));
to->size = from->size;
for (int i=0; i<to->size; ++i)
to->paths[i] = strdup(from->paths[i]);
}
void AddPath(const char* path, path_collection_t* collection, int folder)
{
char tmp[MAX_PATH];
strcpy(tmp, path);
int l = strlen(tmp);
// skip empty strings
if(l) {
if(folder && tmp[l-1]!='/')
strcat(tmp, "/");
if(collection->size==collection->cap) {
collection->cap += 4;
collection->paths = (char**)realloc(collection->paths, collection->cap*sizeof(char*));
}
collection->paths[collection->size++]=strdup(tmp);
}
}
void PrependPath(const char* path, path_collection_t* collection, int folder)
{
char tmp[MAX_PATH];
strcpy(tmp, path);
int l = strlen(tmp);
// skip empty strings
if(l) {
if(folder && tmp[l-1]!='/')
strcat(tmp, "/");
if(collection->size==collection->cap) {
collection->cap += 4;
collection->paths = (char**)realloc(collection->paths, collection->cap*sizeof(char*));
}
memmove(collection->paths+1, collection->paths, sizeof(char*)*collection->size);
collection->paths[0]=strdup(tmp);
++collection->size;
}
}
void AppendList(path_collection_t* collection, const char* List, int folder)
{
if(!List)
return;
// and now split the paths...
char tmp[MAX_PATH];
const char *p = List;
while(p) {
const char *p2 = strchr(p, ':');
if(!p2) {
strncpy(tmp, p, MAX_PATH - 1);
p=NULL;
} else {
int l = (uintptr_t)p2 - (uintptr_t)p;
strncpy(tmp, p, l);
tmp[l]='\0';
p=p2+1;
}
// check if there is terminal '/', add it if not
int l = strlen(tmp);
// skip empty strings
if(l) {
if(folder && tmp[l-1]!='/')
strcat(tmp, "/");
AddPath(tmp, collection, folder);
}
}
}
void PrependList(path_collection_t* collection, const char* List, int folder)
{
if(!List)
return;
// and now split the paths...
char tmp[MAX_PATH];
char *p = strdup(List);
while(p) {
char *p2 = strrchr(p, ':');
if(!p2) {
strncpy(tmp, p, MAX_PATH - 1);
free(p);
p=NULL;
} else {
strncpy(tmp, p2+1, MAX_PATH - 1);
tmp[MAX_PATH - 1]='\0';
*p2 = '\0';
}
// check if there is terminal '/', add it if not
int l = strlen(tmp);
// skip empty strings
if(l) {
if(folder && tmp[l-1]!='/')
strcat(tmp, "/");
PrependPath(tmp, collection, folder);
}
}
}
int FindInCollection(const char* path, path_collection_t* collection)
{
for (int i=0; i<collection->size; ++i)
if(strcmp(path, collection->paths[i])==0)
return 1;
return 0;
}

107
src/tools/wine_tools.c Executable file
View File

@ -0,0 +1,107 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <errno.h>
#include "wine_tools.h"
#include "debug.h"
#include "box64context.h"
typedef struct wine_prereserve_s
{
void* addr;
size_t size;
} wine_prereserve_t;
// only the prereseve argument is reserved, not the other zone that wine-preloader reserve
static wine_prereserve_t my_wine_reserve[] = {{(void*)0x00010000, 0x00008000}, {(void*)0x00110000, 0x30000000}, {(void*)0x7f000000, 0x03000000}, {0, 0}, {0, 0}};
int wine_preloaded = 0;
static int get_prereserve(const char* reserve, void** addr, size_t* size)
{
if(!reserve)
return 0;
uintptr_t r = 0;
int first = 1;
while(*reserve) {
// numbers reading
if(*reserve>='0' && *reserve<='9') r=r*16+(*reserve)-'0';
else if(*reserve>='A' && *reserve<='F') r=r*16+(*reserve)-'A'+10;
else if(*reserve>='a' && *reserve<='f') r=r*16+(*reserve)-'a'+10;
else if(*reserve=='-') {if(first) {*addr=(void*)(r&~(box64_pagesize-1)); r=0; first=0;} else {printf_log(LOG_NONE, "Warning, Wine prereserve badly formated\n"); return 0;}}
else {printf_log(LOG_NONE, "Warning, Wine prereserve badly formated\n"); return 0;}
++reserve;
}
*size = r;
return 1;
}
static void add_no_overlap(void* addr, size_t size)
{
int idx = 0;
while(my_wine_reserve[idx].addr && my_wine_reserve[idx].size) {
if(addr>=my_wine_reserve[idx].addr && addr<my_wine_reserve[idx].addr+my_wine_reserve[idx].size) {
// overlap
if (addr+size > my_wine_reserve[idx].addr+my_wine_reserve[idx].size)
// need adjust size
my_wine_reserve[idx].size = (intptr_t)addr-(intptr_t)my_wine_reserve[idx].addr+size;
return;
}
++idx;
}
my_wine_reserve[idx].addr = addr;
my_wine_reserve[idx].size = size;
}
void wine_prereserve(const char* reserve)
{
void* addr = NULL;
size_t size = 0;
if(get_prereserve(reserve, &addr, &size)) {
add_no_overlap(addr, size);
}
int idx = 0;
while(my_wine_reserve[idx].addr && my_wine_reserve[idx].size) {
void* p = mmap(my_wine_reserve[idx].addr, my_wine_reserve[idx].size,
PROT_NONE, /*MAP_FIXED |*/ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
if(p==(void*)-1 || p!=my_wine_reserve[idx].addr) {
printf_log(LOG_NONE, "Warning, prereserve of %p:0x%x failed (%s)\n", my_wine_reserve[idx].addr, my_wine_reserve[idx].size, strerror(errno));
if(p!=(void*)-1)
munmap(p, my_wine_reserve[idx].size);
my_wine_reserve[idx].addr = NULL;
my_wine_reserve[idx].size = 0;
} else {
printf_log(LOG_DEBUG, "WINE prereserve of %p:0x%x done\n", my_wine_reserve[idx].addr, my_wine_reserve[idx].size);
++idx;
}
}
wine_preloaded = 1;
}
void* get_wine_prereserve()
{
if(!wine_preloaded)
wine_prereserve(NULL);
return (void*)my_wine_reserve;
}
#ifdef DYNAREC
void dynarec_wine_prereserve()
{
#if 0
// disable for now, as it break some installer
if(!wine_preloaded)
wine_prereserve(NULL);
// don't reserve the initial arbritrary block as "with linker", it's not true
for(int i=1; i<sizeof(my_wine_reserve)/sizeof(my_wine_reserve[0]); ++i)
if(my_wine_reserve[i].addr && my_wine_reserve[i].size)
addDBFromAddressRange(my_context, (uintptr_t)my_wine_reserve[i].addr, my_wine_reserve[i].size, 0); // prepare the prereserved area for exec, with linker
#endif
}
#endif