mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
Minor changes
* Refactored system/* * Implemented all of tmem * Introduced virtmem
This commit is contained in:
parent
bfc15bb4e1
commit
3926969ebc
@ -31,11 +31,11 @@ bss_loop:
|
|||||||
|
|
||||||
// initialize system
|
// initialize system
|
||||||
mov x0, x28
|
mov x0, x28
|
||||||
bl __nx_init
|
bl __libnx_init
|
||||||
|
|
||||||
// call entrypoint
|
// call entrypoint
|
||||||
mov x0, #0 // argc
|
mov x0, #0 // argc
|
||||||
mov x1, #0 // argv
|
mov x1, #0 // argv
|
||||||
adrp x30, __nx_exit
|
adrp x30, __libnx_exit
|
||||||
add x30, x30, #:lo12:__nx_exit
|
add x30, x30, #:lo12:__libnx_exit
|
||||||
b main
|
b main
|
||||||
|
@ -16,6 +16,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include <switch/kernel/tmem.h>
|
#include <switch/kernel/tmem.h>
|
||||||
#include <switch/kernel/mutex.h>
|
#include <switch/kernel/mutex.h>
|
||||||
|
#include <switch/kernel/virtmem.h>
|
||||||
|
|
||||||
#include <switch/services/sm.h>
|
#include <switch/services/sm.h>
|
||||||
#include <switch/services/bsd.h>
|
#include <switch/services/bsd.h>
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Handle MemHandle;
|
Handle MemHandle;
|
||||||
size_t Size;
|
size_t Size;
|
||||||
|
Permission Perm;
|
||||||
|
void* SourceAddr;
|
||||||
|
void* MappedAddr;
|
||||||
} TransferMemory;
|
} TransferMemory;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PERM_NONE = 0,
|
|
||||||
PERM_R = 1,
|
|
||||||
PERM_RW = 3
|
|
||||||
} Permission;
|
|
||||||
|
|
||||||
Result tmemCreate(TransferMemory* t, size_t size, Permission perm);
|
Result tmemCreate(TransferMemory* t, size_t size, Permission perm);
|
||||||
Result tmemClose(TransferMemory* t);
|
void tmemLoadRemote(TransferMemory* t, Handle handle, size_t size, Permission perm);
|
||||||
|
|
||||||
|
Result tmemMap(TransferMemory* t);
|
||||||
|
Result tmemUnmap(TransferMemory* t);
|
||||||
|
void* tmemGetAddr(TransferMemory* t);
|
||||||
|
|
||||||
|
Result tmemClose(TransferMemory* t);
|
||||||
|
2
nx/include/switch/kernel/virtmem.h
Normal file
2
nx/include/switch/kernel/virtmem.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
void* virtmemReserve(size_t size);
|
||||||
|
void virtmemFree(void* addr, size_t size);
|
@ -19,4 +19,6 @@
|
|||||||
((((module)&0x1FF)) | ((description)&0x1FFF)<<9)
|
((((module)&0x1FF)) | ((description)&0x1FFF)<<9)
|
||||||
|
|
||||||
#define MODULE_LIBNX 345
|
#define MODULE_LIBNX 345
|
||||||
#define MODULE_BADRELOC 1
|
#define LIBNX_BADRELOC 1
|
||||||
|
#define LIBNX_OUTOFMEM 2
|
||||||
|
#define LIBNX_ALREADYMAPPED 3
|
||||||
|
@ -29,8 +29,7 @@ typedef struct {
|
|||||||
u32 padding;
|
u32 padding;
|
||||||
} MemInfo;
|
} MemInfo;
|
||||||
|
|
||||||
typedef struct _regs_t
|
typedef struct {
|
||||||
{
|
|
||||||
u64 X0;
|
u64 X0;
|
||||||
u64 X1;
|
u64 X1;
|
||||||
u64 X2;
|
u64 X2;
|
||||||
@ -39,11 +38,11 @@ typedef struct _regs_t
|
|||||||
u64 X5;
|
u64 X5;
|
||||||
u64 X6;
|
u64 X6;
|
||||||
u64 X7;
|
u64 X7;
|
||||||
} __attribute__((packed)) regs_t;
|
} __attribute__((packed)) SecmonArgs;
|
||||||
|
|
||||||
Result svcSetHeapSize(void** out_addr, u64 size);
|
Result svcSetHeapSize(void** out_addr, u64 size);
|
||||||
Result svcQueryMemory(MemInfo* meminfo_ptr, u32 *pageinfo, u64 addr);
|
Result svcQueryMemory(MemInfo* meminfo_ptr, u32 *pageinfo, u64 addr);
|
||||||
void svcExitProcess() __attribute__((noreturn));
|
void NORETURN svcExitProcess();
|
||||||
Result svcSleepThread(u64 nano);
|
Result svcSleepThread(u64 nano);
|
||||||
Result svcCloseHandle(Handle handle);
|
Result svcCloseHandle(Handle handle);
|
||||||
Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm);
|
Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm);
|
||||||
@ -57,6 +56,8 @@ Result svcGetInfo(u64* out, u64 id0, Handle handle, u64 id1);
|
|||||||
Result svcCreateSession(Handle *server_handle, Handle *client_handle, u32 unk0, u64 unk1);//unk* are normally 0?
|
Result svcCreateSession(Handle *server_handle, Handle *client_handle, u32 unk0, u64 unk1);//unk* are normally 0?
|
||||||
Result svcAcceptSession(Handle *session_handle, Handle port_handle);
|
Result svcAcceptSession(Handle *session_handle, Handle port_handle);
|
||||||
Result svcReplyAndReceive(s32* index, const Handle* handles, s32 handleCount, Handle replyTarget, u64 timeout);
|
Result svcReplyAndReceive(s32* index, const Handle* handles, s32 handleCount, Handle replyTarget, u64 timeout);
|
||||||
|
Result svcMapTransferMemory(Handle tmem_handle, void* addr, size_t size, u32 perm);
|
||||||
|
Result svcUnmapTransferMemory(Handle tmem_handle, void* addr, size_t size);
|
||||||
Result svcQueryPhysicalAddress(u64 out[3], u64 virtaddr);
|
Result svcQueryPhysicalAddress(u64 out[3], u64 virtaddr);
|
||||||
Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
|
Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
|
||||||
Result svcCreateDeviceAddressSpace(Handle *handle, u64 dev_addr, u64 dev_size);
|
Result svcCreateDeviceAddressSpace(Handle *handle, u64 dev_addr, u64 dev_size);
|
||||||
@ -69,4 +70,4 @@ Result svcContinueDebugEvent(Handle debug, u32 flags, u64 unk);
|
|||||||
Result svcQueryDebugProcessMemory(MemInfo* meminfo_ptr, u32* pageinfo, Handle debug, u64 addr);
|
Result svcQueryDebugProcessMemory(MemInfo* meminfo_ptr, u32* pageinfo, Handle debug, u64 addr);
|
||||||
Result svcReadDebugProcessMemory(void* buffer, Handle debug, u64 addr, u64 size);
|
Result svcReadDebugProcessMemory(void* buffer, Handle debug, u64 addr, u64 size);
|
||||||
Result svcManageNamedPort(Handle* portServer, const char* name, s32 maxSessions);
|
Result svcManageNamedPort(Handle* portServer, const char* name, s32 maxSessions);
|
||||||
u64 svcCallSecureMonitor(regs_t *regs);
|
u64 svcCallSecureMonitor(SecmonArgs* regs);
|
||||||
|
@ -43,6 +43,14 @@ typedef u32 Result; ///< Function result.
|
|||||||
typedef void (*ThreadFunc)(void *); ///< Thread entrypoint function.
|
typedef void (*ThreadFunc)(void *); ///< Thread entrypoint function.
|
||||||
typedef void (*voidfn)(void);
|
typedef void (*voidfn)(void);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PERM_NONE = 0,
|
||||||
|
PERM_R = 1,
|
||||||
|
PERM_W = 2,
|
||||||
|
PERM_RW = PERM_R | PERM_W,
|
||||||
|
PERM_DONTCARE = 0x10000000
|
||||||
|
} Permission;
|
||||||
|
|
||||||
/// Creates a bitmask from a bit number.
|
/// Creates a bitmask from a bit number.
|
||||||
#define BIT(n) (1U<<(n))
|
#define BIT(n) (1U<<(n))
|
||||||
|
|
||||||
@ -51,6 +59,9 @@ typedef void (*voidfn)(void);
|
|||||||
/// Packs a struct (and other types?) so it won't include padding bytes.
|
/// Packs a struct (and other types?) so it won't include padding bytes.
|
||||||
#define PACKED __attribute__((packed))
|
#define PACKED __attribute__((packed))
|
||||||
|
|
||||||
|
#define NORETURN __attribute__((noreturn))
|
||||||
|
#define IGNORE_ARG(x) (void)(x)
|
||||||
|
|
||||||
#ifndef LIBCTRU_NO_DEPRECATION
|
#ifndef LIBCTRU_NO_DEPRECATION
|
||||||
/// Flags a function as deprecated.
|
/// Flags a function as deprecated.
|
||||||
#define DEPRECATED __attribute__ ((deprecated))
|
#define DEPRECATED __attribute__ ((deprecated))
|
||||||
@ -59,3 +70,4 @@ typedef void (*voidfn)(void);
|
|||||||
#define DEPRECATED
|
#define DEPRECATED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define INVALID_HANDLE ((Handle) -1)
|
||||||
|
@ -118,6 +118,16 @@ SVC_BEGIN svcReplyAndReceive
|
|||||||
ret
|
ret
|
||||||
SVC_END
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcMapTransferMemory
|
||||||
|
svc 0x51
|
||||||
|
ret
|
||||||
|
SVC_END
|
||||||
|
|
||||||
|
SVC_BEGIN svcUnmapTransferMemory
|
||||||
|
svc 0x52
|
||||||
|
ret
|
||||||
|
SVC_END
|
||||||
|
|
||||||
SVC_BEGIN svcQueryPhysicalAddress
|
SVC_BEGIN svcQueryPhysicalAddress
|
||||||
str x0, [sp, #-16]!
|
str x0, [sp, #-16]!
|
||||||
svc 0x54
|
svc 0x54
|
||||||
|
@ -1,21 +1,98 @@
|
|||||||
|
// Copyright 2017 plutoo
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
|
||||||
Result tmemCreate(TransferMemory* t, size_t size, Permission perm) {
|
Result tmemCreate(TransferMemory* t, size_t size, Permission perm)
|
||||||
t->Size = size;
|
{
|
||||||
|
|
||||||
Result rc = 0;
|
Result rc = 0;
|
||||||
void* addr = heapAllocPages(size);
|
|
||||||
|
|
||||||
if (addr == NULL)
|
t->MemHandle = INVALID_HANDLE;
|
||||||
rc = -1;
|
t->Size = size;
|
||||||
|
t->Perm = perm;
|
||||||
|
t->MappedAddr = NULL;
|
||||||
|
t->SourceAddr = heapAllocPages(size);
|
||||||
|
|
||||||
|
if (t->SourceAddr == NULL) {
|
||||||
|
rc = MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM);
|
||||||
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
rc = svcCreateTransferMemory(&t->MemHandle, addr, size, perm);
|
rc = svcCreateTransferMemory(&t->MemHandle, t->SourceAddr, size, perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result tmemClose(TransferMemory* t) {
|
void tmemLoadRemote(TransferMemory* t, Handle handle, size_t size, Permission perm)
|
||||||
return svcCloseHandle(t->MemHandle);
|
{
|
||||||
|
t->MemHandle = handle;
|
||||||
|
t->Size = size;
|
||||||
|
t->Perm = perm;
|
||||||
|
t->MappedAddr = NULL;
|
||||||
|
t->SourceAddr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result tmemMap(TransferMemory* t)
|
||||||
|
{
|
||||||
|
Result rc = 0;
|
||||||
|
|
||||||
|
if (t->MappedAddr == NULL)
|
||||||
|
{
|
||||||
|
void* addr = virtmemReserve(t->Size);
|
||||||
|
|
||||||
|
rc = svcMapTransferMemory(t->MemHandle, addr, t->Size, t->Perm);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
t->MappedAddr = addr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
virtmemFree(addr, t->Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc = LIBNX_ALREADYMAPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result tmemUnmap(TransferMemory* t)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
|
||||||
|
rc = svcUnmapTransferMemory(t->MemHandle, t->MappedAddr, t->Size);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
t->MappedAddr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tmemGetAddr(TransferMemory* t) {
|
||||||
|
return t->MappedAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result tmemClose(TransferMemory* t)
|
||||||
|
{
|
||||||
|
Result rc = 0;
|
||||||
|
|
||||||
|
if (t->SourceAddr != NULL) {
|
||||||
|
// todo: Free is currently broken for page-aligned allocs.
|
||||||
|
//heapFree(t->SourceAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->MappedAddr != NULL) {
|
||||||
|
rc = tmemUnmap(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (t->MemHandle != INVALID_HANDLE) {
|
||||||
|
rc = svcCloseHandle(t->MemHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
t->SourceAddr = NULL;
|
||||||
|
t->MemHandle = INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
21
nx/source/kernel/virtmem.c
Normal file
21
nx/source/kernel/virtmem.c
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
static u8* g_VirtBase;
|
||||||
|
|
||||||
|
void virtmemSetup() {
|
||||||
|
// TODO: Implement this.
|
||||||
|
}
|
||||||
|
|
||||||
|
void* virtmemReserve(size_t size) {
|
||||||
|
void* ret = g_VirtBase;
|
||||||
|
|
||||||
|
size = (size + 0xFFF) &~ 0xFFF;
|
||||||
|
g_VirtBase += size + 0x1000;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void virtmemFree(void* addr, size_t size) {
|
||||||
|
(void) addr;
|
||||||
|
(void) size;
|
||||||
|
}
|
@ -27,7 +27,7 @@ void fatalSimple(Result err) {
|
|||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
raw->magic = SFCI_MAGIC;
|
||||||
raw->cmd_id = 1;
|
raw->cmd_id = 0;
|
||||||
raw->result = err;
|
raw->result = err;
|
||||||
raw->unknown = 0;
|
raw->unknown = 0;
|
||||||
|
|
||||||
|
@ -49,10 +49,8 @@ Result smInitialize() {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void smExit(void)
|
void smExit(void) {
|
||||||
{
|
if(smHasInitialized()) {
|
||||||
if(smHasInitialized())
|
|
||||||
{
|
|
||||||
svcCloseHandle(g_smHandle);
|
svcCloseHandle(g_smHandle);
|
||||||
g_smHandle = -1;
|
g_smHandle = -1;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#include <switch/types.h>
|
|
||||||
#include <switch/services/sm.h>
|
|
||||||
|
|
||||||
void __attribute__((weak)) __appExit(void) {
|
|
||||||
// Initialize services
|
|
||||||
smExit();
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#include <switch/types.h>
|
|
||||||
#include <switch/services/sm.h>
|
|
||||||
|
|
||||||
void __attribute__((weak)) __appInit(void) {
|
|
||||||
// Initialize services
|
|
||||||
smInitialize();
|
|
||||||
}
|
|
@ -20,7 +20,7 @@ void __nx_dynamic(uintptr_t base, const Elf64_Dyn* dyn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rela == NULL)
|
if (rela == NULL)
|
||||||
fatalSimple(MAKERESULT(MODULE_LIBNX, MODULE_BADRELOC));
|
fatalSimple(MAKERESULT(MODULE_LIBNX, LIBNX_BADRELOC));
|
||||||
|
|
||||||
for (; relasz--; rela++)
|
for (; relasz--; rela++)
|
||||||
{
|
{
|
||||||
|
62
nx/source/system/init.c
Normal file
62
nx/source/system/init.c
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/reent.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void __nx_exit(int rc);
|
||||||
|
|
||||||
|
void virtmemSetup();
|
||||||
|
void heapSetup();
|
||||||
|
|
||||||
|
void __attribute__((weak)) __appInit(void)
|
||||||
|
{
|
||||||
|
// Initialize default services.
|
||||||
|
smInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((weak)) __appExit(void)
|
||||||
|
{
|
||||||
|
// Cleanup default services.
|
||||||
|
smExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((weak)) __libnx_init(void)
|
||||||
|
{
|
||||||
|
// Called by crt0.
|
||||||
|
|
||||||
|
// Newlib initialization goes here.
|
||||||
|
void exitImpl(int rc);
|
||||||
|
__syscalls.exit = exitImpl;
|
||||||
|
|
||||||
|
// Libnx initialization goes here.
|
||||||
|
virtmemSetup();
|
||||||
|
heapSetup();
|
||||||
|
|
||||||
|
// Initialize services.
|
||||||
|
__appInit();
|
||||||
|
|
||||||
|
// Call constructors.
|
||||||
|
void __libc_init_array(void);
|
||||||
|
__libc_init_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((weak)) NORETURN __libnx_exit(void)
|
||||||
|
{
|
||||||
|
// Call destructors.
|
||||||
|
void __libc_fini_array(void);
|
||||||
|
__libc_fini_array();
|
||||||
|
|
||||||
|
// Clean up services.
|
||||||
|
__appExit();
|
||||||
|
|
||||||
|
svcExitProcess();
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NORETURN exitImpl(int rc)
|
||||||
|
{
|
||||||
|
__libnx_exit();
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
#include <sys/iosupport.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <switch/types.h>
|
|
||||||
#include <switch/svc.h>
|
|
||||||
|
|
||||||
void __system_initSyscalls(void);
|
|
||||||
|
|
||||||
void heapSetup();
|
|
||||||
|
|
||||||
void __attribute__((weak)) __libnx_init(void)
|
|
||||||
{
|
|
||||||
// Initialize newlib support system calls
|
|
||||||
__system_initSyscalls();
|
|
||||||
|
|
||||||
heapSetup();
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#include <switch/types.h>
|
|
||||||
#include <switch/svc.h>
|
|
||||||
|
|
||||||
void __attribute__((weak)) __attribute__((noreturn)) __libnx_exit(int rc)
|
|
||||||
{
|
|
||||||
svcExitProcess();
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
#include <sys/iosupport.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/lock.h>
|
|
||||||
#include <sys/reent.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <switch/types.h>
|
|
||||||
#include <switch/svc.h>
|
|
||||||
|
|
||||||
void __nx_exit(int rc);
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
/*extern const u8 __tdata_lma[];
|
|
||||||
extern const u8 __tdata_lma_end[];
|
|
||||||
extern u8 __tls_start[];
|
|
||||||
|
|
||||||
static struct _reent* __nx_get_reent()
|
|
||||||
{
|
|
||||||
ThreadVars* tv = getThreadVars();
|
|
||||||
if (tv->magic != THREADVARS_MAGIC)
|
|
||||||
{
|
|
||||||
svcBreak(USERBREAK_PANIC);
|
|
||||||
for (;;);
|
|
||||||
}
|
|
||||||
return tv->reent;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void __system_initSyscalls(void)
|
|
||||||
{
|
|
||||||
// Register newlib syscalls
|
|
||||||
__syscalls.exit = __nx_exit;
|
|
||||||
//__syscalls.getreent = __nx_get_reent;
|
|
||||||
|
|
||||||
// Initialize thread vars for the main thread (TODO)
|
|
||||||
/*ThreadVars* tv = getThreadVars();
|
|
||||||
tv->magic = THREADVARS_MAGIC;
|
|
||||||
tv->reent = _impure_ptr;
|
|
||||||
tv->thread_ptr = NULL;
|
|
||||||
tv->tls_tp = __tls_start-8; // ARM ELF TLS ABI mandates an 8-byte header
|
|
||||||
|
|
||||||
u32 tls_size = __tdata_lma_end - __tdata_lma;
|
|
||||||
if (tls_size)
|
|
||||||
memcpy(__tls_start, __tdata_lma, tls_size);*/
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
.text
|
|
||||||
.global __nx_init
|
|
||||||
.type __nx_init, %function
|
|
||||||
|
|
||||||
__nx_init:
|
|
||||||
stp x29, x30, [sp, #-16]!
|
|
||||||
bl __libnx_init
|
|
||||||
bl __appInit
|
|
||||||
bl __libc_init_array
|
|
||||||
ldp x29, x30, [sp], #16
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global __nx_exit
|
|
||||||
.type __nx_exit, %function
|
|
||||||
|
|
||||||
__nx_exit:
|
|
||||||
bl __libc_fini_array
|
|
||||||
bl __appExit
|
|
||||||
b __libnx_exit
|
|
Loading…
Reference in New Issue
Block a user