libnx/nx/source/runtime/switch_crt0.s

104 lines
2.8 KiB
ArmAsm

.section .crt0, "ax", %progbits
.global _start
.align 2
_start:
b 1f
.word __nx_mod0 - _start
.ascii "HOMEBREW"
.org _start+0x80; 1:
// Arguments on NSO entry:
// x0=zero | x1=main thread handle
// Arguments on NRO entry (homebrew ABI):
// x0=ptr to env context | x1=UINT64_MAX (-1 aka 0xFFFFFFFFFFFFFFFF)
// Arguments on user-mode exception entry:
// x0=excpt type (non-zero) | x1=ptr to excpt context
// Detect and handle user-mode exceptions first:
// if (x0 != 0 && x1 != UINT64_MAX) __libnx_exception_entry(<inargs>);
cmp x0, #0
ccmn x1, #1, #4, ne // 4 = Z
beq .Lcrt0_main_entry
b __libnx_exception_entry
.Lcrt0_main_entry:
// Get pointer to MOD0 struct (contains offsets to important places)
adr x28, __nx_mod0
// Calculate BSS address/size
ldp w8, w9, [x28, #8] // load BSS start/end offset from MOD0
sub w9, w9, w8 // calculate BSS size
add w9, w9, #7 // round up to 8
bic w9, w9, #7 // ^
add x8, x28, x8 // fixup the start pointer
// Clear the BSS in 8-byte units
1: subs w9, w9, #8
str xzr, [x8], #8
bne 1b
// Preserve registers across function calls
mov x25, x0 // entrypoint argument 0
mov x26, x1 // entrypoint argument 1
mov x27, x30 // loader return address
// Save initial stack pointer
mov x8, sp
adrp x9, __stack_top
str x8, [x9, #:lo12:__stack_top]
// Parse ELF .dynamic section (which applies relocations to our module)
adr x0, _start // get aslr base
ldr w1, [x28, #4] // pointer to .dynamic section
add x1, x28, x1
bl __nx_dynamic
// Perform system initialization
mov x0, x25
mov x1, x26
mov x2, x27
bl __libnx_init
// Jump to the main function
adrp x0, __system_argc // argc
ldr w0, [x0, #:lo12:__system_argc]
adrp x1, __system_argv // argv
ldr x1, [x1, #:lo12:__system_argv]
adrp x30, exit
add x30, x30, #:lo12:exit
b main
.global __nx_exit
.type __nx_exit, %function
__nx_exit:
// Restore stack pointer
adrp x8, __stack_top
ldr x8, [x8, #:lo12:__stack_top]
mov sp, x8
// Jump back to loader
br x1
.global __nx_mod0
__nx_mod0:
.ascii "MOD0"
.word _DYNAMIC - __nx_mod0
.word __bss_start__ - __nx_mod0
.word __bss_end__ - __nx_mod0
.word __eh_frame_hdr_start - __nx_mod0
.word __eh_frame_hdr_end - __nx_mod0
.word 0 // "offset to runtime-generated module object" (neither needed, used nor supported in homebrew)
// MOD0 extensions for homebrew
.ascii "LNY0"
.word __got_start__ - __nx_mod0
.word __got_end__ - __nx_mod0
.section .bss.__stack_top, "aw", %nobits
.global __stack_top
.align 3
__stack_top:
.space 8