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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
|
# Copyright (C) 2023-2025 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/>.
/* Sorry! This program is a hopeless shambles in consequence of
being hastily written in under twenty minutes with minimal testing. */
.section .text
.global _start
_start:
## movl $162, %eax # SYS_nanosleep
## leal timespec, %ebx
## xorl %ecx, %ecx
## int $0x80
leal 8(%esp), %ebp # ebp = start of load area
subl $8, %esp # (%esp) = primary fd, 4(%esp) = secondary fd
movl $-1, 4(%esp)
next_action:
movl (%ebp), %edx # edx = action number
andl $-17, %edx
cmpl $0, %edx # open file?
je open_file
cmpl $3, %edx # jump?
je rest_of_exec
cmpl $4, %edx # anonymous mmap?
je do_mmap_anon
do_mmap:
subl $24, %esp
movl $90, %eax # SYS_old_mmap
movl %esp, %ebx
movl 4(%ebp), %ecx # address
movl %ecx, (%esp)
movl 16(%ebp), %ecx # length
movl %ecx, 4(%esp)
movl 12(%ebp), %ecx # protection
movl %ecx, 8(%esp)
movl 20(%ebp), %ecx # flags
movl %ecx, 12(%esp)
testl $16, (%ebp) # primary?
movl 28(%esp), %ecx
cmovzl 24(%esp), %ecx
movl %ecx, 16(%esp) # fd
movl 8(%ebp), %ecx # offset
movl %ecx, 20(%esp)
do_mmap_1:
int $0x80
addl $24, %esp # restore esp
cmpl $-1, %eax # mmap failed?
je perror
movl 24(%ebp), %ecx # clear
testl %ecx, %ecx
jz continue
movl 4(%ebp), %esi # start of mapping
addl 16(%ebp), %esi # end of mapping
subl %ecx, %esi # start of clear area
again:
testl %ecx, %ecx
jz continue
subl $1, %ecx
movb $0, (%esi, %ecx, 1)
jmp again
continue:
leal 28(%ebp), %ebp
jmp next_action
do_mmap_anon:
subl $24, %esp
movl $90, %eax # SYS_old_mmap
movl %esp, %ebx
movl 4(%ebp), %ecx # address
movl %ecx, (%esp)
movl 16(%ebp), %ecx # length
movl %ecx, 4(%esp)
movl 12(%ebp), %ecx # protection
movl %ecx, 8(%esp)
movl 20(%ebp), %ecx # flags
movl %ecx, 12(%esp)
movl $-1, 16(%esp) # fd
movl 8(%ebp), %ecx # offset
movl %ecx, 20(%esp)
jmp do_mmap_1
open_file:
movl $5, %eax # SYS_open
leal 4(%ebp), %ebx # ebx = %esp + 8
pushl %ebx
xorl %ecx, %ecx # flags = O_RDONLY
xorl %edx, %edx # mode = 0
int $0x80
cmpl $-1, %eax # open failed?
jle perror
movl %ebp, %esi # (esi) = original action number
popl %ebp # ebp = start of string
movl %ebp, %ecx # char past separator
decl %ebp
nextc:
incl %ebp
movb (%ebp), %dl # dl = *ebp
cmpb $47, %dl # dl == '\?'?
jne nextc1
leal 1(%ebp), %ecx # ecx = char past separator
nextc1:
cmpb $0, %dl # dl == 0?
jne nextc
addl $4, %ebp # adjust past ebp prior to rounding
andl $-4, %ebp # round ebp up to the next long
testl $16, (%esi) # original action number & 16?
jz primary
movl %eax, 4(%esp) # secondary fd = eax
jmp next_action
primary:
pushl %ebp
xorl %esi, %esi # arg3
movl %eax, 4(%esp) # primary fd = eax
xorl %edx, %edx # arg2
movl $15, %ebx # PR_SET_NAME, arg1 = ecx
xorl %edi, %edi # arg4
movl $172, %eax # SYS_prctl
xorl %ebp, %ebp # arg5
int $0x80 # syscall
popl %ebp
jmp next_action
perror:
movl %eax, %ebx
negl %ebx
movl $1, %eax
int $0x80
rest_of_exec:
movl 8(%esp), %ecx # ecx = original stack pointer
movl (%ecx), %esi # esi = argc
leal 8(%ecx, %esi, 4), %ecx # ecx = start of environ
movl (%esp), %eax # %eax = primary fd
movl 4(%esp), %edi # %edi = secondary fd
skip_environ:
movl (%ecx), %esi # envp[N]
addl $4, %ecx
testl %esi, %esi # envp[n] ?
jnz skip_environ # otherwise, ecx is now at the end of auxv
1: testl $-1, (%ecx) # auxv type
leal 8(%ecx), %ecx # skip to next auxv
jnz 1b # otherwise copy auxv
movl %ecx, %edx # end of auxv
/* Prepare sufficient space for the new executable name at the
start of the auxiliary vector. */
1: leal 32(%ebp), %esi # file name
/* 28(%ebp) = file name length. */
subl 28(%ebp), %ecx # destination of file name
decl %ecx
/* This is still 16 bytes on i386--see arch_align_stack:
https://android.googlesource.com/kernel/goldfish/+/refs/heads
/android-goldfish-3.10/arch/x86/kernel/process.c#446. */
andl $-16, %ecx # align stack
/* Prepare to store the auxiliary, environment, and argument
vectors. */
subl 8(%esp), %edx # end of auxv to start of stack
negl %edx
andl $-16, %edx # align value
movl %ecx, (%ebp) # temporarily save ecx
addl %edx, %ecx # %ecx = new position of argc
/* Allocate a temporary stack away from any crucial data in which
to store parameters and temporaries. */
cmpl %ecx, %ebp # select position of temporary stack
movl %ecx, %ebx # ebx = temporary stack
jge 1f # %ebx = MIN (%ecx, %edx)
movl %ebp, %ebx # ebx = temporary stack
1: movl (%ebp), %edx # edx = destination of file name
movl %edx, -4(%ebx) # -4(%ebx) = destination of file name
movl 28(%ebp), %edx # file name length
movl %edx, -8(%ebx) # -8(%ebx) = file name length
movl %ecx, -12(%ebx) # -12(%ebx) = new position of argc
movl %esi, -16(%ebx) # -16(%ebx) = file name
movl 8(%esp), %edx # %edx = initial stack pointer
leal -16(%ebx), %esp # switch to temporary stack
/* Push parameters of `struct exec_jump_command'. */
push %edx # initial stack pointer -20(%ebx)
push 4(%ebp) # entry -24(%ebx)
push 8(%ebp) # at_entry -28(%ebx)
push 12(%ebp) # at_phent -32(%ebx)
push 16(%ebp) # at_phnum -36(%ebx)
push 20(%ebp) # at_phdr -40(%ebx)
push 24(%ebp) # at_base -44(%ebx)
/* Push primary and secondary fds. */
push %eax # primary fd -48(%ebx)
push %edi # secondary fd -52(%ebx)
/* Swap %ebp with %ebx. */
push %ebp
push %ebx
pop %ebp
pop %ebx # ebx is the exec_jump_command
/* Save the string lest it should be overwritten while
the environment is moved. */
movl -8(%ebp), %ecx
subl $4, %esp # -56(%ebp)
subl %ecx, %esp
leal -1(%esp), %edi
movl %edi, -56(%ebp) # copy of string
incl %ecx
movl %edi, %esp
cld
rep movsb # complete copy
andl $-4, %esp # align stack
movl -12(%ebp), %ecx
/* Begin moving the argument vectors and environment from
the original SP to the adjusted one. */
1: movl (%edx), %eax # argc and values
movl %eax, (%ecx)
leal 4(%ecx), %ecx
leal 4(%edx), %edx
testl %eax, %eax
jnz 1b
1: movl (%edx), %eax # envp
movl %eax, (%ecx)
leal 4(%ecx), %ecx
leal 4(%edx), %edx
testl %eax, %eax
jnz 1b
copy_auxv:
movl (%edx), %eax # a_type
movl 4(%edx), %esi # a_un.a_val
testl %eax, %eax
leal 8(%edx), %edx
movl %eax, (%ecx) # copy auxv type
leal 8(%ecx), %ecx
jz cleanup # AT_NULL
cmpl $3, %eax # AT_PHDR
jz 1f
cmpl $4, %eax # AT_PHENT
jz 2f
cmpl $5, %eax # AT_PHNUM
jz 3f
cmpl $9, %eax # AT_ENTRY
jz 4f
cmpl $7, %eax # AT_BASE
jz 5f
cmpl $31, %eax # AT_EXECFN
jz 6f
movl %esi, -4(%ecx)
jmp copy_auxv
1: movl -40(%ebp), %esi
movl %esi, -4(%ecx)
jmp copy_auxv
2: movl -32(%ebp), %esi
movl %esi, -4(%ecx)
jmp copy_auxv
3: movl -36(%ebp), %esi
movl %esi, -4(%ecx)
jmp copy_auxv
4: movl -28(%ebp), %esi
movl %esi, -4(%ecx)
jmp copy_auxv
5: movl -44(%ebp), %esi
movl %esi, -4(%ecx)
jmp copy_auxv
6: movl -4(%ebp), %esi # Note: the filename is yet to be copied.
movl %esi, -4(%ecx)
jmp copy_auxv
cleanup:
movl $0, -4(%ecx) # AT_NULL value
/* Copy data for AT_EXECFN to the destination address. */
movl -4(%ebp), %edi
movl -56(%ebp), %esi
movl -8(%ebp), %ecx
incl %ecx
rep movsb
movl $6, %eax # SYS_close
cmpl $-1, -52(%ebp) # see if interpreter fd is set
je cleanup_1
movl -52(%ebp), %ebx
int $0x80
movl $6, %eax # SYS_close
cleanup_1:
movl -48(%ebp), %ebx
int $0x80
enter:
pushl $0
popfl # restore floating point state
movl -12(%ebp), %esp # restore initial stack pointer
xorl %edx, %edx # clear rtld_fini
jmpl *-24(%ebp) # entry
## timespec:
## .long 10
## .long 10
# Local Variables:
# asm-comment-char: ?#
# End:
|