diff options
| author | Po Lu | 2025-04-14 21:28:15 +0800 |
|---|---|---|
| committer | Po Lu | 2025-04-14 21:31:07 +0800 |
| commit | 74df372398dbc90f6c0185f1701af28129073de7 (patch) | |
| tree | 2ef25ec64d9d6845029801bef81422415b2d9ccf /exec | |
| parent | 4918de1699152e98c7aaa3ecb21795a3cbd05194 (diff) | |
| download | emacs-74df372398dbc90f6c0185f1701af28129073de7.tar.gz emacs-74df372398dbc90f6c0185f1701af28129073de7.zip | |
Port recent changes to mipsel systems
* exec/exec.c (exec_0): Don't disable AT_EXECFN substitution on
MIPS systems.
* exec/loader-aarch64.s (skip_environ): Correct typo in
commentary.
* exec/loader-mips64el.s: Add a disclaimer that this file is
currently inoperable.
* exec/loader-mipsel.s (__start): Move environment and argument
vectors and produce and replace AT_EXECFN. Clear stack before
proceeding to circumvent an oversight in glibc.
Diffstat (limited to 'exec')
| -rw-r--r-- | exec/config-mips.m4.in | 2 | ||||
| -rw-r--r-- | exec/exec.c | 13 | ||||
| -rw-r--r-- | exec/loader-aarch64.s | 2 | ||||
| -rw-r--r-- | exec/loader-mips64el.s | 2 | ||||
| -rw-r--r-- | exec/loader-mipsel.s | 306 |
5 files changed, 224 insertions, 101 deletions
diff --git a/exec/config-mips.m4.in b/exec/config-mips.m4.in index c42bbbad2ec..1c9a4c293a6 100644 --- a/exec/config-mips.m4.in +++ b/exec/config-mips.m4.in | |||
| @@ -18,6 +18,7 @@ dnl You should have received a copy of the GNU General Public License | |||
| 18 | dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | 18 | dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. |
| 19 | 19 | ||
| 20 | define(`SYSCALL_open', `ifelse(`@MIPS_N32@',`yes',`6002',`4005')') | 20 | define(`SYSCALL_open', `ifelse(`@MIPS_N32@',`yes',`6002',`4005')') |
| 21 | dnl define(`SYSCALL_openat', `ifelse(`@MIPS_N32@',`yes',`6251',`4288')') | ||
| 21 | define(`SYSCALL_close', `ifelse(`@MIPS_N32@',`yes',`6003',`4006')') | 22 | define(`SYSCALL_close', `ifelse(`@MIPS_N32@',`yes',`6003',`4006')') |
| 22 | define(`SYSCALL_mmap', `ifelse(`@MIPS_N32@',`yes',`6009',`4090')') | 23 | define(`SYSCALL_mmap', `ifelse(`@MIPS_N32@',`yes',`6009',`4090')') |
| 23 | define(`SYSCALL_nanosleep', `ifelse(`@MIPS_N32@',`yes',`6034',`4166')') | 24 | define(`SYSCALL_nanosleep', `ifelse(`@MIPS_N32@',`yes',`6034',`4166')') |
| @@ -34,6 +35,7 @@ define(`SYSCALL', `ifelse(`@MIPS_N32@',`yes',` move $a4, $1 | |||
| 34 | sw $4, 28($sp)')') | 35 | sw $4, 28($sp)')') |
| 35 | 36 | ||
| 36 | define(`RESTORE', `ifelse(`@MIPS_N32@',`yes',` nop',` addi $sp, 32')') | 37 | define(`RESTORE', `ifelse(`@MIPS_N32@',`yes',` nop',` addi $sp, 32')') |
| 38 | define(`FP', `ifelse(`@MIPS_N32@',`yes',`$s8',`$fp')') | ||
| 37 | 39 | ||
| 38 | dnl For mips64. Some assemblers don't want to assemble `daddi'. | 40 | dnl For mips64. Some assemblers don't want to assemble `daddi'. |
| 39 | define(`DADDI2', `ifelse(`@DADDI_BROKEN@',`yes',` li $at, $2 | 41 | define(`DADDI2', `ifelse(`@DADDI_BROKEN@',`yes',` li $at, $2 |
diff --git a/exec/exec.c b/exec/exec.c index 7a8ef2c3a1a..b9c3e4ec92a 100644 --- a/exec/exec.c +++ b/exec/exec.c | |||
| @@ -231,10 +231,10 @@ struct exec_jump_command | |||
| 231 | /* The value of AT_BASE inside the aux vector. */ | 231 | /* The value of AT_BASE inside the aux vector. */ |
| 232 | USER_WORD at_base; | 232 | USER_WORD at_base; |
| 233 | 233 | ||
| 234 | #if defined __mips__ && !defined MIPS_NABI | 234 | #if defined __mips__ |
| 235 | /* The FPU mode to apply. */ | 235 | /* The FPU mode to apply. Not used when !MIPS_NABI. */ |
| 236 | USER_WORD fpu_mode; | 236 | USER_WORD fpu_mode; |
| 237 | #endif /* defined __mips__ && !defined MIPS_NABI */ | 237 | #endif /* defined __mips__ */ |
| 238 | }; | 238 | }; |
| 239 | 239 | ||
| 240 | 240 | ||
| @@ -916,9 +916,7 @@ exec_0 (char *name, struct exec_tracee *tracee, | |||
| 916 | program_header program; | 916 | program_header program; |
| 917 | USER_WORD entry, program_entry, offset; | 917 | USER_WORD entry, program_entry, offset; |
| 918 | USER_WORD header_offset; | 918 | USER_WORD header_offset; |
| 919 | #ifndef __mips__ | ||
| 920 | USER_WORD name_len, aligned_len; | 919 | USER_WORD name_len, aligned_len; |
| 921 | #endif /* !__mips__ */ | ||
| 922 | struct exec_jump_command jump; | 920 | struct exec_jump_command jump; |
| 923 | #if defined __mips__ && !defined MIPS_NABI | 921 | #if defined __mips__ && !defined MIPS_NABI |
| 924 | int fpu_mode; | 922 | int fpu_mode; |
| @@ -1132,6 +1130,8 @@ exec_0 (char *name, struct exec_tracee *tracee, | |||
| 1132 | fpu_mode = FP_FRE; | 1130 | fpu_mode = FP_FRE; |
| 1133 | 1131 | ||
| 1134 | jump.fpu_mode = fpu_mode; | 1132 | jump.fpu_mode = fpu_mode; |
| 1133 | #elif defined __mips__ | ||
| 1134 | jump.fpu_mode = 0; | ||
| 1135 | #endif /* defined __mips__ && !defined MIPS_NABI */ | 1135 | #endif /* defined __mips__ && !defined MIPS_NABI */ |
| 1136 | 1136 | ||
| 1137 | /* The offset used for at_phdr should be that of the first | 1137 | /* The offset used for at_phdr should be that of the first |
| @@ -1149,8 +1149,6 @@ exec_0 (char *name, struct exec_tracee *tracee, | |||
| 1149 | sizeof jump); | 1149 | sizeof jump); |
| 1150 | loader_area_used += sizeof jump; | 1150 | loader_area_used += sizeof jump; |
| 1151 | 1151 | ||
| 1152 | /* TODO: MIPS support. */ | ||
| 1153 | #ifndef __mips__ | ||
| 1154 | /* Copy the length of NAME and NAME itself to the loader area. */ | 1152 | /* Copy the length of NAME and NAME itself to the loader area. */ |
| 1155 | name_len = strlen (name); | 1153 | name_len = strlen (name); |
| 1156 | aligned_len = ((name_len + 1 + sizeof name_len - 1) | 1154 | aligned_len = ((name_len + 1 + sizeof name_len - 1) |
| @@ -1167,7 +1165,6 @@ exec_0 (char *name, struct exec_tracee *tracee, | |||
| 1167 | offset = aligned_len - (name_len + 1); | 1165 | offset = aligned_len - (name_len + 1); |
| 1168 | while (offset--) | 1166 | while (offset--) |
| 1169 | loader_area[loader_area_used++] = '\0'; | 1167 | loader_area[loader_area_used++] = '\0'; |
| 1170 | #endif /* !__mips__ */ | ||
| 1171 | 1168 | ||
| 1172 | /* Close the file descriptor and return the number of bytes | 1169 | /* Close the file descriptor and return the number of bytes |
| 1173 | used. */ | 1170 | used. */ |
diff --git a/exec/loader-aarch64.s b/exec/loader-aarch64.s index 376f439417f..d3c565bf3f8 100644 --- a/exec/loader-aarch64.s +++ b/exec/loader-aarch64.s | |||
| @@ -144,7 +144,7 @@ skip_environ: | |||
| 144 | and x7, x7, -8 // align value | 144 | and x7, x7, -8 // align value |
| 145 | add x4, x7, x4 // destination argc | 145 | add x4, x7, x4 // destination argc |
| 146 | and x4, x4, -16 // align destination argc | 146 | and x4, x4, -16 // align destination argc |
| 147 | // Load values that must be into registers x14-x19. | 147 | // Load values that must be preserved into registers x14-x19. |
| 148 | // x14 = cmd->entry | 148 | // x14 = cmd->entry |
| 149 | // x15 = cmd->at_entry | 149 | // x15 = cmd->at_entry |
| 150 | // x16 = cmd->at_phent | 150 | // x16 = cmd->at_phent |
diff --git a/exec/loader-mips64el.s b/exec/loader-mips64el.s index 491b7ccfb60..1493af3c309 100644 --- a/exec/loader-mips64el.s +++ b/exec/loader-mips64el.s | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | # You should have received a copy of the GNU General Public License | 15 | # You should have received a copy of the GNU General Public License |
| 16 | # along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | 16 | # along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. |
| 17 | 17 | ||
| 18 | /* NOTE: this file is presently non-functional. */ | ||
| 19 | |||
| 18 | include(`config-mips.m4') | 20 | include(`config-mips.m4') |
| 19 | 21 | ||
| 20 | .set noreorder # delay slots managed by hand | 22 | .set noreorder # delay slots managed by hand |
diff --git a/exec/loader-mipsel.s b/exec/loader-mipsel.s index 9ffe7e928e7..bf90493e726 100644 --- a/exec/loader-mipsel.s +++ b/exec/loader-mipsel.s | |||
| @@ -15,34 +15,34 @@ | |||
| 15 | # You should have received a copy of the GNU General Public License | 15 | # You should have received a copy of the GNU General Public License |
| 16 | # along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | 16 | # along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. |
| 17 | 17 | ||
| 18 | include(`config-mips.m4') | 18 | include(`config-mips.m4') |
| 19 | 19 | ||
| 20 | # Make sure not to use t4 through t7, in order to maintain portability | 20 | ## Beware: $t0-$t4 alias the syscall (and function, but they are not |
| 21 | # with N32 ABI systems. | 21 | ## material in this context) argument registers on N32 systems, and |
| 22 | ## mustn't be relied upon to hold arguments to `SYSCALL'. | ||
| 22 | 23 | ||
| 23 | .set noreorder # delay slots managed by hand | 24 | .set noreorder # delay slots managed by hand |
| 24 | .section .text | 25 | .section .text |
| 25 | .global __start | 26 | .global __start |
| 26 | __start: | 27 | __start: |
| 27 | dnl li $v0, SYSCALL_nanosleep # SYS_nanosleep | 28 | ## li $v0, SYSCALL_nanosleep # SYS_nanosleep |
| 28 | dnl la $a0, .timespec # rqtp | 29 | ## la $a0, timespec # rqtp |
| 29 | dnl li $a1, 0 # rmtp | 30 | ## li $a1, 0 # rmtp |
| 30 | dnl syscall # syscall | 31 | ## syscall # syscall |
| 31 | lw $s6, ($sp) # original stack pointer | 32 | lw $s6, ($sp) # original stack pointer |
| 32 | addi $s0, $sp, 8 # start of load area | 33 | addi $s0, $sp, 8 # start of load area |
| 33 | addi $sp, -8 # primary fd, secondary fd | 34 | addi $sp, -8 # primary fd, secondary fd |
| 34 | li $t0, -1 # secondary fd | 35 | li $t0, -1 # secondary fd |
| 35 | sw $t0, 4($sp) # initialize secondary fd | 36 | sw $t0, 4($sp) # initialize secondary fd |
| 36 | .next_action: | 37 | next_action: |
| 37 | lw $s2, ($s0) # action number | 38 | lw $s2, ($s0) # action number |
| 38 | nop # delay slot | ||
| 39 | andi $t0, $s2, 15 # t0 = s2 & 15 | 39 | andi $t0, $s2, 15 # t0 = s2 & 15 |
| 40 | beqz $t0, .open_file # open file? | 40 | beqz $t0, open_file # open file? |
| 41 | li $t1, 3 # t1 = 3, delay slot | 41 | li $t1, 3 # t1 = 3, delay slot |
| 42 | beq $t0, $t1, .rest_of_exec # jump to code | 42 | beq $t0, $t1, rest_of_exec # jump to code |
| 43 | li $t1, 4 # t1 = 4, delay slot | 43 | li $t1, 4 # t1 = 4, delay slot |
| 44 | beq $t0, $t1, .do_mmap_anon # anonymous mmap | 44 | beq $t0, $t1, do_mmap_anon # anonymous mmap |
| 45 | .do_mmap: | 45 | do_mmap: |
| 46 | lw $a0, 4($s0) # vm_address, delay slot | 46 | lw $a0, 4($s0) # vm_address, delay slot |
| 47 | lw $v1, 8($s0) # file_offset | 47 | lw $v1, 8($s0) # file_offset |
| 48 | lw $a2, 12($s0) # protection | 48 | lw $a2, 12($s0) # protection |
| @@ -50,33 +50,33 @@ dnl syscall # syscall | |||
| 50 | lw $a3, 20($s0) # flags | 50 | lw $a3, 20($s0) # flags |
| 51 | lw $v0, ($sp) # primary fd | 51 | lw $v0, ($sp) # primary fd |
| 52 | andi $t1, $s2, 16 # t1 = s2 & 16 | 52 | andi $t1, $s2, 16 # t1 = s2 & 16 |
| 53 | beqz $t1, .do_mmap_1 # secondary fd? | 53 | beqz $t1, do_mmap_1 # secondary fd? |
| 54 | nop # delay slot | 54 | nop # delay slot |
| 55 | lw $v0, 4($sp) # secondary fd | 55 | lw $v0, 4($sp) # secondary fd |
| 56 | nop # delay slot | 56 | nop # delay slot |
| 57 | .do_mmap_1: | 57 | do_mmap_1: |
| 58 | SYSCALL(`$v0',`$v1',`$zero',`$zero') # syscall args | 58 | SYSCALL(`$v0',`$v1',`$zero',`$zero') # syscall args |
| 59 | li $v0, SYSCALL_mmap # SYS_mmap | 59 | li $v0, SYSCALL_mmap # SYS_mmap |
| 60 | syscall # syscall | 60 | syscall # syscall |
| 61 | bne $a3, $zero, .perror # perror | 61 | bnez $a3, perror # perror |
| 62 | RESTORE() # delay slot, restore sp | 62 | RESTORE() # delay slot, restore sp |
| 63 | lw $s5, 24($s0) # clear | 63 | lw $s5, 24($s0) # clear |
| 64 | add $t0, $a0, $a1 # t0 = length + vm_address, delay slot | 64 | add $t0, $a0, $a1 # t0 = length + vm_address, delay slot |
| 65 | sub $t1, $t0, $s5 # t1 = t0 - clear | 65 | sub $t1, $t0, $s5 # t1 = t0 - clear |
| 66 | .align: | 66 | align: |
| 67 | beq $t0, $t1, .continue # already finished? | 67 | beq $t0, $t1, continue # already finished? |
| 68 | nop # delay slot | 68 | nop # delay slot |
| 69 | andi $t2, $t1, 3 # t1 & 3? | 69 | andi $t2, $t1, 3 # t1 & 3? |
| 70 | bnez $t2, .fillw # start filling longs | 70 | bnez $t2, fillw # start filling longs |
| 71 | nop # delay slot | 71 | nop # delay slot |
| 72 | sb $zero, ($t1) # clear byte | 72 | sb $zero, ($t1) # clear byte |
| 73 | addi $t1, $t1, 1 # t1++ | 73 | addi $t1, $t1, 1 # t1++ |
| 74 | j .align # continue | 74 | j align # continue |
| 75 | nop # delay slot | 75 | nop # delay slot |
| 76 | .fillw: | 76 | fillw: |
| 77 | sub $t2, $t0, $t1 # t2 = t0 - t1 | 77 | sub $t2, $t0, $t1 # t2 = t0 - t1 |
| 78 | sltiu $t2, $t2, 32 # r2 < 32? | 78 | sltiu $t2, $t2, 32 # r2 < 32? |
| 79 | bne $t2, $zero, .fillb # fill bytes | 79 | bne $t2, $zero, fillb # fill bytes |
| 80 | nop # delay slot | 80 | nop # delay slot |
| 81 | sw $zero, ($t1) # zero word | 81 | sw $zero, ($t1) # zero word |
| 82 | addi $t1, $t1, 4 # next word | 82 | addi $t1, $t1, 4 # next word |
| @@ -94,53 +94,52 @@ RESTORE() # delay slot, restore sp | |||
| 94 | addi $t1, $t1, 4 # next word | 94 | addi $t1, $t1, 4 # next word |
| 95 | sw $zero, ($t1) # zero word | 95 | sw $zero, ($t1) # zero word |
| 96 | addi $t1, $t1, 4 # next word | 96 | addi $t1, $t1, 4 # next word |
| 97 | j .fillw # fill either word or byte | 97 | j fillw # fill either word or byte |
| 98 | nop # delay slot | 98 | nop # delay slot |
| 99 | .fillb: | 99 | fillb: |
| 100 | beq $t0, $t1, .continue # already finished? | 100 | beq $t0, $t1, continue # already finished? |
| 101 | nop # delay slot | 101 | nop # delay slot |
| 102 | sb $zero, ($t1) # clear byte | 102 | sb $zero, ($t1) # clear byte |
| 103 | addi $t1, $t1, 1 # t1++ | 103 | addi $t1, $t1, 1 # t1++ |
| 104 | .continue: | 104 | continue: |
| 105 | addi $s0, $s0, 28 # s0 = next action | 105 | addi $s0, $s0, 28 # s0 = next action |
| 106 | j .next_action # next action | 106 | j next_action # next action |
| 107 | nop # delay slot | 107 | nop # delay slot |
| 108 | .do_mmap_anon: | 108 | do_mmap_anon: |
| 109 | lw $v1, 8($s0) # file_offset | 109 | lw $v1, 8($s0) # file_offset |
| 110 | lw $a2, 12($s0) # protection | 110 | lw $a2, 12($s0) # protection |
| 111 | lw $a1, 16($s0) # length | 111 | lw $a1, 16($s0) # length |
| 112 | lw $a3, 20($s0) # flags | 112 | lw $a3, 20($s0) # flags |
| 113 | li $t4, -1 # fd | 113 | j do_mmap_1 # do mmap |
| 114 | j .do_mmap_1 # do mmap | 114 | li $v0, -1 # fd, delay slot |
| 115 | nop # delay slot | 115 | open_file: |
| 116 | .open_file: | ||
| 117 | li $v0, SYSCALL_open # SYS_open | 116 | li $v0, SYSCALL_open # SYS_open |
| 118 | addi $a0, $s0, 4 # start of name | 117 | addi $a0, $s0, 4 # start of name |
| 119 | move $a1, $zero # flags = O_RDONLY | 118 | move $a1, $zero # flags = O_RDONLY |
| 120 | move $a2, $zero # mode = 0 | 119 | move $a2, $zero # mode = 0 |
| 121 | syscall # syscall | 120 | syscall # syscall |
| 122 | bne $a3, $zero, .perror # perror | 121 | bne $a3, $zero, perror # perror |
| 123 | addi $s0, $s0, 4 # start of string, delay slot | 122 | addi $s0, $s0, 4 # start of string, delay slot |
| 124 | move $t3, $s0 # t3 = char past separator | 123 | move $t3, $s0 # t3 = char past separator |
| 125 | .nextc: | 124 | nextc: |
| 126 | lb $t0, ($s0) # load byte | 125 | lb $t0, ($s0) # load byte |
| 127 | addi $s0, $s0, 1 # s0++ | 126 | addi $s0, $s0, 1 # s0++ |
| 128 | li $t1, 47 # directory separator `/' | 127 | li $t1, 47 # directory separator `/' |
| 129 | bne $t0, $t1, .nextc1 # is separator char? | 128 | bne $t0, $t1, nextc1 # is separator char? |
| 130 | nop # delay slot | 129 | nop # delay slot |
| 131 | move $t3, $s0 # t3 = char past separator | 130 | move $t3, $s0 # t3 = char past separator |
| 132 | .nextc1: | 131 | nextc1: |
| 133 | bnez $t0, .nextc # next character? | 132 | bnez $t0, nextc # next character? |
| 134 | nop # delay slot | 133 | nop # delay slot |
| 135 | addi $s0, $s0, 3 # adjust for round | 134 | addi $s0, $s0, 3 # adjust for round |
| 136 | li $t2, -4 # t2 = -4 | 135 | li $t2, -4 # t2 = -4 |
| 137 | and $s0, $s0, $t2 # mask for round | 136 | and $s0, $s0, $t2 # mask for round |
| 138 | andi $t0, $s2, 16 # t1 = s2 & 16 | 137 | andi $t0, $s2, 16 # t1 = s2 & 16 |
| 139 | beqz $t0, .primary # primary fd? | 138 | beqz $t0, primary # primary fd? |
| 140 | move $t0, $sp # address of primary fd, delay slot | 139 | move $t0, $sp # address of primary fd, delay slot |
| 141 | addi $t0, $t0, 4 # address of secondary fd | 140 | addi $t0, $t0, 4 # address of secondary fd |
| 142 | j .next_action # next action | 141 | j next_action # next action |
| 143 | .primary: | 142 | primary: |
| 144 | sw $v0, ($t0) # store fd, delay slot | 143 | sw $v0, ($t0) # store fd, delay slot |
| 145 | li $v0, SYSCALL_prctl # SYS_prctl | 144 | li $v0, SYSCALL_prctl # SYS_prctl |
| 146 | li $a0, 15 # PR_SET_NAME | 145 | li $a0, 15 # PR_SET_NAME |
| @@ -150,86 +149,209 @@ RESTORE() # delay slot, restore sp | |||
| 150 | SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args | 149 | SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args |
| 151 | syscall # syscall | 150 | syscall # syscall |
| 152 | RESTORE() # restore sp | 151 | RESTORE() # restore sp |
| 153 | j .next_action # next action | 152 | j next_action # next action |
| 154 | nop # delay slot | 153 | nop # delay slot |
| 155 | .perror: | 154 | perror: |
| 156 | move $a0, $v0 # errno | 155 | move $a0, $v0 # errno |
| 157 | li $v0, SYSCALL_exit # SYS_exit | 156 | li $v0, SYSCALL_exit # SYS_exit |
| 158 | syscall # syscall | 157 | syscall # syscall |
| 159 | .rest_of_exec: | 158 | rest_of_exec: |
| 160 | move $s1, $s6 # s1 = original SP | 159 | move $s1, $s6 # s1 = original SP |
| 161 | lw $t0, ($s1) # argc | 160 | lw $t0, ($s1) # argc |
| 162 | nop # delay slot | 161 | nop # delay slot |
| 163 | sll $t0, $t0, 2 # argc *= 4 | 162 | sll $t0, $t0, 2 # argc *= 4 |
| 164 | addi $t0, $t0, 8 # argc += 8 | 163 | addi $t0, $t0, 8 # argc += 8 |
| 165 | add $s1, $s1, $t0 # s1 = start of envp | 164 | add $s1, $s1, $t0 # s1 = start of envp |
| 166 | .skipenv: | 165 | skip_environ: |
| 167 | lw $t0, ($s1) # t0 = *s1 | 166 | /* Locate the auxiliary vector. */ |
| 167 | 1: lw $t0, ($s1) # t0 = *s1 | ||
| 168 | bnez $t0, 1b # skip environment entry | ||
| 168 | addi $s1, $s1, 4 # s1++ | 169 | addi $s1, $s1, 4 # s1++ |
| 169 | bne $t0, $zero, .skipenv # skip again | 170 | move $s2, $s1 # $s2 = end of environment |
| 170 | nop # delay slot | 171 | 1: lw $t0, ($s1) # t0 = *s1 |
| 171 | la $s2, .auxvtab # address of auxv table | 172 | bnez $t0, 1b # skip auxiliary vector entry |
| 172 | .one_auxv: | 173 | addi $s1, $s1, 8 # (Elf32_auxv_t *) s1++ |
| 173 | lw $t0, ($s1) # t0 = auxv type | 174 | /* Decide how many bytes must be copied and where to |
| 174 | li $t1, 10 # t1 = 10, delay slot | 175 | save the file name. Move the stack pointer to a safe |
| 175 | beqz $t0, .finish # is AT_IGNORE? | 176 | position below any data that must be preserved. */ |
| 176 | sltu $t1, $t0, $t1 # t1 = t0 < num offsets, delay slot | 177 | lw $t1, 32($s0) # length of string |
| 177 | beq $t1, $zero, .next # next auxv | 178 | addi $t1, $t1, 1 |
| 178 | sll $t1, $t0, 2 # t1 = t0 * 4, delay slot | 179 | addi $t2, $s0, 36 # pointer to string |
| 179 | add $t1, $s2, $t1 # t1 = .auxvtab + t1 | 180 | sub $t3, $s1, $s6 # number of bytes in vectors |
| 180 | lw $t2, ($t1) # t2 = *t1 | 181 | sub $t0, $s1, $t1 # position of string |
| 181 | nop # delay slot | 182 | and $t0, $t0, -16 # align value |
| 182 | beqz $t2, .next # skip auxv | 183 | sub $t3, $t0, $t3 # position of argc |
| 183 | add $t2, $s0, $t2 # t2 = s0 + t2 | 184 | and $t3, $t3, -16 # align value |
| 184 | lw $t2, ($t2) # t2 = *t2 | 185 | /* Move the stack pointer and save required information. |
| 185 | nop # delay slot | 186 | 4(FP) = secondary/interpreter fd. |
| 186 | sw $t2, 4($s1) # set auxv value | 187 | 0(FP) = primary/executable fd. |
| 187 | .next: | 188 | -4(FP) = cmd->entry |
| 188 | addi $s1, $s1, 8 # next auxv | 189 | -8(FP) = cmd->at_entry |
| 189 | j .one_auxv # next auxv | 190 | -12(FP) = cmd->at_phent |
| 190 | nop # delay slot | 191 | -16(FP) = cmd->at_phnum |
| 191 | .finish: | 192 | -20(FP) = cmd->at_phdr |
| 192 | lw $t0, 4($sp) # secondary fd | 193 | -24(FP) = cmd->at_base |
| 193 | lw $s1, ($sp) # primary fd, delay slot, preserved | 194 | -28(FP) = cmd->fpu_mode (only significant when N32) |
| 195 | $sp = copy of string. */ | ||
| 196 | move $t4, $sp # current sp | ||
| 197 | sub $t5, $t3, $sp # new argc - current sp | ||
| 198 | bleu $t5, -8, 1f # more than two slots apart | ||
| 199 | addi $sp, $t3, -8 # $sp = two slots below new argc | ||
| 200 | j 2f # skip copying fds | ||
| 201 | 1: move $sp, $t4 # retain current sp | ||
| 202 | lw $t5, ($t4) # old primary fd | ||
| 203 | sw $t5, ($sp) # save the same | ||
| 204 | lw $t5, 4($t4) # old interpreter fd | ||
| 205 | sw $t5, 4($sp) # save the same | ||
| 206 | 2: move FP, $sp # set base pointer | ||
| 207 | addi $sp, $sp, -28 # command data | ||
| 208 | lw $t5, 4($s0) # entry | ||
| 209 | lw $t6, 8($s0) # at_entry | ||
| 210 | sw $t5, -4(FP) # save entry | ||
| 211 | sw $t6, -8(FP) # save at_entry | ||
| 212 | lw $t5, 12($s0) # at_phent | ||
| 213 | lw $t6, 16($s0) # at_phnum | ||
| 214 | sw $t5, -12(FP) # save at_phent | ||
| 215 | sw $t6, -16(FP) # save at_phnum | ||
| 216 | lw $t5, 20($s0) # at_phdr | ||
| 217 | lw $t6, 24($s0) # at_base | ||
| 218 | sw $t5, -20(FP) # save at_phdr | ||
| 219 | sw $t6, -24(FP) # save at_base | ||
| 220 | lw $t5, 28($s0) # fpu_mode | ||
| 221 | sw $t5, -28(FP) # save fpu_mode | ||
| 222 | sub $sp, $sp, $t1 # space for string | ||
| 223 | /* Save the input string. */ | ||
| 224 | add $t5, $t2, $t1 # end of source ($t2) | ||
| 225 | move $t6, $sp # dst | ||
| 226 | move $s0, $t1 # $s0 = length of string | ||
| 227 | /* src = $t2, dst = $t6 */ | ||
| 228 | bgeu $t2, $t5, 2f # there already? | ||
| 229 | nop | ||
| 230 | 1: lb $t1, ($t2) # $t1 = *$t2 | ||
| 231 | addi $t2, $t2, 1 # $t2++ | ||
| 232 | addi $t6, $t6, 1 # $t6++ | ||
| 233 | bltu $t2, $t5, 1b | ||
| 234 | sb $t1, -1($t6) # *($t6 - 1) = $t1 | ||
| 235 | 2: move $s3, $sp # copy of string | ||
| 236 | and $sp, $sp, -16 # align stack | ||
| 237 | copy_env_and_args: | ||
| 238 | /* Copy argc, argv, and the environment array. | ||
| 239 | $t4 = destination, $t5 = src, $s2 = src_end */ | ||
| 240 | move $t4, $t3 # destination of argc | ||
| 241 | move $t5, $s6 # original SP | ||
| 242 | bgeu $t5, $s2, 2f # there already? | ||
| 243 | nop | ||
| 244 | 1: lw $t1, ($t5) # $t1 = *src | ||
| 245 | addi $t5, $t5, 4 # src++ | ||
| 246 | addi $t4, $t4, 4 # dst++ | ||
| 247 | bltu $t5, $s2, 1b # src < src_end | ||
| 248 | sw $t1, -4($t4) # *(dst - 4) = $t1 | ||
| 249 | copy_auxv: | ||
| 250 | /* $t4 = destination, $t5 = first auxval. */ | ||
| 251 | 2: lw $t1, ($t5) # a_type | ||
| 252 | lw $t2, 4($t5) # a_un.a_val | ||
| 253 | addi $t4, $t4, 8 # (Elf32_auxv_t *) dst++ | ||
| 254 | addi $t5, $t5, 8 # (Elf32_auxv_t *) src++ | ||
| 255 | beqz $t1, 8f # AT_NULL | ||
| 256 | li $t6, 3 | ||
| 257 | beq $t1, $t6, 1f # AT_PHDR | ||
| 258 | li $t6, 4 | ||
| 259 | beq $t1, $t6, 2f # AT_PHENT | ||
| 260 | li $t6, 5 | ||
| 261 | beq $t1, $t6, 3f # AT_PHNUM | ||
| 262 | li $t6, 9 | ||
| 263 | beq $t1, $t6, 4f # AT_ENTRY | ||
| 264 | li $t6, 7 | ||
| 265 | beq $t1, $t6, 5f # AT_BASE | ||
| 266 | li $t6, 31 | ||
| 267 | beq $t1, $t6, 6f # AT_EXECFN | ||
| 268 | nop | ||
| 269 | b 7f | ||
| 270 | nop | ||
| 271 | 1: b 7f | ||
| 272 | lw $t2, -20(FP) | ||
| 273 | 2: b 7f | ||
| 274 | lw $t2, -12(FP) | ||
| 275 | 3: b 7f | ||
| 276 | lw $t2, -16(FP) | ||
| 277 | 4: b 7f | ||
| 278 | lw $t2, -8(FP) | ||
| 279 | 5: b 7f | ||
| 280 | lw $t2, -24(FP) | ||
| 281 | 6: b 7f | ||
| 282 | move $t2, $t0 | ||
| 283 | 7: sw $t1, -8($t4) # dst->a_type | ||
| 284 | j copy_auxv | ||
| 285 | sw $t2, -4($t4) # dst->a_un.a_val | ||
| 286 | /* Copy the final element. */ | ||
| 287 | 8: sw $t1, -8($t4) # dst->a_type | ||
| 288 | sw $t2, -4($t4) # dst->a_un.a_val | ||
| 289 | finish: | ||
| 290 | /* Copy the string to its position in auxv | ||
| 291 | (src = $s3, dst = $t0). */ | ||
| 292 | add $t1, $s3, $s0 # src end | ||
| 293 | bgeu $s3, $t1, 2f # there already? | ||
| 294 | nop | ||
| 295 | 1: lb $t2, ($s3) # c = *src | ||
| 296 | addi $s3, $s3, 1 # *src++ | ||
| 297 | addi $t0, $t0, 1 # dst++ | ||
| 298 | bltu $s3, $t1, 1b | ||
| 299 | sb $t2, -1($t0) # *(dst - 1) = c | ||
| 300 | /* Save variables. */ | ||
| 301 | 2: move $s6, $t3 # new stack pointer | ||
| 302 | lw $t4, 4(FP) # secondary fd | ||
| 303 | lw $s1, (FP) # primary fd, delay slot, preserved | ||
| 194 | li $t2, -1 # immediate -1 | 304 | li $t2, -1 # immediate -1 |
| 195 | beq $t0, $t2, .finish1 # secondary fd set? | 305 | beq $t4, $t2, finish1 # secondary fd set? |
| 196 | li $v0, SYSCALL_close # SYS_close, delay slot | 306 | li $v0, SYSCALL_close # SYS_close, delay slot |
| 197 | move $a0, $t0 # fd | 307 | move $a0, $t4 # fd |
| 198 | syscall # syscall | 308 | syscall # syscall |
| 199 | li $v0, SYSCALL_close # SYS_close | 309 | li $v0, SYSCALL_close # SYS_close |
| 200 | .finish1: | 310 | finish1: |
| 201 | move $a0, $s1 # primary fd | 311 | move $a0, $s1 # primary fd |
| 202 | syscall # syscall | 312 | syscall # syscall |
| 203 | li $v0, SYSCALL_prctl # SYS_prctl | 313 | li $v0, SYSCALL_prctl # SYS_prctl |
| 204 | li $a0, 45 # PR_SET_FP_MODE | 314 | li $a0, 45 # PR_SET_FP_MODE |
| 205 | lw $a1, 28($s0) # fpu_mode | 315 | lw $a1, -28(FP) # fpu_mode |
| 206 | move $a2, $zero # arg3 | 316 | move $a2, $zero # arg3 |
| 207 | move $a3, $zero # arg4 | 317 | move $a3, $zero # arg4 |
| 208 | SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args | 318 | SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args |
| 209 | syscall # syscall | 319 | syscall # syscall |
| 210 | RESTORE() # restore sp | 320 | RESTORE() # restore sp |
| 211 | .jump: | 321 | jump: |
| 212 | move $v0, $zero # rtld_fini | 322 | move $v0, $zero # rtld_fini |
| 213 | lw $t0, 4($s0) # entry | 323 | lw $t9, -4(FP) # entry |
| 214 | move $sp, $s6 # restore stack pointer, delay slot | 324 | move $sp, $s6 # restore stack pointer, delay slot |
| 215 | jr $t0 # enter | 325 | /* Clear at least one page's worth of stack. glibc on mipsel |
| 216 | nop # delay slot | 326 | copies certain fields from the stack to the `link_map' |
| 327 | structure representing ld.so, which are not subsequently | ||
| 328 | replaced if otherwise than zero. | ||
| 217 | 329 | ||
| 218 | .auxvtab: | 330 | XXX: report this glibc bug? */ |
| 219 | .long 0 # 0 | 331 | addi $v0, $sp, -4096 |
| 220 | .long 0 # 1 | 332 | and $v0, $v0, -4095 |
| 221 | .long 0 # 2 | 333 | 1: sw $zero, ($v0) # copy 32 byte blocks |
| 222 | .long 20 # 3 AT_PHDR | 334 | sw $zero, 4($v0) |
| 223 | .long 12 # 4 AT_PHENT | 335 | sw $zero, 8($v0) |
| 224 | .long 16 # 5 AT_PHNUM | 336 | sw $zero, 12($v0) |
| 225 | .long 0 # 6 | 337 | sw $zero, 16($v0) |
| 226 | .long 24 # 7 AT_BASE | 338 | sw $zero, 20($v0) |
| 227 | .long 0 # 8 | 339 | sw $zero, 24($v0) |
| 228 | .long 8 # 9 AT_ENTRY | 340 | sw $zero, 28($v0) |
| 341 | addi $v0, $v0, 32 | ||
| 342 | sub $t0, $sp, $v0 # remainder | ||
| 343 | bge $t0, 32, 1b # test remainder | ||
| 344 | nop # copy 4 byte blocks | ||
| 345 | beqz $t0, 2f | ||
| 346 | 1: addi $v0, $v0, 4 | ||
| 347 | bltu $v0, $sp, 1b | ||
| 348 | sw $zero, -4($v0) | ||
| 349 | 2: jr $t9 # enter | ||
| 350 | nop # delay slot | ||
| 229 | 351 | ||
| 230 | .timespec: | 352 | ## timespec: |
| 231 | .long 10 | 353 | ## .long 10 |
| 232 | .long 10 | 354 | ## .long 10 |
| 233 | 355 | ||
| 234 | # Local Variables: | 356 | # Local Variables: |
| 235 | # asm-comment-char: ?# | 357 | # asm-comment-char: ?# |