diff options
author | Rich Felker <dalias@aerifal.cx> | 2016-02-04 23:01:03 +0000 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2016-02-04 23:01:03 +0000 |
commit | 756c8af8589265e99e454fe3adcda1d0bc5e1963 (patch) | |
tree | 8de0abc5bc1ed79f72f4da99b795cd0333416e31 /src | |
parent | aecda35373511c5bf02c0f708bd262adb1a09287 (diff) | |
download | musl-756c8af8589265e99e454fe3adcda1d0bc5e1963.tar.gz musl-756c8af8589265e99e454fe3adcda1d0bc5e1963.tar.xz musl-756c8af8589265e99e454fe3adcda1d0bc5e1963.zip |
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')
-rw-r--r-- | src/thread/mips/syscall_cp.s | 15 |
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 |