]> Chaos Git - corbenik/ctrulib.git/commitdiff
Reference count srv, cleanup launcher code.
authorSteven Smith <Steveice10@gmail.com>
Sun, 15 Nov 2015 17:37:04 +0000 (09:37 -0800)
committerSteven Smith <Steveice10@gmail.com>
Sun, 15 Nov 2015 21:02:06 +0000 (13:02 -0800)
17 files changed:
libctru/include/3ds.h
libctru/include/3ds/env.h [new file with mode: 0644]
libctru/include/3ds/services/apt.h
libctru/include/3ds/srv.h
libctru/source/allocator/linear.cpp
libctru/source/env.c [new file with mode: 0644]
libctru/source/gpu/gpu.c
libctru/source/ndsp/ndsp.c
libctru/source/romfs_dev.c
libctru/source/services/apt.c
libctru/source/services/fs.c
libctru/source/services/irrst.c
libctru/source/srv.c
libctru/source/system/allocateHeaps.c
libctru/source/system/ctru_exit.c
libctru/source/system/initArgv.c
libctru/source/system/initSystem.c

index 44b91d20ea5f62db10f2cae8ae8c1797b5e9e5be..a2c8e72a91f6d47e475684be31f9c27fbbeaacf9 100644 (file)
@@ -18,6 +18,7 @@ extern "C" {
 #include <3ds/synchronization.h>
 #include <3ds/gfx.h>
 #include <3ds/console.h>
+#include <3ds/env.h>
 #include <3ds/util/utf.h>
 
 #include <3ds/allocator/linear.h>
diff --git a/libctru/include/3ds/env.h b/libctru/include/3ds/env.h
new file mode 100644 (file)
index 0000000..eaefb98
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * @file env.h
+ * @brief Homebrew environment information.
+ */
+#pragma once
+
+/// System run-flags.
+enum {
+       RUNFLAG_APTWORKAROUND = BIT(0), ///< Use APT workaround.
+       RUNFLAG_APTREINIT     = BIT(1), ///< Reinitialize APT.
+};
+
+/**
+ * @brief Gets whether the application was launched from a homebrew environment.
+ * @return Whether the application was launched from a homebrew environment.
+ */
+static inline bool envIsHomebrew(void) {
+       extern void* __service_ptr;
+       return __service_ptr != NULL;
+}
+
+/**
+ * @brief Retrieves a handle from the environment handle list.
+ * @param name Name of the handle.
+ * @return The retrieved handle.
+ */
+Handle envGetHandle(const char* name);
+
+/**
+ * @brief Gets the environment-recommended app ID to use with APT.
+ * @return The APT app ID.
+ */
+static inline u32 envGetAptAppId(void) {
+       extern u32 __apt_appid;
+       return __apt_appid;
+}
+
+/**
+ * @brief Gets the environment-recommended heap size.
+ * @return The heap size.
+ */
+static inline u32 envGetHeapSize(void) {
+       extern u32 __heap_size;
+       return __heap_size;
+}
+
+/**
+ * @brief Gets the environment-recommended linear heap size.
+ * @return The linear heap size.
+ */
+static inline u32 envGetLinearHeapSize(void) {
+       extern u32 __linear_heap_size;
+       return __linear_heap_size;
+}
+
+/**
+ * @brief Gets the environment argument list.
+ * @return The argument list.
+ */
+static inline const char* envGetSystemArgList(void) {
+       extern const char* __system_arglist;
+       return __system_arglist;
+}
+
+/**
+ * @brief Gets the environment run flags.
+ * @return The run flags.
+ */
+static inline u32 envGetSystemRunFlags(void) {
+       extern u32 __system_runflags;
+       return __system_runflags;
+}
index afe860bdb2f606ec8d66dc0d9ca457d9e6f58010..3b102bfd91083fd0fe6d05baef02ed52ba80ff4c 100644 (file)
@@ -4,12 +4,6 @@
  */
 #pragma once
 
-// TODO: find a better place to put this
-/// APT workaround flag.
-#define RUNFLAG_APTWORKAROUND (BIT(0))
-/// APT reinititalize flag.
-#define RUNFLAG_APTREINIT (BIT(1))
-
 /**
  * @brief NS Application IDs.
  *
index d61d640ea986569aa4761b09418c5bdeba526f57..d121cb1a79c94db6b2115ba6bf63e4024f085b1c 100644 (file)
@@ -8,7 +8,7 @@
 Result srvInit(void);
 
 /// Exits the service API.
-Result srvExit(void);
+void srvExit(void);
 
 /**
  * @brief Gets the current service API session handle.
@@ -17,7 +17,7 @@ Result srvExit(void);
 Handle *srvGetSessionHandle(void);
 
 /**
- * @brief Retrieves a service handle, retrieving from the launcher handle list if possible.
+ * @brief Retrieves a service handle, retrieving from the environment handle list if possible.
  * @param out Pointer to write the handle to.
  * @param name Name of the service.
  */
index 1a1e1cbc3ea002632e5172d68ad6bb7c699f1210..05e86e0bfeea50ead3cf3ef6cd1b70d1177b6a4d 100644 (file)
@@ -8,13 +8,14 @@ extern "C"
 #include "mem_pool.h"
 #include "addrmap.h"
 
-extern u32 __linear_heap, __linear_heap_size;
+extern u32 __ctru_linear_heap;
+extern u32 __ctru_linear_heap_size;
 
 static MemPool sLinearPool;
 
 static bool linearInit()
 {
-       auto blk = MemBlock::Create((u8*)__linear_heap, __linear_heap_size);
+       auto blk = MemBlock::Create((u8*)__ctru_linear_heap, __ctru_linear_heap_size);
        if (blk)
        {
                sLinearPool.AddBlock(blk);
diff --git a/libctru/source/env.c b/libctru/source/env.c
new file mode 100644 (file)
index 0000000..4eb24ba
--- /dev/null
@@ -0,0 +1,67 @@
+#include <3ds/types.h>
+#include <3ds/svc.h>
+#include <3ds/env.h>
+
+/*
+  The homebrew loader can choose to supply a list of service handles that have
+  been "stolen" from other processes that have been compromised. This allows us
+  to access services that are normally restricted from the current process.
+
+  For every service requested by the application, we shall first check if the
+  list given to us contains the requested service and if so use it. If we don't
+  find the service in that list, we ask the service manager and hope for the
+  best.
+ */
+
+typedef struct {
+       u32 num;
+
+       struct {
+               char name[8];
+               Handle handle;
+       } services[];
+} service_list_t;
+
+extern void* __service_ptr;
+
+static int __name_cmp(const char* a, const char* b) {
+       u32 i;
+
+       for(i=0; i<8; i++) {
+               if(a[i] != b[i])
+                       return 1;
+               if(a[i] == '\0')
+                       return 0;
+       }
+
+       return 0;
+}
+
+Handle envGetHandle(const char* name) {
+       if(__service_ptr == NULL)
+               return 0;
+
+       service_list_t* service_list = (service_list_t*) __service_ptr;
+       u32 i, num = service_list->num;
+
+       for(i=0; i<num; i++) {
+               if(__name_cmp(service_list->services[i].name, name) == 0)
+                       return service_list->services[i].handle;
+       }
+
+       return 0;
+}
+
+void envDestroyHandles(void) {
+       if(__service_ptr == NULL)
+               return;
+
+       service_list_t* service_list = (service_list_t*) __service_ptr;
+       u32 i, num = service_list->num;
+
+       for(i=0; i<num; i++)
+               svcCloseHandle(service_list->services[i].handle);
+
+       service_list->num = 0;
+}
+
index 90fd34ba6ca7b1c49a67d7e414b666bddadd4a1c..9146c1042db6c5ffbbae52930194064d107425fa 100644 (file)
@@ -45,13 +45,13 @@ void GPUCMD_Run(void)
        GX_ProcessCommandList(gpuCmdBuf, gpuCmdBufOffset*4, GX_CMDLIST_FLUSH);
 }
 
-extern u32 __linear_heap_size;
-extern u32 __linear_heap;
+extern u32 __ctru_linear_heap;
+extern u32 __ctru_linear_heap_size;
 
 void GPUCMD_FlushAndRun(void)
 {
        //take advantage of GX_FlushCacheRegions to flush gsp heap
-       GX_FlushCacheRegions(gpuCmdBuf, gpuCmdBufOffset*4, (u32 *) __linear_heap, __linear_heap_size, NULL, 0);
+       GX_FlushCacheRegions(gpuCmdBuf, gpuCmdBufOffset*4, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0);
        GX_ProcessCommandList(gpuCmdBuf, gpuCmdBufOffset*4, 0x0);
 }
 
index 11445ba0f618ad91817aeeb7ba24590ea00177fa..4c5a50392c367e495eee5a01825b69d816e3ab17 100644 (file)
@@ -1,6 +1,7 @@
 #include "ndsp-internal.h"
 #include <3ds/services/cfgu.h>
 #include <3ds/services/fs.h>
+#include <3ds/env.h>
 
 #define NDSP_THREAD_STACK_SIZE 0x1000
 
@@ -388,7 +389,6 @@ void ndspUseComponent(const void* binary, u32 size, u16 progMask, u16 dataMask)
 
 static bool ndspFindAndLoadComponent(void)
 {
-       extern Handle __get_handle_from_list(const char* name);
        Result rc;
        Handle rsrc;
        void* bin;
@@ -425,7 +425,7 @@ static bool ndspFindAndLoadComponent(void)
        } while (0);
 
        // Try loading the DSP component from hb:ndsp
-       rsrc = __get_handle_from_list("hb:ndsp");
+       rsrc = envGetHandle("hb:ndsp");
        if (rsrc) do
        {
                extern u32 fake_heap_end;
index 1706b7871d21fac061576b0dc2c0ab520fff29c2..3b25602a812dcdb8866da9045a59cc08fb5413b3 100644 (file)
@@ -14,6 +14,7 @@
 #include <3ds/romfs.h>
 #include <3ds/services/fs.h>
 #include <3ds/util/utf.h>
+#include <3ds/env.h>
 
 static bool romFS_active;
 static Handle romFS_file;
@@ -24,7 +25,6 @@ static romfs_dir* romFS_cwd;
 static u32 *dirHashTable, *fileHashTable;
 static void *dirTable, *fileTable;
 
-extern u32 __service_ptr;
 extern int __system_argc;
 extern char** __system_argv;
 
@@ -117,7 +117,7 @@ static Result romfsInitCommon(void);
 Result romfsInit(void)
 {
        if (romFS_active) return 0;
-       if (__service_ptr)
+       if (envIsHomebrew())
        {
                // RomFS appended to a 3DSX file
                if (__system_argc == 0 || !__system_argv[0]) return 1;
index 98591cbe257d3afb706a4ef9ad86d29df43a360f..5bbbbe2709e18d53ad106f0231007f50c6357638 100644 (file)
 #include <3ds/services/apt.h>
 #include <3ds/services/gspgpu.h>
 #include <3ds/ipc.h>
-
+#include <3ds/env.h>
 
 #define APT_HANDLER_STACKSIZE (0x1000)
 
-//TODO : better place to put this ?
-extern u32 __apt_appid;
-extern u32 __system_runflags;
-
 NS_APPID currentAppId;
 
 static const char *__apt_servicestr;
@@ -71,12 +67,12 @@ static void aptAppStarted(void);
 
 static bool aptIsReinit(void)
 {
-       return (__system_runflags & RUNFLAG_APTREINIT) != 0;
+       return (envGetSystemRunFlags() & RUNFLAG_APTREINIT) != 0;
 }
 
 static bool aptIsCrippled(void)
 {
-       return (__system_runflags & RUNFLAG_APTWORKAROUND) != 0 && !aptIsReinit();
+       return (envGetSystemRunFlags() & RUNFLAG_APTWORKAROUND) != 0 && !aptIsReinit();
 }
 
 static Result __apt_initservicehandle(void)
@@ -464,7 +460,7 @@ Result aptInit(void)
        if(R_FAILED(ret=APT_GetLockHandle(0x0, &aptLockHandle))) goto _fail;
        svcCloseHandle(aptuHandle);
 
-       currentAppId = __apt_appid;
+       currentAppId = envGetAptAppId();
 
        svcCreateEvent(&aptStatusEvent, 0);
        svcCreateEvent(&aptSleepSync, 0);
index 8e18cbc547fb69d955a716b3626adc209f26e2fb..90738a6cd3546b288802356e16cea236d96bedef 100644 (file)
@@ -6,13 +6,11 @@
 #include <3ds/synchronization.h>
 #include <3ds/services/fs.h>
 #include <3ds/ipc.h>
+#include <3ds/env.h>
 
 static Handle fsuHandle;
 static int fsuRefCount;
 
-// used to determine whether or not we should do FSUSER_Initialize on fsuHandle
-Handle __get_handle_from_list(char* name);
-
 Result fsInit(void)
 {
        Result ret = 0;
@@ -20,7 +18,7 @@ Result fsInit(void)
        if (AtomicPostIncrement(&fsuRefCount)) return 0;
 
        ret = srvGetServiceHandle(&fsuHandle, "fs:USER");
-       if (R_SUCCEEDED(ret) && __get_handle_from_list("fs:USER") == 0)
+       if (R_SUCCEEDED(ret) && envGetHandle("fs:USER") == 0)
        {
                ret = FSUSER_Initialize();
                if (R_FAILED(ret)) svcCloseHandle(fsuHandle);
index 4337939270f4a1c7feeddca3b94b3bd18ef8f032..2f93fc16b56566b49006bedd5211e6637fb5565a 100644 (file)
@@ -11,9 +11,7 @@
 #include <3ds/synchronization.h>
 #include <3ds/services/irrst.h>
 #include <3ds/ipc.h>
-
-// used to determine whether or not we should do IRRST_Initialize
-Handle __get_handle_from_list(char* name);
+#include <3ds/env.h>
 
 Handle irrstHandle;
 Handle irrstMemHandle;
@@ -38,7 +36,7 @@ Result irrstInit(void)
        if(R_FAILED(ret=IRRST_GetHandles(&irrstMemHandle, &irrstEvent))) goto cleanup1;
 
        // Initialize ir:rst
-       if(__get_handle_from_list("ir:rst")==0)ret=IRRST_Initialize(10, 0);
+       if(envGetHandle("ir:rst") == 0) ret = IRRST_Initialize(10, 0);
 
        // Map ir:rst shared memory.
        irrstSharedMem=(vu32*)mappableAlloc(0x98);
@@ -48,7 +46,7 @@ Result irrstInit(void)
                goto cleanup1;
        }
 
-       if(R_FAILED(ret=svcMapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem, MEMPERM_READ, 0x10000000)))goto cleanup2;
+       if(R_FAILED(ret = svcMapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem, MEMPERM_READ, 0x10000000))) goto cleanup2;
 
        // Reset internal state.
        kHeld = 0;
@@ -75,7 +73,7 @@ void irrstExit(void)
        svcCloseHandle(irrstEvent);
        // Unmap ir:rst sharedmem and close handles.
        svcUnmapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem);
-       if(__get_handle_from_list("ir:rst")==0) IRRST_Shutdown();
+       if(envGetHandle("ir:rst") == 0) IRRST_Shutdown();
        svcCloseHandle(irrstMemHandle);
        svcCloseHandle(irrstHandle);
 
index e3daaa145e037960ec5de5c0472b0edac88fd20d..e5b66526a1afe5e61366193f29cf670a8627c410 100644 (file)
@@ -8,93 +8,33 @@
 #include <3ds/srv.h>
 #include <3ds/svc.h>
 #include <3ds/ipc.h>
-
-
-/*
-  The homebrew loader can choose to supply a list of service handles that have
-  been "stolen" from other processes that have been compromised. This allows us
-  to access services that are normally restricted from the current process.
-
-  For every service requested by the application, we shall first check if the
-  list given to us contains the requested service and if so use it. If we don't
-  find the service in that list, we ask the service manager and hope for the
-  best.
- */
-
-typedef struct {
-       u32 num;
-
-       struct {
-               char name[8];
-               Handle handle;
-       } services[];
-} service_list_t;
-
-extern service_list_t* __service_ptr;
-
-static int __name_cmp(const char* a, const char* b) {
-       u32 i;
-
-       for(i=0; i<8; i++) {
-               if(a[i] != b[i])
-                       return 1;
-               if(a[i] == '\0')
-                       return 0;
-       }
-
-       return 0;
-}
-
-Handle __get_handle_from_list(const char* name) {
-       if((u32)__service_ptr == 0)
-               return 0;
-
-       u32 i, num = __service_ptr->num;
-
-       for(i=0; i<num; i++) {
-               if(__name_cmp(__service_ptr->services[i].name, name) == 0)
-                       return __service_ptr->services[i].handle;
-       }
-
-       return 0;
-}
-
-void __destroy_handle_list(void) {
-       if((u32)__service_ptr == 0)
-               return;
-
-       u32 i, num = __service_ptr->num;
-
-       for(i=0; i<num; i++)
-               svcCloseHandle(__service_ptr->services[i].handle);
-
-       __service_ptr->num = 0;
-}
+#include <3ds/synchronization.h>
+#include <3ds/env.h>
 
 static Handle srvHandle;
+static int srvRefCount;
 
 Result srvInit(void)
 {
        Result rc = 0;
 
-       if(srvHandle != 0) return rc;
+       if (AtomicPostIncrement(&srvRefCount)) return 0;
 
-       if(R_FAILED(rc = svcConnectToPort(&srvHandle, "srv:"))) return rc;
-
-       if(R_FAILED(rc = srvRegisterClient())) {
-               svcCloseHandle(srvHandle);
-               srvHandle = 0;
-       }
+       rc = svcConnectToPort(&srvHandle, "srv:");
+       if (R_FAILED(rc)) goto end;
 
+       rc = srvRegisterClient();
+end:
+       if (R_FAILED(rc)) srvExit();
        return rc;
 }
 
-Result srvExit(void)
+void srvExit(void)
 {
-       if(srvHandle != 0) svcCloseHandle(srvHandle);
+       if (AtomicDecrement(&srvRefCount)) return;
 
+       if (srvHandle != 0) svcCloseHandle(srvHandle);
        srvHandle = 0;
-       return 0;
 }
 
 Handle *srvGetSessionHandle(void)
@@ -106,7 +46,7 @@ Result srvGetServiceHandle(Handle* out, const char* name)
 {
        /* Look in service-list given to us by loader. If we find find a match,
           we return it. */
-       Handle h = __get_handle_from_list(name);
+       Handle h = envGetHandle(name);
 
        if(h != 0) {
                return svcDuplicateHandle(out, h);
index 44bbe639290bddde29d5a4e507f5bb2b7bd9e695..6bfcb62706fcc20566c73b9559bb1a7246ccfdfa 100644 (file)
@@ -1,24 +1,31 @@
 #include <3ds/types.h>
 #include <3ds/svc.h>
+#include <3ds/env.h>
 
 extern char* fake_heap_start;
 extern char* fake_heap_end;
-u32 __linear_heap;
-u32 __heapBase;
-extern u32 __heap_size, __linear_heap_size;
 
+u32 __ctru_heap;
+u32 __ctru_heap_size;
+u32 __ctru_linear_heap;
+u32 __ctru_linear_heap_size;
 
 void __attribute__((weak)) __system_allocateHeaps() {
        u32 tmp=0;
 
+       // Retrieve heap sizes.
+       __ctru_heap_size = envGetHeapSize();
+       __ctru_linear_heap_size = envGetLinearHeapSize();
+
        // Allocate the application heap
-       __heapBase = 0x08000000;
-       svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
+       __ctru_heap = 0x08000000;
+       svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
 
        // Allocate the linear heap
-       svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE);
+       svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE);
+
        // Set up newlib heap
-       fake_heap_start = (char*)__heapBase;
-       fake_heap_end = fake_heap_start + __heap_size;
+       fake_heap_start = (char*)__ctru_heap;
+       fake_heap_end = fake_heap_start + __ctru_heap_size;
 
-}
\ No newline at end of file
+}
index 41c5acd1bb5dfa41327628ba7786229591d5d1b5..e9ece2e7e9a1046e2d397aa744395a66a1d14625 100644 (file)
@@ -1,12 +1,16 @@
 #include <3ds/types.h>
 #include <3ds/svc.h>
+#include <3ds/env.h>
+
+extern u32 __ctru_heap;
+extern u32 __ctru_heap_size;
+extern u32 __ctru_linear_heap;
+extern u32 __ctru_linear_heap_size;
 
-extern u32 __linear_heap;
-extern u32 __heapBase;
-extern u32 __heap_size, __linear_heap_size;
 extern void (*__system_retAddr)(void);
 
-void __destroy_handle_list(void);
+void envDestroyHandles(void);
+
 void __appExit();
 
 void __libc_fini_array(void);
@@ -18,13 +22,13 @@ void __attribute__((weak)) __attribute__((noreturn)) __libctru_exit(int rc)
        u32 tmp=0;
 
        // Unmap the linear heap
-       svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0);
+       svcControlMemory(&tmp, __ctru_linear_heap, 0x0, __ctru_linear_heap_size, MEMOP_FREE, 0x0);
 
        // Unmap the application heap
-       svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0);
+       svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_FREE, 0x0);
 
        // Close some handles
