1 2/*--------------------------------------------------------------------*/ 3/*--- A minimal setjmp/longjmp implementation. m_libcsetjmp.c ---*/ 4/*--------------------------------------------------------------------*/ 5 6/* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2010-2013 Mozilla Inc 11 12 This program is free software; you can redistribute it and/or 13 modify it under the terms of the GNU General Public License as 14 published by the Free Software Foundation; either version 2 of the 15 License, or (at your option) any later version. 16 17 This program is distributed in the hope that it will be useful, but 18 WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 General Public License for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program; if not, write to the Free Software 24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 25 02111-1307, USA. 26 27 The GNU General Public License is contained in the file COPYING. 28*/ 29 30/* Contributed by Julian Seward <jseward@acm.org> */ 31 32 33#include "pub_core_basics.h" 34#include "pub_core_libcsetjmp.h" /* self */ 35 36 37/* See include/pub_tool_libcsetjmp.h for background and rationale. */ 38 39/* The alternative implementations are for ppc{32,64}-linux and 40 {amd64,x86}-{linux,darwin}. See #259977. That leaves only 41 {arm,s390x}-linux using the gcc builtins now. 42*/ 43 44/* ------------ ppc32-linux ------------ */ 45 46#if defined(VGP_ppc32_linux) 47 48__asm__( 49".text" "\n" 50"" "\n" 51".global VG_MINIMAL_SETJMP" "\n" // r3 = jmp_buf 52"VG_MINIMAL_SETJMP:" "\n" 53" stw 0, 0(3)" "\n" 54" stw 1, 4(3)" "\n" 55" stw 2, 8(3)" "\n" 56" stw 3, 12(3)" "\n" 57" stw 4, 16(3)" "\n" 58" stw 5, 20(3)" "\n" 59" stw 6, 24(3)" "\n" 60" stw 7, 28(3)" "\n" 61" stw 8, 32(3)" "\n" 62" stw 9, 36(3)" "\n" 63" stw 10, 40(3)" "\n" 64" stw 11, 44(3)" "\n" 65" stw 12, 48(3)" "\n" 66" stw 13, 52(3)" "\n" 67" stw 14, 56(3)" "\n" 68" stw 15, 60(3)" "\n" 69" stw 16, 64(3)" "\n" 70" stw 17, 68(3)" "\n" 71" stw 18, 72(3)" "\n" 72" stw 19, 76(3)" "\n" 73" stw 20, 80(3)" "\n" 74" stw 21, 84(3)" "\n" 75" stw 22, 88(3)" "\n" 76" stw 23, 92(3)" "\n" 77" stw 24, 96(3)" "\n" 78" stw 25, 100(3)" "\n" 79" stw 26, 104(3)" "\n" 80" stw 27, 108(3)" "\n" 81" stw 28, 112(3)" "\n" 82" stw 29, 116(3)" "\n" 83" stw 30, 120(3)" "\n" 84" stw 31, 124(3)" "\n" 85 // must use a caller-save register here as scratch, hence r4 86" mflr 4" "\n" 87" stw 4, 128(3)" "\n" 88" mfcr 4" "\n" 89" stw 4, 132(3)" "\n" 90" li 3, 0" "\n" 91" blr" "\n" 92"" "\n" 93 94 95".global VG_MINIMAL_LONGJMP" "\n" 96"VG_MINIMAL_LONGJMP:" "\n" // r3 = jmp_buf 97 // do r4 = 1 98 // and park it in the restore slot for r3 (the ret reg) 99" li 4, 1" "\n" 100" stw 4, 12(3)" "\n" 101 // restore everything except r3 102 // then r3 last of all 103 // then blr 104" lwz 0, 128(3)" "\n" 105" mtlr 0" "\n" 106" lwz 0, 132(3)" "\n" 107" mtcr 0" "\n" 108" lwz 0, 0(3)" "\n" 109" lwz 1, 4(3)" "\n" 110" lwz 2, 8(3)" "\n" 111 // r3 is done at the end 112" lwz 4, 16(3)" "\n" 113" lwz 5, 20(3)" "\n" 114" lwz 6, 24(3)" "\n" 115" lwz 7, 28(3)" "\n" 116" lwz 8, 32(3)" "\n" 117" lwz 9, 36(3)" "\n" 118" lwz 10, 40(3)" "\n" 119" lwz 11, 44(3)" "\n" 120" lwz 12, 48(3)" "\n" 121" lwz 13, 52(3)" "\n" 122" lwz 14, 56(3)" "\n" 123" lwz 15, 60(3)" "\n" 124" lwz 16, 64(3)" "\n" 125" lwz 17, 68(3)" "\n" 126" lwz 18, 72(3)" "\n" 127" lwz 19, 76(3)" "\n" 128" lwz 20, 80(3)" "\n" 129" lwz 21, 84(3)" "\n" 130" lwz 22, 88(3)" "\n" 131" lwz 23, 92(3)" "\n" 132" lwz 24, 96(3)" "\n" 133" lwz 25, 100(3)" "\n" 134" lwz 26, 104(3)" "\n" 135" lwz 27, 108(3)" "\n" 136" lwz 28, 112(3)" "\n" 137" lwz 29, 116(3)" "\n" 138" lwz 30, 120(3)" "\n" 139" lwz 31, 124(3)" "\n" 140" lwz 3, 12(3)" "\n" 141" blr" "\n" 142"" "\n" 143 144".previous" "\n" 145); 146 147#endif /* VGP_ppc32_linux */ 148 149 150/* ------------ ppc64-linux ------------ */ 151 152#if defined(VGP_ppc64_linux) 153 154__asm__( 155".section \".toc\",\"aw\"" "\n" 156 157".section \".text\"" "\n" 158".align 2" "\n" 159".p2align 4,,15" "\n" 160".globl VG_MINIMAL_SETJMP" "\n" 161 162".section \".opd\",\"aw\"" "\n" 163".align 3" "\n" 164"VG_MINIMAL_SETJMP:" "\n" 165".quad .L.VG_MINIMAL_SETJMP,.TOC.@tocbase,0" "\n" 166".previous" "\n" 167 168".type VG_MINIMAL_SETJMP, @function" "\n" 169".L.VG_MINIMAL_SETJMP:" "\n" 170" std 0, 0(3)" "\n" 171" std 1, 8(3)" "\n" 172" std 2, 16(3)" "\n" 173" std 3, 24(3)" "\n" 174" std 4, 32(3)" "\n" 175" std 5, 40(3)" "\n" 176" std 6, 48(3)" "\n" 177" std 7, 56(3)" "\n" 178" std 8, 64(3)" "\n" 179" std 9, 72(3)" "\n" 180" std 10, 80(3)" "\n" 181" std 11, 88(3)" "\n" 182" std 12, 96(3)" "\n" 183" std 13, 104(3)" "\n" 184" std 14, 112(3)" "\n" 185" std 15, 120(3)" "\n" 186" std 16, 128(3)" "\n" 187" std 17, 136(3)" "\n" 188" std 18, 144(3)" "\n" 189" std 19, 152(3)" "\n" 190" std 20, 160(3)" "\n" 191" std 21, 168(3)" "\n" 192" std 22, 176(3)" "\n" 193" std 23, 184(3)" "\n" 194" std 24, 192(3)" "\n" 195" std 25, 200(3)" "\n" 196" std 26, 208(3)" "\n" 197" std 27, 216(3)" "\n" 198" std 28, 224(3)" "\n" 199" std 29, 232(3)" "\n" 200" std 30, 240(3)" "\n" 201" std 31, 248(3)" "\n" 202 // must use a caller-save register here as scratch, hence r4 203" mflr 4" "\n" 204" std 4, 256(3)" "\n" 205" mfcr 4" "\n" 206" std 4, 264(3)" "\n" 207" li 3, 0" "\n" 208" blr" "\n" 209"" "\n" 210 211 212".globl VG_MINIMAL_LONGJMP" "\n" 213 214".section \".opd\",\"aw\"" "\n" 215".align 3" "\n" 216"VG_MINIMAL_LONGJMP:" "\n" 217".quad .L.VG_MINIMAL_LONGJMP,.TOC.@tocbase,0" "\n" 218".previous" "\n" 219 220".type VG_MINIMAL_LONGJMP, @function" "\n" 221".L.VG_MINIMAL_LONGJMP:" "\n" 222 // do r4 = 1 223 // and park it in the restore slot for r3 (the ret reg) 224" li 4, 1" "\n" 225" std 4, 24(3)" "\n" 226 // restore everything except r3 227 // then r3 last of all 228 // then blr 229" ld 0, 256(3)" "\n" 230" mtlr 0" "\n" 231" ld 0, 264(3)" "\n" 232" mtcr 0" "\n" 233" ld 0, 0(3)" "\n" 234" ld 1, 8(3)" "\n" 235" ld 2, 16(3)" "\n" 236 // r3 is done at the end 237" ld 4, 32(3)" "\n" 238" ld 5, 40(3)" "\n" 239" ld 6, 48(3)" "\n" 240" ld 7, 56(3)" "\n" 241" ld 8, 64(3)" "\n" 242" ld 9, 72(3)" "\n" 243" ld 10, 80(3)" "\n" 244" ld 11, 88(3)" "\n" 245" ld 12, 96(3)" "\n" 246" ld 13, 104(3)" "\n" 247" ld 14, 112(3)" "\n" 248" ld 15, 120(3)" "\n" 249" ld 16, 128(3)" "\n" 250" ld 17, 136(3)" "\n" 251" ld 18, 144(3)" "\n" 252" ld 19, 152(3)" "\n" 253" ld 20, 160(3)" "\n" 254" ld 21, 168(3)" "\n" 255" ld 22, 176(3)" "\n" 256" ld 23, 184(3)" "\n" 257" ld 24, 192(3)" "\n" 258" ld 25, 200(3)" "\n" 259" ld 26, 208(3)" "\n" 260" ld 27, 216(3)" "\n" 261" ld 28, 224(3)" "\n" 262" ld 29, 232(3)" "\n" 263" ld 30, 240(3)" "\n" 264" ld 31, 248(3)" "\n" 265" ld 3, 24(3)" "\n" 266" blr" "\n" 267"" "\n" 268 269".previous" "\n" 270".previous" "\n" 271); 272 273#endif /* VGP_ppc64_linux */ 274 275 276/* ------------ amd64-{linux,darwin} ------------ */ 277 278#if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) 279 280__asm__( 281".text" "\n" 282"" "\n" 283 284#if defined(VGP_amd64_linux) 285".global VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf 286"VG_MINIMAL_SETJMP:" "\n" 287 288#elif defined(VGP_amd64_darwin) 289".globl _VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf 290"_VG_MINIMAL_SETJMP:" "\n" 291 292#else 293# error "Huh?" 294#endif 295 296" movq %rax, 0(%rdi)" "\n" 297" movq %rbx, 8(%rdi)" "\n" 298" movq %rcx, 16(%rdi)" "\n" 299" movq %rdx, 24(%rdi)" "\n" 300" movq %rdi, 32(%rdi)" "\n" 301" movq %rsi, 40(%rdi)" "\n" 302" movq %rbp, 48(%rdi)" "\n" 303" movq %rsp, 56(%rdi)" "\n" 304" movq %r8, 64(%rdi)" "\n" 305" movq %r9, 72(%rdi)" "\n" 306" movq %r10, 80(%rdi)" "\n" 307" movq %r11, 88(%rdi)" "\n" 308" movq %r12, 96(%rdi)" "\n" 309" movq %r13, 104(%rdi)" "\n" 310" movq %r14, 112(%rdi)" "\n" 311" movq %r15, 120(%rdi)" "\n" 312 // store the return address 313" movq 0(%rsp), %rax" "\n" 314" movq %rax, 128(%rdi)" "\n" 315 // and return zero 316" movq $0, %rax" "\n" 317" ret" "\n" 318"" "\n" 319 320 321#if defined(VGP_amd64_linux) 322".global VG_MINIMAL_LONGJMP" "\n" 323"VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf 324 325#elif defined(VGP_amd64_darwin) 326".globl _VG_MINIMAL_LONGJMP" "\n" 327"_VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf 328 329#else 330# error "Huh?" 331#endif 332 // skip restoring rax; it's pointless 333" movq 8(%rdi), %rbx" "\n" 334" movq 16(%rdi), %rcx" "\n" 335" movq 24(%rdi), %rdx" "\n" 336 // defer restoring rdi; we still need it 337" movq 40(%rdi), %rsi" "\n" 338" movq 48(%rdi), %rbp" "\n" 339" movq 56(%rdi), %rsp" "\n" 340" movq 64(%rdi), %r8" "\n" 341" movq 72(%rdi), %r9" "\n" 342" movq 80(%rdi), %r10" "\n" 343" movq 88(%rdi), %r11" "\n" 344" movq 96(%rdi), %r12" "\n" 345" movq 104(%rdi), %r13" "\n" 346" movq 112(%rdi), %r14" "\n" 347" movq 120(%rdi), %r15" "\n" 348 // restore the return address 349" movq 128(%rdi), %rax" "\n" 350 // restore rdi; this is the last use 351" movq 32(%rdi), %rdi" "\n" 352 // make %rsp look like we really did a return 353" addq $8, %rsp" "\n" 354 // continue at RA of original call. Note: this is a 355 // nasty trick. We assume that %rax is nonzero, and so the 356 // caller can differentiate this case from the normal _SETJMP 357 // return case. If the return address ever is zero, then 358 // we're hosed; but that seems pretty unlikely given that it 359 // would mean we'd be executing at the wraparound point of the 360 // address space. 361" jmp *%rax" "\n" 362"" "\n" 363 364#if !defined(VGP_amd64_darwin) 365".previous" "\n" 366#endif 367); 368 369#endif /* VGP_amd64_linux || VGP_amd64_darwin */ 370 371 372/* ------------ x86-{linux,darwin} ------------ */ 373 374#if defined(VGP_x86_linux) || defined(VGP_x86_darwin) 375 376__asm__( 377".text" "\n" 378"" "\n" 379 380#if defined(VGP_x86_linux) 381".global VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf 382"VG_MINIMAL_SETJMP:" "\n" 383 384#elif defined(VGP_x86_darwin) 385".globl _VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf 386"_VG_MINIMAL_SETJMP:" "\n" 387 388#else 389# error "Huh?" 390#endif 391 392" movl %eax, 0(%eax)" "\n" 393" movl %ebx, 4(%eax)" "\n" 394" movl %ecx, 8(%eax)" "\n" 395" movl %edx, 12(%eax)" "\n" 396" movl %edi, 16(%eax)" "\n" 397" movl %esi, 20(%eax)" "\n" 398" movl %ebp, 24(%eax)" "\n" 399" movl %esp, 28(%eax)" "\n" 400 // store the return address 401" movl 0(%esp), %ebx" "\n" 402" movl %ebx, 32(%eax)" "\n" 403 // un-trash ebx (necessary? i don't know) 404" movl 4(%eax), %ebx" "\n" 405 // and return zero 406" movl $0, %eax" "\n" 407" ret" "\n" 408"" "\n" 409 410 411#if defined(VGP_x86_linux) 412".global VG_MINIMAL_LONGJMP" "\n" 413"VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf 414 415#elif defined(VGP_x86_darwin) 416".globl _VG_MINIMAL_LONGJMP" "\n" 417"_VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf 418 419#else 420# error "Huh?" 421#endif 422 423 // skip restoring eax; it's pointless 424" movl 4(%eax), %ebx" "\n" 425" movl 8(%eax), %ecx" "\n" 426" movl 12(%eax), %edx" "\n" 427" movl 16(%eax), %edi" "\n" 428" movl 20(%eax), %esi" "\n" 429" movl 24(%eax), %ebp" "\n" 430" movl 28(%eax), %esp" "\n" 431 // restore the return address 432" movl 32(%eax), %eax" "\n" 433 // make %esp look like we really did a return 434" addl $4, %esp" "\n" 435 // continue at RA of original call. Same zero-vs-nonzero 436 // trick/assumption as documented for the amd64-linux case. 437" jmp *%eax" "\n" 438"" "\n" 439 440#if !defined(VGP_x86_darwin) 441".previous" "\n" 442#endif 443); 444 445#endif /* VGP_x86_linux || VGP_x86_darwin */ 446 447#if defined(VGP_mips32_linux) 448 449__asm__( 450".text \n\t" 451".globl VG_MINIMAL_SETJMP; \n\t" 452".align 2; \n\t" 453"VG_MINIMAL_SETJMP: \n\t" /* a0 = jmp_buf */ 454" sw $s0, 0($a0) \n\t" /* Save registers s0-s7. */ 455" sw $s1, 4($a0) \n\t" 456" sw $s2, 8($a0) \n\t" 457" sw $s3, 12($a0) \n\t" 458" sw $s4, 16($a0) \n\t" 459" sw $s5, 20($a0) \n\t" 460" sw $s6, 24($a0) \n\t" 461" sw $s7, 28($a0) \n\t" 462" sw $s8, 32($a0) \n\t" /* Frame pointer. */ 463" sw $ra, 36($a0) \n\t" /* Return address. */ 464" sw $gp, 40($a0) \n\t" /* Global data pointer. */ 465" sw $sp, 44($a0) \n\t" /* Stack pointer. */ 466 467" move $v0, $zero \n\t" /* Return zero. */ 468" j $ra \n\t" 469" nop \n\t" 470".previous \n\t" 471" \n\t" 472".globl VG_MINIMAL_LONGJMP; \n\t" 473".align 2; \n\t" 474"VG_MINIMAL_LONGJMP: \n\t" /* a0 = jmp_buf */ 475" lw $s0, 0($a0) \n\t" /* Restore registers s0-s7. */ 476" lw $s1, 4($a0) \n\t" 477" lw $s2, 8($a0) \n\t" 478" lw $s3, 12($a0) \n\t" 479" lw $s4, 16($a0) \n\t" 480" lw $s5, 20($a0) \n\t" 481" lw $s6, 24($a0) \n\t" 482" lw $s7, 28($a0) \n\t" 483" lw $s8, 32($a0) \n\t" /* Frame pointer. */ 484" lw $ra, 36($a0) \n\t" /* Return address. */ 485" lw $gp, 40($a0) \n\t" /* Global data pointer. */ 486" lw $sp, 44($a0) \n\t" /* Stack pointer. */ 487 488/* Checking whether second argument is zero. */ 489" bnez $a1, 1f \n\t" 490" nop \n\t" 491" addi $a1, $a1, 1 \n\t" /* We must return 1 if val=0. */ 492"1: \n\t" 493" move $v0, $a1 \n\t" /* Return value of second argument. */ 494" j $ra \n\t" 495" nop \n\t" 496".previous \n\t" 497); 498#endif /* VGP_mips32_linux */ 499 500/*--------------------------------------------------------------------*/ 501/*--- end ---*/ 502/*--------------------------------------------------------------------*/ 503