diff --git a/nx/source/runtime/env.c b/nx/source/runtime/env.c index 7ee2e327..6cbd2c73 100644 --- a/nx/source/runtime/env.c +++ b/nx/source/runtime/env.c @@ -4,6 +4,8 @@ #include "services/sm.h" #include "services/fatal.h" +void NORETURN __nx_exit(LoaderReturnFn retaddr, Result rc); + static bool g_isNso = false; static Handle g_mainThreadHandle = INVALID_HANDLE; static LoaderReturnFn g_loaderRetAddr = NULL; @@ -88,7 +90,7 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr) if (ent->Flags & EntryFlag_IsMandatory) { // Encountered unknown but mandatory key, bail back to loader. - g_loaderRetAddr(MAKERESULT(346, 100 + ent->Key)); + __nx_exit(g_loaderRetAddr, MAKERESULT(346, 100 + ent->Key)); } break; diff --git a/nx/source/runtime/init.c b/nx/source/runtime/init.c index 365515dd..1c46c812 100644 --- a/nx/source/runtime/init.c +++ b/nx/source/runtime/init.c @@ -7,7 +7,8 @@ #include "services/applet.h" #include "runtime/devices/fs_dev.h" -void __nx_exit(int rc); +void* __stack_top; +void NORETURN __nx_exit(LoaderReturnFn retaddr, Result rc); void virtmemSetup(void); void newlibSetup(void); @@ -133,6 +134,5 @@ void __attribute__((weak)) NORETURN __libnx_exit(int rc) // Clean up services. __appExit(); - envGetExitFuncPtr()(0); - while(1); + __nx_exit(envGetExitFuncPtr(), 0); } diff --git a/nx/source/runtime/switch_crt0.s b/nx/source/runtime/switch_crt0.s index 4c49ff95..11986e5e 100644 --- a/nx/source/runtime/switch_crt0.s +++ b/nx/source/runtime/switch_crt0.s @@ -33,6 +33,11 @@ bss_loop: subs x1, x1, #8 bne bss_loop + // store stack pointer + mov x1, sp + adrp x0, __stack_top + str x1, [x0, #:lo12:__stack_top] + // process .dynamic section mov x0, x28 adrp x1, _DYNAMIC @@ -53,3 +58,17 @@ bss_loop: adrp x30, __libnx_exit add x30, x30, #:lo12:__libnx_exit b main + +.global __nx_exit +.type __nx_exit, %function +__nx_exit: + mov x8, x0 + + // restore stack pointer + adrp x0, __stack_top + ldr x0, [x0, #:lo12:__stack_top] + mov sp, x0 + + // jump back to loader + mov x0, #0 + br x8