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
+ /* 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.
+
+ 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
-.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
-
-.timespec:
- .long 10
- .long 10
+## timespec:
+## .long 10
+## .long 10
# Local Variables:
# asm-comment-char: ?#