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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
# Copyright (C) 2023-2026 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/>.
.section .text
.global _start
_start:
# movq $35, %rax # SYS_nanosleep
# leaq timespec(%rip), %rdi
# xorq %rsi, %rsi
# syscall
popq %r13 # original SP
popq %r15 # size of load area.
movq $-1, %r12 # r12 is the interpreter fd
next_action:
movq (%rsp), %r14 # action number
movq %r14, %r15 # original action number
andq $-17, %r14
cmpq $0, %r14 # open file?
je open_file
cmpq $3, %r14 # jump?
je rest_of_exec
cmpq $4, %r14 # anonymous mmap?
je do_mmap_anon
do_mmap:
movq $9, %rax # SYS_mmap
movq 8(%rsp), %rdi # address
movq 16(%rsp), %r9 # offset
movq 24(%rsp), %rdx # protection
movq 32(%rsp), %rsi # length
movq 40(%rsp), %r10 # flags
# set r8 to the primary fd unless r15 & 16
testq $16, %r15
movq %r12, %r8
cmovzq %rbx, %r8
do_mmap_1:
syscall
cmpq $-1, %rax # mmap failed
je perror
movq 48(%rsp), %r9 # clear
testq %r9, %r9
jz continue
movq 8(%rsp), %r10 # start of mapping
addq 32(%rsp), %r10 # end of mapping
subq %r9, %r10 # start of clear area
again:
testq %r9, %r9
jz continue
subq $1, %r9
movb $0, (%r10, %r9, 1)
jmp again
continue:
leaq 56(%rsp), %rsp
jmp next_action
do_mmap_anon:
movq $9, %rax # SYS_mmap
movq 8(%rsp), %rdi # address
movq 16(%rsp), %r9 # offset
movq 24(%rsp), %rdx # protection
movq 32(%rsp), %rsi # length
movq 40(%rsp), %r10 # flags
movq $-1, %r8 # -1
jmp do_mmap_1
open_file:
movq $2, %rax # SYS_open
leaq 8(%rsp), %rdi # rdi = %rsp + 8
xorq %rsi, %rsi # flags = O_RDONLY
xorq %rdx, %rdx # mode = 0
syscall
cmpq $-1, %rax # open failed
jle perror
movq %rdi, %rsp # rsp = start of string
subq $1, %rsp
movq %rsp, %r14 # r14 = start of string
nextc:
addq $1, %rsp
movb (%rsp), %dil # rdi = *rsp
cmpb $47, %dil # *rsp == '/'?
jne nextc1
movq %rsp, %r14 # r14 = rsp
addq $1, %r14 # r14 = char past separator
nextc1:
cmpb $0, %dil # *rsp == 0?
jne nextc
addq $8, %rsp # adjust past rsp prior to rounding
andq $-8, %rsp # round rsp up to the next quad
testq $16, %r15 # r15 & 16?
jz primary
movq %rax, %r12 # otherwise, move fd to r12
jmp next_action
primary:
movq %rax, %rbx # if not, move fd to rbx
movq $157, %rax # SYS_prctl
movq $15, %rdi # PR_SET_NAME
movq %r14, %rsi # arg1
xorq %rdx, %rdx # arg2
xorq %r10, %r10 # arg3
xorq %r8, %r8 # arg4
xorq %r9, %r9 # arg5
syscall
jmp next_action
perror:
movq %rax, %r12 # error code
negq %r12
movq $1, %rax # SYS_write
movq $1, %rdi # stdout
leaq error(%rip), %rsi # buffer
movq $24, %rdx # count
syscall
movq $60, %rax # SYS_exit
movq %r12, %rdi # code
syscall
rest_of_exec: # rsp now points to seven quads + string:
movq %rsp, %r8 # now, they are r8
movq %r13, %rsp # restore SP
popq %r10 # argc
leaq 8(%rsp,%r10,8), %rsp # now at start of environ
skip_environ:
popq %rcx # envp[N]
testq %rcx, %rcx # envp[n]?
jnz skip_environ # otherwise, rsp is now at the end of auxv
movq %rsp, %r11 # start of auxv
1: testq $-1, (%r11) # NULL?
leaq 16(%r11), %r11 # next entry
jnz 1b # otherwise copy auxv
/* Prepare sufficient space for the new executable name at the
start of the auxiliary vector. */
1: leaq 64(%r8), %rsi # file name
movq 56(%r8), %r9 # name length
leaq -1(%r11), %r14
subq %r9, %r14 # destination of file name
andq $-16, %r14 # align destination
/* Prepare to copy argv, environ and auxv. */
1: subq %r13, %r11 # size required
addq $15, %r11 # align size
andq $-16, %r11
negq %r11 # subtract
leaq -56(%r14,%r11,1), %r11 # %r11 = destination - struct exec_jump_command
/* Move the file name out of the way. */
leaq 9(%rsi,%r9,1), %r10 # end of name + 8
cmpq %r10, %r11 # end of name >= struct exec_jump_command - 8
jae 1f # save exec command
xorq %r10, %r10
subq %r9, %r10
leaq -9(%r11,%r10,1), %rdi # position of new name
movq %rdi, %r10
cld
leaq 1(%r9), %rcx # length (including termination)
rep movsb # copy file name
movq %r10, %rsi # file name
/* Preserve jump command. */
1: cmpq %r8, %r11 # decide copy direction
jb 1f # copy forward
movq 48(%r8), %rax
movq %rax, 48(%r11) # %r11->at_base
movq 40(%r8), %rax
movq %rax, 40(%r11) # %r11->at_phdr
movq 32(%r8), %rax
movq %rax, 32(%r11) # %r11->at_phnum
movq 24(%r8), %rax
movq %rax, 24(%r11) # %r11->at_phent
movq 16(%r8), %rax
movq %rax, 16(%r11) # %r11->at_entry
movq 8(%r8), %rax
movq %rax, 8(%r11) # %r11->entry
movq (%r8), %rax
movq %rax, (%r11) # %r11->command
movq %r14, -8(%r11) # destination of file name
jmp copy_env_and_args
1: movq %r14, -8(%r11) # destination of file name
movq (%r8), %rax
movq %rax, (%r11) # %r11->command
movq 8(%r8), %rax
movq %rax, 8(%r11) # %r11->entry
movq 16(%r8), %rax
movq %rax, 16(%r11) # %r11->at_entry
movq 24(%r8), %rax
movq %rax, 24(%r11) # %r11->at_phent
movq 32(%r8), %rax
movq %rax, 32(%r11) # %r11->at_phnum
movq 40(%r8), %rax
movq %rax, 40(%r11) # %r11->at_phdr
movq 48(%r8), %rax
movq %rax, 48(%r11) # %r11->at_base
copy_env_and_args:
/* Copy argv and environ to their new positions. */
leaq 8(%r13), %r10 # src
leaq 64(%r11), %rdi # dest
movq (%r13), %rcx # argc
movq %rcx, -8(%rdi) # copy argc
1: movq (%r10), %rcx
movq %rcx, (%rdi)
testq %rcx, %rcx
leaq 8(%r10), %r10 # src++
leaq 8(%rdi), %rdi # dst++
jnz 1b
1: movq (%r10), %rcx
movq %rcx, (%rdi)
testq %rcx, %rcx
leaq 8(%r10), %r10 # src++
leaq 8(%rdi), %rdi # dst++
jnz 1b
copy_auxv:
movq (%r10), %rcx # a_type
movq 8(%r10), %rdx # a_un.a_val
addq $16, %r10 # next entry
movq %rcx, (%rdi)
jrcxz cleanup # AT_NULL
cmpq $3, %rcx # AT_PHDR
cmoveq 40(%r11), %rdx # %r11->at_phdr
cmpq $4, %rcx # AT_PHENT
cmoveq 24(%r11), %rdx # %r11->at_phent
cmpq $5, %rcx # AT_PHNUM
cmoveq 32(%r11), %rdx # %r11->at_phnum
cmpq $9, %rcx # AT_ENTRY
cmoveq 16(%r11), %rdx # %r11->at_entry
cmpq $7, %rcx # AT_BASE
cmoveq 48(%r11), %rdx # %r11->at_base
cmpq $31, %rcx # AT_EXECFN
jne 1f
movq -8(%r11), %rdx # string
1: movq %rdx, 8(%rdi) # AT_NULL value
addq $16, %rdi # next entry
jmp copy_auxv
cleanup:
/* Copy the filename. */
movq -8(%r11), %rdi # destination of file name
leaq 1(%r9), %rcx # length (including termination)
rep movsb
movq %rdx, 8(%rdi) # AT_NULL value
leaq 56(%r11), %r13 # restore original stack pointer
movq $3, %rax # SYS_close
cmpq $-1, %r12 # see if interpreter fd is set
je cleanup_1
movq %r12, %rdi
syscall
movq $3, %rax # SYS_close
cleanup_1:
movq %rbx, %rdi
syscall
/* Enter the program. */
pushq $0
popfq # clear FP state
movq %r13, %rsp # restore SP
xorq %rdx, %rdx # clear rtld_fini
jmpq *-48(%rsp) # entry
error:
.ascii "_start: internal error.\n"
#timespec:
# .quad 10
# .quad 10
# Local Variables:
# asm-comment-char: ?#
# End:
|