diff --git a/.gitmodules b/.gitmodules
index b2543534..a97914ec 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -93,3 +93,6 @@
 [submodule "externals/pugixml"]
 	path = externals/pugixml
 	url = https://github.com/zeux/pugixml.git
+[submodule "externals/box64"]
+	path = externals/box64
+	url = git@github.com:skmp/box64.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee719f68..f367e95c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -696,6 +696,7 @@ create_target_directory_groups(shadps4)
 
 target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui)
 target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
+target_link_libraries(shadps4 PRIVATE box64-core)
 
 target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
 target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 5410f37e..5a8d10e1 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -182,4 +182,9 @@ add_subdirectory(tracy)
 # pugixml
 if (NOT TARGET pugixml::pugixml)
     add_subdirectory(pugixml)
+endif()
+
+# box64-core
+if (NOT TARGET box64-core)
+    add_subdirectory(box64/box64-core)
 endif()
\ No newline at end of file
diff --git a/externals/box64 b/externals/box64
new file mode 160000
index 00000000..ee232489
--- /dev/null
+++ b/externals/box64
@@ -0,0 +1 @@
+Subproject commit ee232489491741bc7e9d0306212be4135fd6fbda
diff --git a/src/core/aerolib/stubs.cpp b/src/core/aerolib/stubs.cpp
index 2634fc46..6652e905 100644
--- a/src/core/aerolib/stubs.cpp
+++ b/src/core/aerolib/stubs.cpp
@@ -78,7 +78,12 @@ u64 GetStub(const char* nid) {
         stub_nids[UsedStubEntries] = entry;
     }
 
-    return (u64)stub_handlers[UsedStubEntries++];
+        uint8_t* code = (uint8_t*)malloc(13); \
+        code[0] = 0xCD; \
+        code[1] = 0x13; \
+        code[2] = 0xC3; \
+        memcpy(code + 3, &stub_handlers[UsedStubEntries++], 8); \
+    return (u64)code;
 }
 
 } // namespace Core::AeroLib
diff --git a/src/core/libraries/avplayer/avplayer.cpp b/src/core/libraries/avplayer/avplayer.cpp
index 60d68c4f..c7476a1f 100644
--- a/src/core/libraries/avplayer/avplayer.cpp
+++ b/src/core/libraries/avplayer/avplayer.cpp
@@ -309,7 +309,7 @@ void RegisterlibSceAvPlayer(Core::Loader::SymbolsResolver* sym) {
     LIB_FUNCTION("XC9wM+xULz8", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerJumpToTime);
     LIB_FUNCTION("9y5v+fGN4Wk", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPause);
     LIB_FUNCTION("HD1YKVU26-M", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPostInit);
-    LIB_FUNCTION("agig-iDRrTE", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPrintf);
+    // LIB_FUNCTION("agig-iDRrTE", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPrintf);
     LIB_FUNCTION("w5moABNwnRY", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerResume);
     LIB_FUNCTION("k-q+xOxdc3E", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0,
                  sceAvPlayerSetAvSyncMode);
diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp
index ae2c6e2b..a095f057 100644
--- a/src/core/libraries/kernel/file_system.cpp
+++ b/src/core/libraries/kernel/file_system.cpp
@@ -223,7 +223,9 @@ s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) {
 
     std::scoped_lock lk{file->m_mutex};
     file->f.Seek(offset, origin);
-    return file->f.Tell();
+    auto rv = file->f.Tell();
+
+    return rv;
 }
 
 s64 PS4_SYSV_ABI posix_lseek(int d, s64 offset, int whence) {
diff --git a/src/core/libraries/libs.h b/src/core/libraries/libs.h
index ea928101..1b795a41 100644
--- a/src/core/libraries/libs.h
+++ b/src/core/libraries/libs.h
@@ -28,6 +28,7 @@ struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
             std::string_view(name.value) != "sceUserServiceGetEvent") {
             // LOG_WARNING(Core_Linker, "Function {} called", name.value);
         }