-       __destroy_handle_list();
+       envDestroyHandles();
 
        if (__sync_fini)
                __sync_fini();
index 0fae5ddf3e6fac588bcc99230d5f444232ec4f4d..d566b000397c18eb5aff82493aee919fdd7a4f07 100644 (file)
@@ -1,11 +1,11 @@
 #include <3ds/types.h>
+#include <3ds/env.h>
 
 #include <string.h>
 
 // System globals we define here
 int __system_argc;
 char** __system_argv;
-extern const char* __system_arglist;
 
 extern char* fake_heap_start;
 extern char* fake_heap_end;
@@ -13,7 +13,8 @@ extern char* fake_heap_end;
 void __system_initArgv()
 {
        int i;
-       const char* temp = __system_arglist;
+       const char* arglist = envGetSystemArgList();
+       const char* temp = arglist;
 
        // Check if the argument list is present
        if (!temp)
@@ -31,14 +32,14 @@ void __system_initArgv()
        }
 
        // Reserve heap memory for argv data
-       u32 argSize = temp - __system_arglist - sizeof(u32);
+       u32 argSize = temp - arglist - sizeof(u32);
        __system_argv = (char**)fake_heap_start;
        fake_heap_start += sizeof(char**)*(__system_argc + 1);
        char* argCopy = fake_heap_start;
        fake_heap_start += argSize;
 
        // Fill argv array
-       memcpy(argCopy, &__system_arglist[4], argSize);
+       memcpy(argCopy, &arglist[4], argSize);
        temp = argCopy;
        for (i = 0; i < __system_argc; i ++)
        {
index 98c5837e2126ab87cadf817dc11de5edfef22581..0d0ac97ee66583b0f2ecb012dc25bb59be994220 100644 (file)
@@ -1,15 +1,13 @@
 #include <sys/iosupport.h>
 #include <sys/time.h>
-
 #include <string.h>
+
 #include <3ds/types.h>
 #include <3ds/svc.h>
+#include <3ds/env.h>
 
 void (*__system_retAddr)(void);
 
-// Data from _prm structure
-extern void* __service_ptr; // used to detect if we're run from a homebrew launcher
-
 void __system_allocateHeaps();
 void __system_initArgv();
 void __appInit();
@@ -27,7 +25,7 @@ void __attribute__((weak)) __libctru_init(void (*retAddr)(void))
        __syscalls.exit = __ctru_exit;
     __syscalls.gettod_r = __libctru_gtod;
 
-       __system_retAddr = __service_ptr ? retAddr : NULL;
+       __system_retAddr = envIsHomebrew() ? retAddr : NULL;
 
        if (__sync_init)
                __sync_init();