From 7a01350624e1665e707f98e13d51f53e9f87ce95 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 13 Apr 2025 18:50:59 +0800 Subject: [PATCH] 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. --- exec/exec.c | 25 ++++- exec/loader-aarch64.s | 212 +++++++++++++++++++++--------------- exec/loader-armeabi.s | 234 ++++++++++++++++++++++++--------------- exec/loader-x86.s | 247 +++++++++++++++++++++++++++++------------- exec/loader-x86_64.s | 231 ++++++++++++++++++++++++++------------- exec/trace.c | 12 ++ 6 files changed, 636 insertions(+), 325 deletions(-) diff --git a/exec/exec.c b/exec/exec.c index b1c9825daff..7a8ef2c3a1a 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -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. */ diff --git a/exec/loader-aarch64.s b/exec/loader-aarch64.s index 686a804aa0e..64f95725eca 100644 --- a/exec/loader-aarch64.s +++ b/exec/loader-aarch64.s @@ -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: diff --git a/exec/loader-armeabi.s b/exec/loader-armeabi.s index 2aa52f3e006..572020bb573 100644 --- a/exec/loader-armeabi.s +++ b/exec/loader-armeabi.s @@ -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: ?@ diff --git a/exec/loader-x86.s b/exec/loader-x86.s index 5e5bb7253ab..d9cfa28f6a3 100644 --- a/exec/loader-x86.s +++ b/exec/loader-x86.s @@ -15,26 +15,29 @@ # You should have received a copy of the GNU General Public License # along with GNU Emacs. If not, see . +/* 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: diff --git a/exec/loader-x86_64.s b/exec/loader-x86_64.s index 0854df98db9..236f8d6670f 100644 --- a/exec/loader-x86_64.s +++ b/exec/loader-x86_64.s @@ -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: diff --git a/exec/trace.c b/exec/trace.c index ff67ed5d941..b0ec602d821 100644 --- a/exec/trace.c +++ b/exec/trace.c @@ -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;