aboutsummaryrefslogtreecommitdiffhomepage
path: root/targets/nintendoswitch.s
blob: 48edc857f2a23c72474eb3dc2bd44a46aa57bc78 (plain)
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