+        LOG_WARNING(Core_Linker, "Function {} called", name.value);
         if constexpr (std::is_same_v<R, s32> || std::is_same_v<R, u32>) {
             const u32 ret = f(args...);
             if (ret != 0 && std::string_view(name.value) != "scePthreadEqual") {
@@ -43,8 +44,8 @@ struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
 template <StringLiteral name, class F, F f>
 constexpr auto wrapper = wrapper_impl<name, F, f>::wrap;
 
-// #define W(foo) wrapper<#foo, decltype(&foo), foo>
-#define W(foo) foo
+#define W(foo) wrapper<#foo, decltype(&foo), foo>
+// #define W(foo) foo
 
 #define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function)  \
     {                                                                                              \
@@ -57,7 +58,12 @@ constexpr auto wrapper = wrapper_impl<name, F, f>::wrap;
         sr.module_version_minor = moduleVersionMinor;                                              \
         sr.type = Core::Loader::SymbolType::Function;                                              \
         auto func = reinterpret_cast<u64>(W(function));                                            \
-        sym->AddSymbol(sr, func);                                                                  \
+        uint8_t* code = (uint8_t*)malloc(13); \
+        code[0] = 0xCD; \
+        code[1] = 0x13; \
+        code[2] = 0xC3; \
+        memcpy(code + 3, &func, 8); \
+        sym->AddSymbol(sr, (u64)code);                                                                  \
     }
 
 #define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function)       \
diff --git a/src/core/linker.cpp b/src/core/linker.cpp
index e8aab673..1e600788 100644
--- a/src/core/linker.cpp
+++ b/src/core/linker.cpp
@@ -19,6 +19,224 @@
 #include "core/tls.h"
 #include "core/virtual_memory.h"
 
+#include <unordered_map>
+#include <unistd.h>
+#include <fcntl.h>
+extern "C" {
+    #include "x64emu.h"
+    #include "x64run.h"
+    #include "box64context.h"
+    #include "regs.h"
+    #include "externals/box64/src/emu/x64emu_private.h"
+
+
+box64context_t *my_context = NULL;
+    int box64_dynarec_test = 0;
+    int box64_log = 2; //2 is debug; //LOG_NONE;
+    int box64_dynarec_log = 0;
+
+    int box64_ignoreint3 = 0;
+    int box64_is32bits = 0;
+    int box64_wine = 0;
+    int box64_rdtsc = 0;
+    int box64_rdtsc_1ghz = 0;
+    uint8_t box64_rdtsc_shift = 0;
+    int box64_sse_flushto0 = 0;
+    int box64_x87_no80bits = 0;
+    int box64_sync_rounding = 0;
+    int box64_shaext = 1;
+    int box64_sse42 = 1;
+    int box64_avx = 1;
+    int box64_avx2 = 1;
+    int cycle_log = 0;
+    int box64_mapclean = 0;
+    int box64_dynarec = 1;
+    uintptr_t box64_pagesize = 16 * 1024;
+
+    int box64_dynarec_dump = 0;
+    int box64_dynarec_forced = 0;
+    int box64_dynarec_bigblock = 1;
+    int box64_dynarec_forward = 128;
+    int box64_dynarec_strongmem = 0;
+    int box64_dynarec_x87double = 0;
+    int box64_dynarec_div0 = 0;
+    int box64_dynarec_fastnan = 1;
+    int box64_dynarec_fastround = 1;
+    int box64_dynarec_safeflags = 1;
+    int box64_dynarec_callret = 0;
+    int box64_dynarec_bleeding_edge = 1;
+    int box64_dynarec_tbb = 1;
+    int box64_dynarec_wait = 1;
+    int box64_dynarec_missing = 0;
+    int box64_dynarec_aligned_atomics = 0;
+    uintptr_t box64_nodynarec_start = 0;
+    uintptr_t box64_nodynarec_end = 0;
+    uintptr_t box64_dynarec_test_start = 0;
+    uintptr_t box64_dynarec_test_end = 0;
+
+    int arm64_asimd = 1;
+    int arm64_aes = 1;
+    int arm64_pmull = 1;
+    int arm64_crc32 = 1;
+    int arm64_atomics = 1;
+    int arm64_sha1 = 1;
+    int arm64_sha2 = 1;
+    int arm64_uscat = 1;
+    int arm64_flagm = 1;
+    int arm64_flagm2 = 1;
+    int arm64_frintts = 1;
+    int arm64_afp = 1;
+    int arm64_rndr = 1;
+
+    uint32_t default_gs = 0x53;
+    uint32_t default_fs = 0x53;
+    int box64_maxcpu = 0;
+    void emit_signal(x64emu_t* emu, int sig, void* addr, int code) {
+        for(;;) {
+            printf("Signal %d at %p with code %d\n", sig, addr, code);
+        }
+    }
+    void emit_div0(x64emu_t* emu, void* addr, int code) {
+        for(;;) {
+            printf("Divide by 0 at %p with code %d\n", addr, code);
+        }
+    }
+    void emit_interruption(x64emu_t* emu, int num, void* addr) {
+        if (num == 19) {
+            using HLEFunc = PS4_SYSV_ABI uint64_t (*)(
+                uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
+                double, double, double, double, double, double, double, double);
+
+            HLEFunc hleFunc;
+            memcpy(&hleFunc, (uint8_t*)addr + 1, 8);
+            asm volatile(
+                "mov x0, %4\n"
+                "mov x1, %5\n"
+                "mov x2, %6\n"
+                "mov x3, %7\n"
+                "mov x4, %8\n"
+                "mov x5, %9\n"
+
+                "mov v0.16b, %10.16b\n"
+                "mov v1.16b, %11.16b\n"
+                "mov v2.16b, %12.16b\n"
+                "mov v3.16b, %13.16b\n"
+                "mov v4.16b, %14.16b\n"
+                "mov v5.16b, %15.16b\n"
+                "mov v6.16b, %16.16b\n"
+                "mov v7.16b, %17.16b\n"
+                "blr %18\n"
+                "mov %0, x0\n"
+                "mov %1, x1\n"
+                "mov %2.16b, v0.16b\n"
+                "mov %3.16b, v1.16b\n"
+                : "=r"(emu->regs[_RAX].q[0]), "=r"(emu->regs[_RDX].q[0]), "=w"(emu->xmm[0].u128), "=w"(emu->xmm[1].u128)
+                : "r"(emu->regs[_RDI].q[0]), "r"(emu->regs[_RSI].q[0]), "r"(emu->regs[_RDX].q[0]), "r"(emu->regs[_RCX].q[0]),
+                  "r"(emu->regs[_R8].q[0]), "r"(emu->regs[_R9].q[0]),  "w"(emu->xmm[0].u128), "w"(emu->xmm[1].u128), "w"(emu->xmm[2].u128),
+                  "w"(emu->xmm[3].u128), "w"(emu->xmm[4].u128), "w"(emu->xmm[5].u128), "w"(emu->xmm[6].u128),
+                  "w"(emu->xmm[7].u128), "r"(hleFunc)
+                : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",  // Clobber volatile general-purpose registers
+                    "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
+                    "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",  // Clobber volatile SIMD registers
+                    "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", 
+                    "memory", "cc"  // Clobber memory and condition codes
+            );
+            // emu->regs[_RAX].q[0] = hleFunc(
+            //     emu->regs[_RDI].q[0],
+            //     emu->regs[_RSI].q[0],
+            //     emu->regs[_RDX].q[0],
+            //     emu->regs[_RCX].q[0],
+            //     emu->regs[_R8].q[0],
+            //     emu->regs[_R9].q[0],
+
+            //     emu->xmm[0].d[0],
+            //     emu->xmm[1].d[0],
+            //     emu->xmm[2].d[0],
+            //     emu->xmm[3].d[0],
+
+            //     emu->xmm[4].d[0],
+            //     emu->xmm[5].d[0],
+            //     emu->xmm[6].d[0],
+            //     emu->xmm[7].d[0]
+            // );
+        } else if (num == 20) {
+            emu->quit = 1;
+        } else {
+            for(;;) {
+                printf("Interruption %d at %p\n", num, addr);
+            }
+        }
+    }
+    
+    void x64Syscall(x64emu_t *emu) {
+        for(;;) {
+            printf("Syscall\n");
+        }
+    }
+    void x86Syscall(x64emu_t *emu) {
+        for(;;) {
+            printf("Syscall\n");
+        }
+    }
+
+    void printf_ftrace(const char* fmt, ...)
+    {
+
+        va_list args;
+        va_start(args, fmt);
+        vprintf(fmt, args);
+
+        va_end(args);
+    }
+    int printFunctionAddr(uintptr_t nextaddr, const char* text) {
+        printf("Function address %p with text %s\n", (void*)nextaddr, text);
+        return 0;
+    }
+    void PltResolver64(x64emu_t* emu) {
+        for(;;) {
+            printf("PltResolver64\n");
+        }
+    }
+
+    int isRetX87Wrapper(uint64_t fun) {
+        return 0;
+    }
+    int isSimpleWrapper(uint64_t fun) {
+        return 0;
+    }
+
+    int isAddrInPrereserve(uintptr_t addr) {
+        return 0;
+    }
+
+    void* FindElfAddress(box64context_t *context, uintptr_t addr)
+    {
+        
+        return NULL;
+    }
+
+    const char* GetNativeName(void* p)
+    {
+        return "NativeName";
+    }
+
+    void* GetSegmentBase(uint32_t desc)
+    {
+        printf("GetSegmentBase\n");
+        return NULL;
+    }
+
+    uint64_t RunFunctionWithEmu(x64emu_t *emu, int QuitOnLongJump, uintptr_t fnc, int nargs, ...) {
+        for(;;) {
+            printf("RunFunctionWithEmu\n");
+        }
+    }
+
+    const char* SymName64(void *h, void* sym) {
+        return "SymName64";
+    }
+}
+
 namespace Core {
 
 using ExitFunc = PS4_SYSV_ABI void (*)();
@@ -27,6 +245,10 @@ static PS4_SYSV_ABI void ProgramExitFunc() {
     fmt::print("exit function called\n");
 }
 
+
+box64context_t *my_context;
+thread_local x64emu_t *emu;
+
 static void RunMainEntry(VAddr addr, EntryParams* params, ExitFunc exit_func) {
 #ifdef ARCH_X86_64
     // reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have
@@ -49,6 +271,34 @@ static void RunMainEntry(VAddr addr, EntryParams* params, ExitFunc exit_func) {
                  : "r"(addr), "r"(params), "r"(exit_func)
                  : "rax", "rsi", "rdi");
 #else
+
+uint64_t rsp = GetRSP(emu);
+
+rsp = rsp & ~16;
+uint8_t* code = (uint8_t*)malloc(2);
+            code[0] = 0xCD;
+            code[1] = 0x14;
+            rsp -= 8;
+
+        for (int i = params->argc; i > 0; i--) {
+            rsp = rsp - 8;
+            *(void**)rsp = &params->argv[i - 1];
+        }
+
+        rsp = rsp - 8;
+        *(u64*)rsp = params->argc;
+
+        uint64_t rsi = (u64)params;
+        uint64_t rdi = (u64)exit_func;
+
+        SetRIP(emu, addr);
+        SetRSP(emu, rsp);
+        SetRSI(emu, rsi);
+        SetRDI(emu, rdi);
+        emu->quit = 0;
+
+        Run(emu, 0);
+
     UNIMPLEMENTED_MSG("Missing RunMainEntry() implementation for target CPU architecture.");
 #endif
 }
@@ -96,10 +346,35 @@ void Linker::Execute() {
     Libraries::Kernel::pthreadInitSelfMainThread();
     InitTlsForThread(true);
 
+    my_context = NewBox64Context(0);
+    emu = NewX64Emu(my_context, 0, (uintptr_t)0, 0, 0);
+
+    thread_set_emu(emu);
+
+    uintptr_t stack_top = 8 * 1024 * 1024 + (uintptr_t)malloc(8 * 1024 * 1024);
+
     // Start shared library modules
     for (auto& m : m_modules) {
         if (m->IsSharedLib()) {
-            m->Start(0, nullptr, nullptr);
+            // m->Start(0, nullptr, nullptr);
+            LOG_DEBUG(Core_Linker, "Starting shared library module {}", m->name);
+            const VAddr addr = m->dynamic_info.init_virtual_addr + m->GetBaseAddress();
+            uint8_t* code = (uint8_t*)malloc(2);
+            code[0] = 0xCD;
+            code[1] = 0x14;
+            uint64_t rsp = stack_top;
+            rsp &= ~16;
+            rsp -= 8;
+            *(uint8_t**)rsp = code;
+
+            SetRIP(emu, addr);
+            SetRSP(emu, rsp);
+            SetRDI(emu, 0);
+            SetRSI(emu, 0);
+            SetRDX(emu, 0);
+
+            emu->quit = 0;
+            Run(emu, 0);
         }
     }
 
@@ -110,6 +385,8 @@ void Linker::Execute() {
 
     for (auto& m : m_modules) {
         if (!m->IsSharedLib()) {
+            LOG_DEBUG(Core_Linker, "Starting main library module {}", m->name);
+            SetRSP(emu, stack_top);
             RunMainEntry(m->GetEntryAddress(), &p, ProgramExitFunc);
         }
     }
@@ -274,6 +551,7 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
     sr.type = sym_type;
 
     const auto* record = m_hle_symbols.FindSymbol(sr);
+
     if (!record) {
         // Check if it an export function
         const auto* p = FindExportedModule(*module, *library);
@@ -283,6 +561,7 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
     }
     if (record) {
         *return_info = *record;
+
         return true;
     }