in mips cancellable syscall asm, don't assume gp register is valid
authorRich Felker <dalias@aerifal.cx>
Thu, 4 Feb 2016 23:01:03 +0000 (23:01 +0000)
committerRich Felker <dalias@aerifal.cx>
Thu, 4 Feb 2016 23:01:03 +0000 (23:01 +0000)
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.

src/thread/mips/syscall_cp.s

index 8f76d40e1ebf2976f4139caaf735f781e098e50a..b01a570402b8aa94652becdf5c342d2ac94c9c67 100644 (file)
@@ -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