summaryrefslogtreecommitdiff
path: root/src/thread/mips
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2016-02-04 23:01:03 +0000
committerRich Felker <dalias@aerifal.cx>2016-02-04 23:01:03 +0000
commit756c8af8589265e99e454fe3adcda1d0bc5e1963 (patch)
tree8de0abc5bc1ed79f72f4da99b795cd0333416e31 /src/thread/mips
parentaecda35373511c5bf02c0f708bd262adb1a09287 (diff)
downloadmusl-756c8af8589265e99e454fe3adcda1d0bc5e1963.tar.gz
in mips cancellable syscall asm, don't assume gp register is valid
the old __cp_cancel code path loaded the address of __cancel from the GOT using the $gp register, which happened to be set to point to the correct GOT by the calling C function, but there is no ABI requirement that this happen. instead, go the roundabout way and compute the address of __cancel via pc-relative and gp-relative addressing starting with a fake return address generated by a bal instruction, which is the same trick crt1 uses to bootstrap.
Diffstat (limited to 'src/thread/mips')
-rw-r--r--src/thread/mips/syscall_cp.s15
1 files changed, 13 insertions, 2 deletions
diff --git a/src/thread/mips/syscall_cp.s b/src/thread/mips/syscall_cp.s
index 8f76d40e..b01a5704 100644
--- a/src/thread/mips/syscall_cp.s
+++ b/src/thread/mips/syscall_cp.s
@@ -9,6 +9,9 @@
.global __cp_cancel
.hidden __cp_cancel
.type __cp_cancel,@function
+.global __cp_cancel_data
+.hidden __cp_cancel_data
+.type __cp_cancel_data,@function
.hidden __cancel
.global __syscall_cp_asm
.hidden __syscall_cp_asm
@@ -40,7 +43,15 @@ __cp_end:
nop
__cp_cancel:
+ move $2, $ra
+ bal 1f
addu $sp, $sp, 32
- lw $25, %call16(__cancel)($gp)
+__cp_cancel_data:
+ .gpword __cp_cancel_data
+ .gpword __cancel
+1: lw $3, ($ra)
+ subu $3, $ra, $3
+ lw $25, 4($ra)
+ addu $25, $25, $3
jr $25
- nop
+ move $ra, $2