Replace AT_EXECFN in auxiliary vectors of programs executed on Android

* exec/exec.c (insert_args, exec_0): On non-MIPS systems, copy
NAME and its length to the loader area.  State that MIPS support
is not yet available (though it will be pending the availability
of a functioning emulator).

* exec/loader-aarch64.s (_start):

* exec/loader-armeabi.s (_start):

* exec/loader-x86.s (_start):

* exec/loader-x86_64.s (_start): Displace auxv, environ, and
argv to create sufficient space for the provided file name, and
copy the file name there.  Replace AT_EXECFN to refer to this
space.
This commit is contained in:
Po Lu 2025-04-13 18:50:59 +08:00
parent f5b59a8a73
commit 7a01350624
6 changed files with 636 additions and 325 deletions

View file

@ -831,7 +831,7 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs,
assert (new3 == new + effective_size);
/* And that it is properly aligned. */
assert (!(new3 & (sizeof new3 - 2)));
assert (!(new3 & (sizeof new3 - 1)));
/* Now modify the system call argument to point to new +
text_size. */
@ -916,6 +916,9 @@ exec_0 (char *name, struct exec_tracee *tracee,
program_header program;
USER_WORD entry, program_entry, offset;
USER_WORD header_offset;
#ifndef __mips__
USER_WORD name_len, aligned_len;
#endif /* !__mips__ */
struct exec_jump_command jump;
#if defined __mips__ && !defined MIPS_NABI
int fpu_mode;
@ -1146,6 +1149,26 @@ exec_0 (char *name, struct exec_tracee *tracee,
sizeof jump);
loader_area_used += sizeof jump;
/* TODO: MIPS support. */
#ifndef __mips__
/* Copy the length of NAME and NAME itself to the loader area. */
name_len = strlen (name);
aligned_len = ((name_len + 1 + sizeof name_len - 1)
& -sizeof name_len);
if (sizeof loader_area - loader_area_used
< aligned_len + sizeof name_len)
goto fail1;
memcpy (loader_area + loader_area_used, &name_len, sizeof name_len);
loader_area_used += sizeof name_len;
memcpy (loader_area + loader_area_used, name, name_len + 1);
loader_area_used += name_len + 1;
/* Properly align the loader area. */
offset = aligned_len - (name_len + 1);
while (offset--)
loader_area[loader_area_used++] = '\0';
#endif /* !__mips__ */
/* Close the file descriptor and return the number of bytes
used. */

View file

@ -22,68 +22,68 @@
.section .text
.global _start
_start:
//mov x8, 101 // SYS_nanosleep
//adr x0, timespec // req
//mov x1, #0 // rem
//svc #0 // syscall
// 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:
next_action:
ldr x11, [x20] // action number
and x12, x11, #-17 // actual action number
cbz x12, .open_file // open file?
cbz x12, open_file // open file?
cmp x12, #3 // jump?
beq .rest_of_exec
beq rest_of_exec
cmp x12, #4 // anonymous mmap?
beq .do_mmap_anon
.do_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
beq do_mmap_1
mov x4, x28 // secondary fd
.do_mmap_1:
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
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:
fill64:
sub x2, x1, x3 // x2 = x1 - x3
cmp x2, #63 // x2 >= 64?
ble .fillb // start filling bytes
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:
b fill64
fillb:
cmp x1, x3 // x1 == x3?
beq .continue // done
beq continue // done
strb w0, [x3], #1 // ((char *) x3)++ = 0
b .fillb
.continue:
b fillb
continue:
add x20, x20, #56 // next action
b .next_action
.do_mmap_anon:
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:
b do_mmap_1
open_file:
mov x8, #56 // SYS_openat
mov x0, #-100 // AT_FDCWD
add x1, x20, #8 // file name
@ -91,19 +91,19 @@ _start:
mov x3, #0 // mode
svc #0 // syscall
cmp x0, #-1 // rc < 0?
ble .perror
ble perror
mov x19, x1 // x19 == x1
.nextc:
nextc:
ldrb w2, [x1], #1 // b = *x1++
cmp w2, #47 // dir separator?
bne .nextc1 // not dir separator
bne nextc1 // not dir separator
mov x19, x1 // x19 = char past separator
.nextc1:
cbnz w2, .nextc // b?
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
bne secondary // secondary fd
mov x29, x0 // primary fd
mov x8, #167 // SYS_prctl
mov x0, #15 // PR_SET_NAME
@ -113,75 +113,117 @@ _start:
mov x4, #0 // arg4
mov x5, #0 // arg5
svc #0 // syscall
b .next_action // next action
.secondary:
b next_action // next action
secondary:
mov x28, x0 // secondary fd
b .next_action // next action.
.perror:
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:
rest_of_exec:
mov x7, x20 // x7 = x20
mov x20, x10 // x20 = x10
ldr x9, [x20] // argc
add x9, x9, #2 // x9 += 2
mov x8, x10 // x8 = x10
ldr x9, [x8], #16 // (void *) x8 += 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
add x8, x8, x9 // now past argv
skip_environ:
ldr x9, [x8], #8 // x9 = *envp++
cbnz x9, skip_environ // x9?
// Skip the auxiliary vector.
1: ldp x11, x12, [x8], #16 // a_type, a_un.a_val
cbnz x11, 1b // a_type != NULL
// Prepare sufficient space at x20 for the file name string.
// Load the aforesaid string, and its length.
ldr x6, [x7, 56] // string length
add x6, x6, 1
add x5, x7, 64 // string pointer
sub x4, x10, x8 // number of elements to copy
sub x7, x8, x6 // AT_EXECFN location
and x7, x7, -8 // align value
add x4, x7, x4 // destination argc
and x4, x4, -16 // align destination argc
// Load values that must be into registers x14-x19.
// x14 = cmd->entry
// x15 = cmd->at_entry
// x16 = cmd->at_phent
// x17 = cmd->at_phnum
// x18 = cmd->at_phdr
// x19 = cmd->at_base
ldp x14, x15, [x20, 8]
ldp x16, x17, [x20, 24]
ldp x18, x19, [x20, 40]
// Move the string to a safe location, if necessary.
sub x3, x4, x5 // distance from dest to string
cmp x3, x6 // distance > length
bge copy_env_and_args // not necessary
mov x2, x5 // src
sub x5, x4, x6 // backup string
mov x1, x5 // dst
add x9, x2, x6 // src end
cmp x2, x9
bcs copy_env_and_args
1: ldrb w3, [x2], #1
strb w3, [x1], #1
cmp x2, x9
bls 1b
copy_env_and_args:
// Copy argc and the environment array.
mov x8, x10
mov x10, x4
1: ldr x9, [x8], #8 // envp
str x9, [x4], #8
cbnz x9, 1b
1: ldr x9, [x8], #8 // environ
str x9, [x4], #8
cbnz x9, 1b
copy_auxv:
ldp x11, x12, [x8], #16 // a_type, a_un.a_val
stp x11, x12, [x4], #16 // write value
cbz x11, cleanup // AT_NULL
cmp x11, #3 // AT_PHDR
csel x12, x18, x12, eq
cmp x11, #4 // AT_PHENT
csel x12, x16, x12, eq
cmp x11, #5 // AT_PHNUM
csel x12, x17, x12, eq
cmp x11, #9 // AT_ENTRY
csel x12, x15, x12, eq
cmp x11, #7 // AT_BASE
csel x12, x19, x12, eq
cmp x11, #31 // AT_EXECFN
csel x12, x7, x12, eq
str x12, [x4, -8] // replace value
b copy_auxv
cleanup:
// Copy the filename.
add x9, x5, x6 // end
cmp x5, x9
bcs 2f
1: ldrb w3, [x5], #1
strb w3, [x7], #1
cmp x5, x9
bls 1b
// Close file descriptors.
2: cmp x28, #-1 // is secondary fd set?
beq cleanup1 // not set
mov x8, #57 // SYS_close
mov x0, x28 // secondary fd
svc #0 // syscall
.cleanup1:
cleanup1:
mov x8, #57 // SYS_close
mov x0, x29 // primary fd
svc #0 // syscall
.enter:
enter:
mov sp, x10 // restore original SP
mov x0, #0 // clear rtld_fini
ldr x1, [x7, 8] // branch to code
br x1
br x14
timespec:
.quad 10
.quad 10
// timespec:
// .quad 10
// .quad 10
// Local Variables:
// asm-comment-char: ?/
// End:

View file

@ -18,23 +18,23 @@
.section .text
.global _start
_start:
@mov r7, #162 @ SYS_nanosleep
@adr r0, timespec @ req
@mov r1, #0 @ rem
@swi #0 @ syscall
@@ mov r7, #162 @ SYS_nanosleep
@@ adr r0, timespec @ req
@@ mov r1, #0 @ rem
@@ swi #0 @ syscall
mov r8, sp @ r8 = sp
ldr r9, [r8], #8 @ r9 = original sp, r8 += 8
mov r14, #-1 @ r14 = secondary fd
.next_action:
next_action:
ldr r11, [r8] @ r11 = action number
and r12, r11, #-17 @ actual action number
cmp r12, #0 @ open file?
beq .open_file @ open file.
beq open_file @ open file.
cmp r12, #3 @ jump?
beq .rest_of_exec @ jump to code.
beq rest_of_exec @ jump to code.
cmp r12, #4 @ anonymous mmap?
beq .do_mmap_anon @ anonymous mmap.
.do_mmap:
beq do_mmap_anon @ anonymous mmap.
do_mmap:
add r6, r8, #4 @ r6 = r8 + 4
ldm r6!, {r0, r5} @ vm_address, file_offset
ldm r6!, {r1, r2} @ protection, length
@ -45,28 +45,28 @@ _start:
ldm r6!, {r3, r12} @ flags, clear
tst r11, #16 @ primary fd?
mov r4, r10 @ primary fd
beq .do_mmap_1
beq do_mmap_1
mov r4, r14 @ secondary fd
.do_mmap_1:
do_mmap_1:
mov r7, #192 @ SYS_mmap2
swi #0 @ syscall
ldr r2, [r8, #4] @ vm_address
cmp r2, r0 @ rc == vm_address?
bne .perror
bne perror
add r0, r1, r2 @ r0 = length + vm_address
sub r3, r0, r12 @ r3 = r0 - clear
mov r1, #0 @ r1 = 0
.align:
align:
cmp r0, r3 @ r0 == r3?
beq .continue @ continue
beq continue @ continue
tst r3, #3 @ r3 & 3?
bne .fill32 @ fill aligned
bne fill32 @ fill aligned
strb r1, [r3], #1 @ fill byte
b .align @ align again
.fill32:
b align @ align again
fill32:
sub r2, r0, r3 @ r2 = r0 - r3
cmp r2, #31 @ r2 >= 32?
ble .fillb @ start filling bytes
ble fillb @ start filling bytes
str r1, [r3], #4 @ *r3++ = 0
str r1, [r3], #4 @ *r3++ = 0
str r1, [r3], #4 @ *r3++ = 0
@ -75,16 +75,16 @@ _start:
str r1, [r3], #4 @ *r3++ = 0
str r1, [r3], #4 @ *r3++ = 0
str r1, [r3], #4 @ *r3++ = 0
b .fill32
.fillb:
b fill32
fillb:
cmp r0, r3 @ r0 == r3
beq .continue @ done
beq continue @ done
strb r1, [r3], #1 @ ((char *) r3)++ = 0
b .fillb
.continue:
b fillb
continue:
add r8, r8, #28 @ next action
b .next_action
.do_mmap_anon:
b next_action
do_mmap_anon:
add r6, r8, #4 @ r6 = r8 + 4
ldm r6!, {r0, r5} @ vm_address, file_offset
ldm r6!, {r1, r2} @ protection, length
@ -94,29 +94,29 @@ _start:
mov r2, r3 @ swap
ldm r6!, {r3, r12} @ flags, clear
mov r4, #-1 @ fd
b .do_mmap_1
.open_file:
b do_mmap_1
open_file:
mov r7, #5 @ SYS_open
add r0, r8, #4 @ file name
mov r1, #0 @ O_RDONLY
mov r2, #0 @ mode
swi #0 @ syscall
cmp r0, #-1 @ r0 <= -1?
ble .perror
ble perror
add r8, r8, #4 @ r8 = start of string
mov r1, r8 @ r1 = r8
.nextc:
nextc:
ldrb r2, [r8], #1 @ b = *r0++
cmp r2, #47 @ dir separator?
bne .nextc1 @ not dir separator
bne nextc1 @ not dir separator
mov r1, r8 @ r1 = char past separator
.nextc1:
nextc1:
cmp r2, #0 @ b?
bne .nextc @ next character
bne nextc @ next character
add r8, r8, #3 @ round up r8
and r8, r8, #-4 @ mask for round, set r8
tst r11, #16 @ primary fd?
bne .secondary @ secondary fd
bne secondary @ secondary fd
mov r10, r0 @ primary fd
mov r7, #172 @ SYS_prctl
mov r0, #15 @ PR_SET_NAME, r1 = name
@ -125,79 +125,139 @@ _start:
mov r4, #0 @ arg4
mov r5, #0 @ arg5
swi #0 @ syscall
b .next_action @ next action
.secondary:
b next_action @ next action
secondary:
mov r14, r0 @ secondary fd
b .next_action @ next action
.perror:
b next_action @ next action
perror:
mov r7, #1 @ SYS_exit
mvn r0, r0 @ r0 = ~r0
add r0, r0, #1 @ r0 += 1
swi #0
.rest_of_exec:
rest_of_exec: @ r8 points to seven ints + string
mov r7, r9 @ r7 = original SP
ldr r6, [r7] @ argc
add r6, r6, #2 @ argc + 2
ldr r6, [r7], #8 @ argc & terminator
lsl r6, r6, #2 @ argc *= 4
add r7, r7, r6 @ now past argv
.skipenv:
ldr r6, [r7], #4 @ r6 = *r7++
cmp r6, #0 @ r6?
bne .skipenv @ r6?
.one_auxv:
ldr r6, [r7], #8 @ r6 = *r7, r7 += 2
cmp r6, #0 @ !r6?
beq .cleanup @ r6?
cmp r6, #3 @ is AT_PHDR?
beq .replace_phdr @ replace
cmp r6, #4 @ is AT_PHENT?
beq .replace_phent @ replace
cmp r6, #5 @ is AT_PHNUM?
beq .replace_phnum @ replace
cmp r6, #9 @ is AT_ENTRY?
beq .replace_entry @ replace
cmp r6, #7 @ is AT_BASE?
beq .replace_base @ replace
b .one_auxv @ next auxv
.replace_phdr:
ldr r6, [r8, #20] @ at_phdr
str r6, [r7, #-4] @ store value
b .one_auxv
.replace_phent:
ldr r6, [r8, #12] @ at_phent
str r6, [r7, #-4] @ store value
b .one_auxv
.replace_phnum:
ldr r6, [r8, #16] @ at_phnum
str r6, [r7, #-4] @ store value
b .one_auxv
.replace_entry:
ldr r6, [r8, #8] @ at_entry
str r6, [r7, #-4] @ store value
b .one_auxv
.replace_base:
ldr r6, [r8, #24] @ at_base
str r6, [r7, #-4] @ store value
b .one_auxv
.cleanup:
ldr r6, [r8, #28] @ length of string
add r6, r6, #1
skip_environ:
1: ldr r1, [r7], #4 @ r1 = *r7++
tst r1, r1 @ r1
bne 1b @ r1
1: ldm r7!, {r0, r1} @ a_type, a_un.a_val
tst r0, r0
bne 1b @ a_type -> 1b
@@ Establish the number of bytes in the argument, environment,
@@ and auxiliary vectors to be moved.
sub r5, r7, r9 @ r5 = bytes in vectors
@@ Expand r7 with sufficient space for the filename and align
@@ it.
sub r4, r7, r5
and r4, r4, #-8 @ r4 = address of AT_EXECFN
sub r3, r4, r5 @ r4 - number of bytes in vectors
and r3, r3, #-16 @ r3 = position of new argc
@@ Reserve an area that is guaranteed not to be clobbered into
@@ which to copy the command and file name.
mov r2, r3
cmp r2, r8
blo 1f
mov r2, r8
1: sub r2, r2, #24 @ space for data
@@ [r2, #0] = entry
@@ [r2, #4] = at_entry
@@ [r2, #8] = at_phent
@@ [r2, #12] = at_phnum
@@ [r2, #16] = at_phdr
@@ [r2, #20] = at_base
add r7, r8, #4 @ &cmd->entry
ldm r7!, {r0, r1}
stm r2!, {r0, r1}
ldm r7!, {r0, r1}
stm r2!, {r0, r1}
ldm r7!, {r0, r1}
stm r2!, {r0, r1}
sub r2, r2, #24
sub r0, r2, r6 @ r0 = copy of AT_EXECFN
add r1, r8, #32 @ src
add r5, r1, r6 @ src end
cmp r1, r5
bcs copy_env_and_args
1: ldrb r7, [r1], #1
strb r7, [r0], #1
cmp r1, r5
blo 1b
copy_env_and_args:
mov r5, r3
1: ldr r0, [r9], #4 @ argc and arguments
str r0, [r5], #4 @ *dst = ...
tst r0, r0
bne 1b
1: ldr r0, [r9], #4 @ environment string
str r0, [r5], #4 @ *dst = ...
tst r0, r0
bne 1b
copy_auxv:
ldm r9!, {r0, r1} @ a_type, a_un.a_val
tst r0, r0 @ AT_NULL
beq 8f
cmp r0, #3 @ AT_PHDR
beq 2f
cmp r0, #4 @ AT_PHENT
beq 3f
cmp r0, #5 @ AT_PHNUM
beq 4f
cmp r0, #9 @ AT_ENTRY
beq 5f
cmp r0, #7 @ AT_BASE
beq 6f
cmp r0, #31 @ AT_EXECFN
beq 7f
1: stm r5!, {r0, r1}
b copy_auxv
2: ldr r1, [r2, #16]
b 1b
3: ldr r1, [r2, #8]
b 1b
4: ldr r1, [r2, #12]
b 1b
5: ldr r1, [r2, #4]
b 1b
6: ldr r1, [r2, #20]
b 1b
7: mov r1, r4
b 1b
8:
stm r5!, {r0, r1}
cleanup:
@@ Copy the filename.
sub r0, r2, r6 @ src
add r1, r0, r6 @ src end
cmp r0, r1
bcs 2f
1: ldrb r5, [r0], #1
strb r5, [r4], #1 @ *dst++
cmp r0, r1
blo 1b
2: mov r9, r3 @ replace original SP
cmp r14, #-1 @ secondary fd set?
bne .cleanup1 @ not set
beq cleanup1 @ not set
mov r7, #6 @ SYS_close
mov r0, r14 @ secondary fd
swi #0 @ syscall
.cleanup1:
cleanup1:
mov r7, #6 @ SYS_close
mov r0, r10 @ primary fd
swi #0 @ syscall
.enter:
enter:
mov sp, r9 @ restore original SP
mov r0, #0 @ clear rtld_fini
ldr r1, [r8, #4] @ branch to code
ldr r1, [r2] @ branch to code
bx r1
timespec:
.long 10
.long 10
@@ timespec:
@@ .long 10
@@ .long 10
@ Local Variables:
@ asm-comment-char: ?@

View file

@ -15,26 +15,29 @@
# 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
## 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:
next_action:
movl (%ebp), %edx # edx = action number
andl $-17, %edx
cmpl $0, %edx # open file?
je .open_file
je open_file
cmpl $3, %edx # jump?
je .rest_of_exec
je rest_of_exec
cmpl $4, %edx # anonymous mmap?
je .do_mmap_anon
.do_mmap:
je do_mmap_anon
do_mmap:
subl $24, %esp
movl $90, %eax # SYS_old_mmap
movl %esp, %ebx
@ -52,27 +55,27 @@ _start:
movl %ecx, 16(%esp) # fd
movl 8(%ebp), %ecx # offset
movl %ecx, 20(%esp)
.do_mmap_1:
do_mmap_1:
int $0x80
addl $24, %esp # restore esp
cmpl $-1, %eax # mmap failed?
je .perror
je perror
movl 24(%ebp), %ecx # clear
testl %ecx, %ecx
jz .continue
jz continue
movl 4(%ebp), %esi # start of mapping
addl 16(%ebp), %esi # end of mapping
subl %ecx, %esi # start of clear area
.again:
again:
testl %ecx, %ecx
jz .continue
jz continue
subl $1, %ecx
movb $0, (%esi, %ecx, 1)
jmp .again
.continue:
jmp again
continue:
leal 28(%ebp), %ebp
jmp .next_action
.do_mmap_anon:
jmp next_action
do_mmap_anon:
subl $24, %esp
movl $90, %eax # SYS_old_mmap
movl %esp, %ebx
@ -87,8 +90,8 @@ _start:
movl $-1, 16(%esp) # fd
movl 8(%ebp), %ecx # offset
movl %ecx, 20(%esp)
jmp .do_mmap_1
.open_file:
jmp do_mmap_1
open_file:
movl $5, %eax # SYS_open
leal 4(%ebp), %ebx # ebx = %esp + 8
pushl %ebx
@ -96,27 +99,27 @@ _start:
xorl %edx, %edx # mode = 0
int $0x80
cmpl $-1, %eax # open failed?
jle .perror
jle perror
movl %ebp, %esi # (esi) = original action number
popl %ebp # ebp = start of string
movl %ebp, %ecx # char past separator
decl %ebp
.nextc:
nextc:
incl %ebp
movb (%ebp), %dl # dl = *ebp
cmpb $47, %dl # dl == '\?'?
jne .nextc1
jne nextc1
leal 1(%ebp), %ecx # ecx = char past separator
.nextc1:
nextc1:
cmpb $0, %dl # dl == 0?
jne .nextc
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
jz primary
movl %eax, 4(%esp) # secondary fd = eax
jmp .next_action
.primary:
jmp next_action
primary:
pushl %ebp
xorl %esi, %esi # arg3
movl %eax, 4(%esp) # primary fd = eax
@ -127,74 +130,168 @@ _start:
xorl %ebp, %ebp # arg5
int $0x80 # syscall
popl %ebp
jmp .next_action
.perror:
jmp next_action
perror:
movl %eax, %ebx
negl %ebx
movl $1, %eax
int $0x80
.rest_of_exec:
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
.skip_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, esi is now at the start of auxv
.one_auxv:
movl (%ecx), %esi # auxv type
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
testl %esi, %esi # is 0?
jz .cleanup
cmpl $3, %esi # is AT_PHDR
je .replace_phdr
cmpl $4, %esi # is AT_PHENT?
je .replace_phent
cmpl $5, %esi # is AT_PHNUM?
je .replace_phnum
cmpl $9, %esi # is AT_ENTRY?
je .replace_entry
cmpl $7, %esi # is AT_BASE
je .replace_base
jmp .one_auxv
.replace_phdr:
movl 20(%ebp), %esi
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 .one_auxv
.replace_phent:
movl 12(%ebp), %esi
jmp copy_auxv
1: movl -40(%ebp), %esi
movl %esi, -4(%ecx)
jmp .one_auxv
.replace_phnum:
movl 16(%ebp), %esi
jmp copy_auxv
2: movl -32(%ebp), %esi
movl %esi, -4(%ecx)
jmp .one_auxv
.replace_entry:
movl 8(%ebp), %esi
jmp copy_auxv
3: movl -36(%ebp), %esi
movl %esi, -4(%ecx)
jmp .one_auxv
.replace_base:
movl 24(%ebp), %esi
jmp copy_auxv
4: movl -28(%ebp), %esi
movl %esi, -4(%ecx)
jmp .one_auxv
.cleanup:
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, 4(%esp) # see if interpreter fd is set
je .cleanup_1
movl 4(%esp), %ebx
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 (%esp), %ebx
cleanup_1:
movl -48(%ebp), %ebx
int $0x80
.enter:
enter:
pushl $0
popfl # restore floating point state
movl 8(%esp), %esp # restore initial stack pointer
movl -12(%ebp), %esp # restore initial stack pointer
xorl %edx, %edx # clear rtld_fini
jmpl *4(%ebp) # entry
jmpl *-24(%ebp) # entry
## timespec:
## .long 10
## .long 10
timespec:
.long 10
.long 10
# Local Variables:
# asm-comment-char: ?#
# End:

View file

@ -25,17 +25,17 @@ _start:
popq %r13 # original SP
popq %r15 # size of load area.
movq $-1, %r12 # r12 is the interpreter fd
.next_action:
next_action:
movq (%rsp), %r14 # action number
movq %r14, %r15 # original action number
andq $-17, %r14
cmpq $0, %r14 # open file?
je .open_file
je open_file
cmpq $3, %r14 # jump?
je .rest_of_exec
je rest_of_exec
cmpq $4, %r14 # anonymous mmap?
je .do_mmap_anon
.do_mmap:
je do_mmap_anon
do_mmap:
movq $9, %rax # SYS_mmap
movq 8(%rsp), %rdi # address
movq 16(%rsp), %r9 # offset
@ -46,26 +46,26 @@ _start:
testq $16, %r15
movq %r12, %r8
cmovzq %rbx, %r8
.do_mmap_1:
do_mmap_1:
syscall
cmpq $-1, %rax # mmap failed
je .perror
je perror
movq 48(%rsp), %r9 # clear
testq %r9, %r9
jz .continue
jz continue
movq 8(%rsp), %r10 # start of mapping
addq 32(%rsp), %r10 # end of mapping
subq %r9, %r10 # start of clear area
.again:
again:
testq %r9, %r9
jz .continue
jz continue
subq $1, %r9
movb $0, (%r10, %r9, 1)
jmp .again
.continue:
jmp again
continue:
leaq 56(%rsp), %rsp
jmp .next_action
.do_mmap_anon:
jmp next_action
do_mmap_anon:
movq $9, %rax # SYS_mmap
movq 8(%rsp), %rdi # address
movq 16(%rsp), %r9 # offset
@ -73,35 +73,35 @@ _start:
movq 32(%rsp), %rsi # length
movq 40(%rsp), %r10 # flags
movq $-1, %r8 # -1
jmp .do_mmap_1
.open_file:
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
jle perror
movq %rdi, %rsp # rsp = start of string
subq $1, %rsp
movq %rsp, %r14 # r14 = start of string
.nextc:
nextc:
addq $1, %rsp
movb (%rsp), %dil # rdi = *rsp
cmpb $47, %dil # *rsp == '/'?
jne .nextc1
jne nextc1
movq %rsp, %r14 # r14 = rsp
addq $1, %r14 # r14 = char past separator
.nextc1:
nextc1:
cmpb $0, %dil # *rsp == 0?
jne .nextc
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
jz primary
movq %rax, %r12 # otherwise, move fd to r12
jmp .next_action
.primary:
jmp next_action
primary:
movq %rax, %rbx # if not, move fd to rbx
movq $157, %rax # SYS_prctl
movq $15, %rdi # PR_SET_NAME
@ -111,82 +111,159 @@ _start:
xorq %r8, %r8 # arg4
xorq %r9, %r9 # arg5
syscall
jmp .next_action
.perror:
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 $23, %rdx # count
movq $24, %rdx # count
syscall
movq $60, %rax # SYS_exit
movq %r12, %rdi # code
syscall
.rest_of_exec: # rsp now points to six quads:
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 %r10 # envp[N]
testq %r10, %r10 # envp[n]?
jnz .skip_environ # otherwise, rsp is now at the start of auxv
.one_auxv:
popq %rcx # auxv type
addq $8, %rsp # skip value
testq %rcx, %rcx # is 0?
jz .cleanup
cmpq $3, %rcx # is AT_PHDR?
je .replace_phdr
cmpq $4, %rcx # is AT_PHENT?
je .replace_phent
cmpq $5, %rcx # is AT_PHNUM?
je .replace_phnum
cmpq $9, %rcx # is AT_ENTRY?
je .replace_entry
cmpq $7, %rcx # is AT_BASE?
je .replace_base
jmp .one_auxv
.replace_phdr:
movq 40(%r8), %r9
movq %r9, -8(%rsp) # set at_phdr
jmp .one_auxv
.replace_phent:
movq 24(%r8), %r9
movq %r9, -8(%rsp) # set at_phent
jmp .one_auxv
.replace_phnum:
movq 32(%r8), %r9
movq %r9, -8(%rsp) # set at_phnum
jmp .one_auxv
.replace_entry:
movq 16(%r8), %r9
movq %r9, -8(%rsp) # set at_entry
jmp .one_auxv
.replace_base:
movq 48(%r8), %r9
movq %r9, -8(%rsp) # set at_base
jmp .one_auxv
.cleanup:
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. */
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
je cleanup_1
movq %r12, %rdi
syscall
movq $3, %rax # SYS_close
.cleanup_1:
cleanup_1:
movq %rbx, %rdi
syscall
.enter:
/* Enter the program. */
pushq $0
popfq # clear FP state
movq %r13, %rsp # restore SP
xorq %rdx, %rdx # clear rtld_fini
jmpq *8(%r8) # entry
jmpq *-48(%rsp) # entry
error:
.ascii "_start: internal error."
timespec:
.quad 10
.quad 10
.ascii "_start: internal error.\n"
#timespec:
# .quad 10
# .quad 10
# Local Variables:
# asm-comment-char: ?#
# End:

View file

@ -909,6 +909,18 @@ finish_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
tracee->pid, 0, 0))
goto error;
/* Enable this block to debug the executable loader. */
#if 0
{
int rc, wstatus;
again1:
rc = waitpid (tracee->pid, &wstatus, __WALL);
if (rc == -1 && errno == EINTR)
goto again1;
ptrace (PTRACE_DETACH, tracee->pid, 0, 0);
}
#endif /* 0 */
error:
free (tracee->exec_data);
tracee->exec_data = NULL;