summaryrefslogtreecommitdiff
path: root/exec/loader-aarch64.s
blob: 0fc9606c62a1b106aee875e21e001325ebbabb06 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Copyright (C) 2023-2024 Free Software Foundation, Inc.
//
// This file is part of GNU Emacs.
//
// GNU Emacs is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// GNU Emacs is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

// Notice that aarch64 requires that sp be aligned to 16 bytes while
// accessing memory from sp, so x20 is used to chase down the load
// area.

	.section .text
	.global _start
_start:
	//mov	x8, 101			// SYS_nanosleep
	//adr	x0, timespec		// req
	//mov	x1, #0			// rem
	//svc	#0			// syscall
	mov	x20, sp			// x20 = sp
	ldr	x10, [x20]		// x10 = original SP
	add	x20, x20, #16		// x20 = start of load area
	mov	x28, #-1		// x28 = secondary fd
.next_action:
	ldr	x11, [x20]		// action number
	and	x12, x11, #-17		// actual action number
	cbz	x12, .open_file		// open file?
	cmp	x12, #3			// jump?
	beq	.rest_of_exec
	cmp	x12, #4			// anonymous mmap?
	beq	.do_mmap_anon
.do_mmap:
	ldr	x0, [x20, 8]		// vm_address
	ldr	x1, [x20, 32]		// length
	ldr	x2, [x20, 24]		// protection
	ldr	x3, [x20, 40]		// flags
	tst	x11, #16		// primary fd?
	mov	x4, x29			// primary fd
	beq	.do_mmap_1
	mov	x4, x28			// secondary fd
.do_mmap_1:
	mov	x8, #222		// SYS_mmap
	ldr	x5, [x20, 16]		// file_offset
	svc	#0			// syscall
	ldr	x9, [x20, 8]		// length
	cmp	x0, x9			// mmap result
	bne	.perror			// print error
	ldr	x3, [x20, 48]		// clear
	add	x1, x1, x0		// x1 = vm_address + end
	sub	x3, x1, x3		// x3 = x1 - clear
	mov	x0, #0			// x0 = 0
.fill64:
	sub	x2, x1, x3		// x2 = x1 - x3
	cmp	x2, #63			// x2 >= 64?
	ble	.fillb			// start filling bytes
	stp	x0, x0, [x3]		// x3[0] = 0, x3[1] = 0
	stp	x0, x0, [x3, 16]	// x3[2] = 0, x3[3] = 0
	stp	x0, x0, [x3, 32]	// x3[4] = 0, x3[5] = 0
	stp	x0, x0, [x3, 48]	// x3[6] = 0, x3[7] = 0
	add	x3, x3, #64		// x3 += 8
	b	.fill64
.fillb:
	cmp	x1, x3			// x1 == x3?
	beq	.continue		// done
	strb	w0, [x3], #1		// ((char *) x3)++ = 0
	b	.fillb
.continue:
	add	x20, x20, #56		// next action
	b	.next_action
.do_mmap_anon:
	ldr	x0, [x20, 8]		// vm_address
	ldr	x1, [x20, 32]		// length
	ldr	x2, [x20, 24]		// protection
	ldr	x3, [x20, 40]		// flags
	mov	x4, #-1			// fd
	b	.do_mmap_1
.open_file:
	mov	x8, #56			// SYS_openat
	mov	x0, #-100		// AT_FDCWD
	add	x1, x20, #8		// file name
	mov	x2, #0			// O_RDONLY
	mov	x3, #0			// mode
	svc	#0			// syscall
	cmp	x0, #-1			// rc < 0?
	ble	.perror
	mov	x19, x1			// x19 == x1
.nextc:
	ldrb	w2, [x1], #1		// b = *x1++
	cmp	w2, #47			// dir separator?
	bne	.nextc1			// not dir separator
	mov	x19, x1			// x19 = char past separator
.nextc1:
	cbnz	w2, .nextc		// b?
	add	x1, x1, #7		// round up x1
	and	x20, x1, #-8		// mask for round, set x20
	tst	x11, #16		// primary fd?
	bne	.secondary		// secondary fd
	mov	x29, x0			// primary fd
	mov	x8, #167		// SYS_prctl
	mov	x0, #15			// PR_SET_NAME
	mov	x1, x19			// basename
	mov	x2, #0			// arg2
	mov	x3, #0			// arg3
	mov	x4, #0			// arg4
	mov	x5, #0			// arg5
	svc	#0			// syscall
	b	.next_action		// next action
.secondary:
	mov	x28, x0			// secondary fd
	b	.next_action		// next action.
.perror:
	mov	x8, #93			// SYS_exit
	mvn	x0, x0			// x1 = ~x0
	add	x0, x0, 1		// x1 += 1
	svc	#0			// exit
.rest_of_exec:
	mov	x7, x20			// x7 = x20
	mov	x20, x10		// x20 = x10
	ldr	x9, [x20]		// argc
	add	x9, x9, #2		// x9 += 2
	lsl	x9, x9, #3		// argc * 8
	add	x20, x20, x9		// now past argv
.skipenv:
	ldr	x9, [x20], #8		// x9 = *envp++
	cbnz	x9, .skipenv		// x9?
.one_auxv:
	ldr	x9, [x20], #16		// x9 = *sp, sp += 2
	cbz	x9, .cleanup		// !x9?
	cmp	x9, #3			// is AT_PHDR?
	beq	.replace_phdr		// replace
	cmp	x9, #4			// is AT_PHENT?
	beq	.replace_phent		// replace
	cmp	x9, #5			// is AT_PHNUM?
	beq	.replace_phnum		// replace
	cmp	x9, #9			// is AT_ENTRY?
	beq	.replace_entry		// replace
	cmp	x9, #7			// is AT_BASE?
	beq	.replace_base		// replace
	b	.one_auxv		// next auxv
.replace_phdr:
	ldr	x9, [x7, 40]		// at_phdr
	str	x9, [x20, -8]		// store value
	b	.one_auxv
.replace_phent:
	ldr	x9, [x7, 24]		// at_phent
	str	x9, [x20, -8]		// store value
	b	.one_auxv
.replace_phnum:
	ldr	x9, [x7, 32]		// at_phnum
	str	x9, [x20, -8]		// store value
	b	.one_auxv
.replace_entry:
	ldr	x9, [x7, 16]		// at_entry
	str	x9, [x20, -8]		// store value
	b	.one_auxv
.replace_base:
	ldr	x9, [x7, 48]		// at_base
	str	x9, [x20, -8]		// store value
	b	.one_auxv
.cleanup:
	cmp	x28, #-1		// is secondary fd set?
	bne	.cleanup1		// not set
	mov	x8, #57			// SYS_close
	mov	x0, x28			// secondary fd
	svc	#0			// syscall
.cleanup1:
	mov	x8, #57			// SYS_close
	mov	x0, x29			// primary fd
	svc	#0			// syscall
.enter:
	mov	sp, x10			// restore original SP
	mov	x0, #0			// clear rtld_fini
	ldr	x1, [x7, 8]		// branch to code
	br	x1

timespec:
	.quad 10
	.quad 10