From 1ae7006148d315c106c5da241ea3b035946e133b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 14 Apr 2025 21:28:15 +0800 Subject: [PATCH] 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. (cherry picked from commit 74df372398dbc90f6c0185f1701af28129073de7) --- exec/config-mips.m4.in | 2 + exec/exec.c | 13 +- exec/loader-aarch64.s | 2 +- exec/loader-mips64el.s | 2 + 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 dnl along with GNU Emacs. If not, see . define(`SYSCALL_open', `ifelse(`@MIPS_N32@',`yes',`6002',`4005')') +dnl define(`SYSCALL_openat', `ifelse(`@MIPS_N32@',`yes',`6251',`4288')') define(`SYSCALL_close', `ifelse(`@MIPS_N32@',`yes',`6003',`4006')') define(`SYSCALL_mmap', `ifelse(`@MIPS_N32@',`yes',`6009',`4090')') define(`SYSCALL_nanosleep', `ifelse(`@MIPS_N32@',`yes',`6034',`4166')') @@ -34,6 +35,7 @@ define(`SYSCALL', `ifelse(`@MIPS_N32@',`yes',` move $a4, $1 sw $4, 28($sp)')') define(`RESTORE', `ifelse(`@MIPS_N32@',`yes',` nop',` addi $sp, 32')') +define(`FP', `ifelse(`@MIPS_N32@',`yes',`$s8',`$fp')') dnl For mips64. Some assemblers don't want to assemble `daddi'. 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 /* The value of AT_BASE inside the aux vector. */ USER_WORD at_base; -#if defined __mips__ && !defined MIPS_NABI - /* The FPU mode to apply. */ +#if defined __mips__ + /* The FPU mode to apply. Not used when !MIPS_NABI. */ USER_WORD fpu_mode; -#endif /* defined __mips__ && !defined MIPS_NABI */ +#endif /* defined __mips__ */ }; @@ -916,9 +916,7 @@ 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; @@ -1132,6 +1130,8 @@ exec_0 (char *name, struct exec_tracee *tracee, fpu_mode = FP_FRE; jump.fpu_mode = fpu_mode; +#elif defined __mips__ + jump.fpu_mode = 0; #endif /* defined __mips__ && !defined MIPS_NABI */ /* The offset used for at_phdr should be that of the first @@ -1149,8 +1149,6 @@ 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) @@ -1167,7 +1165,6 @@ exec_0 (char *name, struct exec_tracee *tracee, 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 376f439417f..d3c565bf3f8 100644 --- a/exec/loader-aarch64.s +++ b/exec/loader-aarch64.s @@ -144,7 +144,7 @@ skip_environ: 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. + // Load values that must be preserved into registers x14-x19. // x14 = cmd->entry // x15 = cmd->at_entry // 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 @@ # You should have received a copy of the GNU General Public License # along with GNU Emacs. If not, see . + /* NOTE: this file is presently non-functional. */ + include(`config-mips.m4') .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 @@ # You should have received a copy of the GNU General Public License # along with GNU Emacs. If not, see . -include(`config-mips.m4') + include(`config-mips.m4') -# Make sure not to use t4 through t7, in order to maintain portability -# with N32 ABI systems. +## Beware: $t0-$t4 alias the syscall (and function, but they are not +## material in this context) argument registers on N32 systems, and +## mustn't be relied upon to hold arguments to `SYSCALL'. .set noreorder # delay slots managed by hand .section .text .global __start __start: -dnl li $v0, SYSCALL_nanosleep # SYS_nanosleep -dnl la $a0, .timespec # rqtp -dnl li $a1, 0 # rmtp -dnl syscall # syscall + ## li $v0, SYSCALL_nanosleep # SYS_nanosleep + ## la $a0, timespec # rqtp + ## li $a1, 0 # rmtp + ## syscall # syscall lw $s6, ($sp) # original stack pointer addi $s0, $sp, 8 # start of load area addi $sp, -8 # primary fd, secondary fd li $t0, -1 # secondary fd sw $t0, 4($sp) # initialize secondary fd -.next_action: +next_action: lw $s2, ($s0) # action number - nop # delay slot andi $t0, $s2, 15 # t0 = s2 & 15 - beqz $t0, .open_file # open file? + beqz $t0, open_file # open file? li $t1, 3 # t1 = 3, delay slot - beq $t0, $t1, .rest_of_exec # jump to code + beq $t0, $t1, rest_of_exec # jump to code li $t1, 4 # t1 = 4, delay slot - beq $t0, $t1, .do_mmap_anon # anonymous mmap -.do_mmap: + beq $t0, $t1, do_mmap_anon # anonymous mmap +do_mmap: lw $a0, 4($s0) # vm_address, delay slot lw $v1, 8($s0) # file_offset lw $a2, 12($s0) # protection @@ -50,33 +50,33 @@ dnl syscall # syscall lw $a3, 20($s0) # flags lw $v0, ($sp) # primary fd andi $t1, $s2, 16 # t1 = s2 & 16 - beqz $t1, .do_mmap_1 # secondary fd? + beqz $t1, do_mmap_1 # secondary fd? nop # delay slot lw $v0, 4($sp) # secondary fd nop # delay slot -.do_mmap_1: +do_mmap_1: SYSCALL(`$v0',`$v1',`$zero',`$zero') # syscall args li $v0, SYSCALL_mmap # SYS_mmap syscall # syscall - bne $a3, $zero, .perror # perror + bnez $a3, perror # perror RESTORE() # delay slot, restore sp lw $s5, 24($s0) # clear add $t0, $a0, $a1 # t0 = length + vm_address, delay slot sub $t1, $t0, $s5 # t1 = t0 - clear -.align: - beq $t0, $t1, .continue # already finished? +align: + beq $t0, $t1, continue # already finished? nop # delay slot andi $t2, $t1, 3 # t1 & 3? - bnez $t2, .fillw # start filling longs + bnez $t2, fillw # start filling longs nop # delay slot sb $zero, ($t1) # clear byte addi $t1, $t1, 1 # t1++ - j .align # continue + j align # continue nop # delay slot -.fillw: +fillw: sub $t2, $t0, $t1 # t2 = t0 - t1 sltiu $t2, $t2, 32 # r2 < 32? - bne $t2, $zero, .fillb # fill bytes + bne $t2, $zero, fillb # fill bytes nop # delay slot sw $zero, ($t1) # zero word addi $t1, $t1, 4 # next word @@ -94,53 +94,52 @@ RESTORE() # delay slot, restore sp addi $t1, $t1, 4 # next word sw $zero, ($t1) # zero word addi $t1, $t1, 4 # next word - j .fillw # fill either word or byte + j fillw # fill either word or byte nop # delay slot -.fillb: - beq $t0, $t1, .continue # already finished? +fillb: + beq $t0, $t1, continue # already finished? nop # delay slot sb $zero, ($t1) # clear byte addi $t1, $t1, 1 # t1++ -.continue: +continue: addi $s0, $s0, 28 # s0 = next action - j .next_action # next action + j next_action # next action nop # delay slot -.do_mmap_anon: +do_mmap_anon: lw $v1, 8($s0) # file_offset lw $a2, 12($s0) # protection lw $a1, 16($s0) # length lw $a3, 20($s0) # flags - li $t4, -1 # fd - j .do_mmap_1 # do mmap - nop # delay slot -.open_file: + j do_mmap_1 # do mmap + li $v0, -1 # fd, delay slot +open_file: li $v0, SYSCALL_open # SYS_open addi $a0, $s0, 4 # start of name move $a1, $zero # flags = O_RDONLY move $a2, $zero # mode = 0 syscall # syscall - bne $a3, $zero, .perror # perror + bne $a3, $zero, perror # perror addi $s0, $s0, 4 # start of string, delay slot move $t3, $s0 # t3 = char past separator -.nextc: +nextc: lb $t0, ($s0) # load byte addi $s0, $s0, 1 # s0++ li $t1, 47 # directory separator `/' - bne $t0, $t1, .nextc1 # is separator char? + bne $t0, $t1, nextc1 # is separator char? nop # delay slot move $t3, $s0 # t3 = char past separator -.nextc1: - bnez $t0, .nextc # next character? +nextc1: + bnez $t0, nextc # next character? nop # delay slot addi $s0, $s0, 3 # adjust for round li $t2, -4 # t2 = -4 and $s0, $s0, $t2 # mask for round andi $t0, $s2, 16 # t1 = s2 & 16 - beqz $t0, .primary # primary fd? + beqz $t0, primary # primary fd? move $t0, $sp # address of primary fd, delay slot addi $t0, $t0, 4 # address of secondary fd - j .next_action # next action -.primary: + j next_action # next action +primary: sw $v0, ($t0) # store fd, delay slot li $v0, SYSCALL_prctl # SYS_prctl li $a0, 15 # PR_SET_NAME @@ -150,86 +149,209 @@ RESTORE() # delay slot, restore sp SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args syscall # syscall RESTORE() # restore sp - j .next_action # next action + j next_action # next action nop # delay slot -.perror: +perror: move $a0, $v0 # errno li $v0, SYSCALL_exit # SYS_exit syscall # syscall -.rest_of_exec: +rest_of_exec: move $s1, $s6 # s1 = original SP lw $t0, ($s1) # argc nop # delay slot sll $t0, $t0, 2 # argc *= 4 addi $t0, $t0, 8 # argc += 8 add $s1, $s1, $t0 # s1 = start of envp -.skipenv: - lw $t0, ($s1) # t0 = *s1 +skip_environ: + /* Locate the auxiliary vector. */ +1: lw $t0, ($s1) # t0 = *s1 + bnez $t0, 1b # skip environment entry addi $s1, $s1, 4 # s1++ - bne $t0, $zero, .skipenv # skip again - nop # delay slot - la $s2, .auxvtab # address of auxv table -.one_auxv: - lw $t0, ($s1) # t0 = auxv type - li $t1, 10 # t1 = 10, delay slot - beqz $t0, .finish # is AT_IGNORE? - sltu $t1, $t0, $t1 # t1 = t0 < num offsets, delay slot - beq $t1, $zero, .next # next auxv - sll $t1, $t0, 2 # t1 = t0 * 4, delay slot - add $t1, $s2, $t1 # t1 = .auxvtab + t1 - lw $t2, ($t1) # t2 = *t1 - nop # delay slot - beqz $t2, .next # skip auxv - add $t2, $s0, $t2 # t2 = s0 + t2 - lw $t2, ($t2) # t2 = *t2 - nop # delay slot - sw $t2, 4($s1) # set auxv value -.next: - addi $s1, $s1, 8 # next auxv - j .one_auxv # next auxv - nop # delay slot -.finish: - lw $t0, 4($sp) # secondary fd - lw $s1, ($sp) # primary fd, delay slot, preserved + move $s2, $s1 # $s2 = end of environment +1: lw $t0, ($s1) # t0 = *s1 + bnez $t0, 1b # skip auxiliary vector entry + addi $s1, $s1, 8 # (Elf32_auxv_t *) s1++ + /* Decide how many bytes must be copied and where to + save the file name. Move the stack pointer to a safe + position below any data that must be preserved. */ + lw $t1, 32($s0) # length of string + addi $t1, $t1, 1 + addi $t2, $s0, 36 # pointer to string + sub $t3, $s1, $s6 # number of bytes in vectors + sub $t0, $s1, $t1 # position of string + and $t0, $t0, -16 # align value + sub $t3, $t0, $t3 # position of argc + and $t3, $t3, -16 # align value + /* Move the stack pointer and save required information. + 4(FP) = secondary/interpreter fd. + 0(FP) = primary/executable fd. + -4(FP) = cmd->entry + -8(FP) = cmd->at_entry + -12(FP) = cmd->at_phent + -16(FP) = cmd->at_phnum + -20(FP) = cmd->at_phdr + -24(FP) = cmd->at_base + -28(FP) = cmd->fpu_mode (only significant when N32) + $sp = copy of string. */ + move $t4, $sp # current sp + sub $t5, $t3, $sp # new argc - current sp + bleu $t5, -8, 1f # more than two slots apart + addi $sp, $t3, -8 # $sp = two slots below new argc + j 2f # skip copying fds +1: move $sp, $t4 # retain current sp + lw $t5, ($t4) # old primary fd + sw $t5, ($sp) # save the same + lw $t5, 4($t4) # old interpreter fd + sw $t5, 4($sp) # save the same +2: move FP, $sp # set base pointer + addi $sp, $sp, -28 # command data + lw $t5, 4($s0) # entry + lw $t6, 8($s0) # at_entry + sw $t5, -4(FP) # save entry + sw $t6, -8(FP) # save at_entry + lw $t5, 12($s0) # at_phent + lw $t6, 16($s0) # at_phnum + sw $t5, -12(FP) # save at_phent + sw $t6, -16(FP) # save at_phnum + lw $t5, 20($s0) # at_phdr + lw $t6, 24($s0) # at_base + sw $t5, -20(FP) # save at_phdr + sw $t6, -24(FP) # save at_base + lw $t5, 28($s0) # fpu_mode + sw $t5, -28(FP) # save fpu_mode + sub $sp, $sp, $t1 # space for string + /* Save the input string. */ + add $t5, $t2, $t1 # end of source ($t2) + move $t6, $sp # dst + move $s0, $t1 # $s0 = length of string + /* src = $t2, dst = $t6 */ + bgeu $t2, $t5, 2f # there already? + nop +1: lb $t1, ($t2) # $t1 = *$t2 + addi $t2, $t2, 1 # $t2++ + addi $t6, $t6, 1 # $t6++ + bltu $t2, $t5, 1b + sb $t1, -1($t6) # *($t6 - 1) = $t1 +2: move $s3, $sp # copy of string + and $sp, $sp, -16 # align stack +copy_env_and_args: + /* Copy argc, argv, and the environment array. + $t4 = destination, $t5 = src, $s2 = src_end */ + move $t4, $t3 # destination of argc + move $t5, $s6 # original SP + bgeu $t5, $s2, 2f # there already? + nop +1: lw $t1, ($t5) # $t1 = *src + addi $t5, $t5, 4 # src++ + addi $t4, $t4, 4 # dst++ + bltu $t5, $s2, 1b # src < src_end + sw $t1, -4($t4) # *(dst - 4) = $t1 +copy_auxv: + /* $t4 = destination, $t5 = first auxval. */ +2: lw $t1, ($t5) # a_type + lw $t2, 4($t5) # a_un.a_val + addi $t4, $t4, 8 # (Elf32_auxv_t *) dst++ + addi $t5, $t5, 8 # (Elf32_auxv_t *) src++ + beqz $t1, 8f # AT_NULL + li $t6, 3 + beq $t1, $t6, 1f # AT_PHDR + li $t6, 4 + beq $t1, $t6, 2f # AT_PHENT + li $t6, 5 + beq $t1, $t6, 3f # AT_PHNUM + li $t6, 9 + beq $t1, $t6, 4f # AT_ENTRY + li $t6, 7 + beq $t1, $t6, 5f # AT_BASE + li $t6, 31 + beq $t1, $t6, 6f # AT_EXECFN + nop + b 7f + nop +1: b 7f + lw $t2, -20(FP) +2: b 7f + lw $t2, -12(FP) +3: b 7f + lw $t2, -16(FP) +4: b 7f + lw $t2, -8(FP) +5: b 7f + lw $t2, -24(FP) +6: b 7f + move $t2, $t0 +7: sw $t1, -8($t4) # dst->a_type + j copy_auxv + sw $t2, -4($t4) # dst->a_un.a_val + /* Copy the final element. */ +8: sw $t1, -8($t4) # dst->a_type + sw $t2, -4($t4) # dst->a_un.a_val +finish: + /* Copy the string to its position in auxv + (src = $s3, dst = $t0). */ + add $t1, $s3, $s0 # src end + bgeu $s3, $t1, 2f # there already? + nop +1: lb $t2, ($s3) # c = *src + addi $s3, $s3, 1 # *src++ + addi $t0, $t0, 1 # dst++ + bltu $s3, $t1, 1b + sb $t2, -1($t0) # *(dst - 1) = c + /* Save variables. */ +2: move $s6, $t3 # new stack pointer + lw $t4, 4(FP) # secondary fd + lw $s1, (FP) # primary fd, delay slot, preserved li $t2, -1 # immediate -1 - beq $t0, $t2, .finish1 # secondary fd set? + beq $t4, $t2, finish1 # secondary fd set? li $v0, SYSCALL_close # SYS_close, delay slot - move $a0, $t0 # fd + move $a0, $t4 # fd syscall # syscall li $v0, SYSCALL_close # SYS_close -.finish1: +finish1: move $a0, $s1 # primary fd syscall # syscall li $v0, SYSCALL_prctl # SYS_prctl li $a0, 45 # PR_SET_FP_MODE - lw $a1, 28($s0) # fpu_mode + lw $a1, -28(FP) # fpu_mode move $a2, $zero # arg3 move $a3, $zero # arg4 SYSCALL(`$a2',`$a2',`$a2',`$a2') # syscall args syscall # syscall RESTORE() # restore sp -.jump: +jump: move $v0, $zero # rtld_fini - lw $t0, 4($s0) # entry + lw $t9, -4(FP) # entry move $sp, $s6 # restore stack pointer, delay slot - jr $t0 # enter - nop # delay slot + /* Clear at least one page's worth of stack. glibc on mipsel + copies certain fields from the stack to the `link_map' + structure representing ld.so, which are not subsequently + replaced if otherwise than zero. -.auxvtab: - .long 0 # 0 - .long 0 # 1 - .long 0 # 2 - .long 20 # 3 AT_PHDR - .long 12 # 4 AT_PHENT - .long 16 # 5 AT_PHNUM - .long 0 # 6 - .long 24 # 7 AT_BASE - .long 0 # 8 - .long 8 # 9 AT_ENTRY + XXX: report this glibc bug? */ + addi $v0, $sp, -4096 + and $v0, $v0, -4095 +1: sw $zero, ($v0) # copy 32 byte blocks + sw $zero, 4($v0) + sw $zero, 8($v0) + sw $zero, 12($v0) + sw $zero, 16($v0) + sw $zero, 20($v0) + sw $zero, 24($v0) + sw $zero, 28($v0) + addi $v0, $v0, 32 + sub $t0, $sp, $v0 # remainder + bge $t0, 32, 1b # test remainder + nop # copy 4 byte blocks + beqz $t0, 2f +1: addi $v0, $v0, 4 + bltu $v0, $sp, 1b + sw $zero, -4($v0) +2: jr $t9 # enter + nop # delay slot -.timespec: - .long 10 - .long 10 +## timespec: +## .long 10 +## .long 10 # Local Variables: # asm-comment-char: ?# -- 2.39.5