1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// For more information on the .nro file format, see:
// https://switchbrew.org/wiki/NRO
.section .text.jmp, "x"
.global _start
_start:
b start
.word _mod_header - _start
.ascii "HOMEBREW"
.ascii "NRO0" // magic
.word 0 // version (always 0)
.word __bss_start - _start // total NRO file size
.word 0 // flags (unused)
// segment headers
.word __text_start - _start
.word __text_size
.word __rodata_start - _start
.word __rodata_size
.word __data_start - _start
.word __data_size
.word __bss_size
.word 0
// ModuleId (not supported)
. = 0x50; // skip 32 bytes
.word 0 // DSO Module Offset (unused)
.word 0 // reserved (unused)
.section .data.mod0
.word 0, 8
.global _mod_header
_mod_header:
.ascii "MOD0"
.word __dynamic_start - _mod_header
.word __bss_start - _mod_header
.word __bss_end - _mod_header
.word 0, 0 // eh_frame_hdr start/end
.word 0 // runtime-generated module object offset
.section .text.start, "x"
.global start
start:
// save lr
mov x7, x30
// get aslr base
bl +4
sub x6, x30, #0x88
// context ptr and main thread handle
mov x25, x0
mov x26, x1
// Save ASLR Base to use later
mov x0, x6
adrp x4, _saved_return_address
str x7, [x4, #:lo12:_saved_return_address]
adrp x4, _context
str x25, [x4, #:lo12:_context]
adrp x4, _main_thread
str x26, [x4, #:lo12:_main_thread]
// store stack pointer
mov x26, sp
adrp x4, _stack_top
str x26, [x4, #:lo12:_stack_top]
// clear .bss
adrp x5, __bss_start
add x5, x5, #:lo12:__bss_start
adrp x6, __bss_end
add x6, x6, #:lo12:__bss_end
bssloop:
cmp x5, x6
b.eq run
str xzr, [x5]
add x5, x5, 8
b bssloop
run:
// process .dynamic section
// ASLR base on x0
adrp x1, _DYNAMIC
add x1, x1, #:lo12:_DYNAMIC
bl __dynamic_loader
// call entrypoint
b main
.global __nx_exit
.type __nx_exit, %function
__nx_exit:
// Exit code in x0
// restore stack pointer
mov sp, x1
// jump back to loader
br x2
.section .data.horizon
.align 8
.global _saved_return_address // Saved return address.
// This might be different than null when coming from launcher
_saved_return_address:
.dword 0
.global _context // Homebrew Launcher Context
// This might be different than null when not coming from launcher
_context:
.dword 0
.global _main_thread
_main_thread:
.dword 0
.global _stack_top
_stack_top:
.dword 0
|