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. */
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;
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. */
.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
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
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:
.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
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
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
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
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: ?@
# 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
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
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
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
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 copy_auxv
+1: movl -40(%ebp), %esi
+ movl %esi, -4(%ecx)
+ jmp copy_auxv
+2: movl -32(%ebp), %esi
movl %esi, -4(%ecx)
- jmp .one_auxv
-.replace_phent:
- movl 12(%ebp), %esi
+ jmp copy_auxv
+3: movl -36(%ebp), %esi
movl %esi, -4(%ecx)
- jmp .one_auxv
-.replace_phnum:
- movl 16(%ebp), %esi
+ jmp copy_auxv
+4: movl -28(%ebp), %esi
movl %esi, -4(%ecx)
- jmp .one_auxv
-.replace_entry:
- movl 8(%ebp), %esi
+ jmp copy_auxv
+5: movl -44(%ebp), %esi
movl %esi, -4(%ecx)
- jmp .one_auxv
-.replace_base:
- movl 24(%ebp), %esi
+ jmp copy_auxv
+6: movl -4(%ebp), %esi # Note: the filename is yet to be copied.
movl %esi, -4(%ecx)
- jmp .one_auxv
-.cleanup:
+ 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:
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
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
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
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:
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;