2 /*--------------------------------------------------------------------*/
3 /*--- A minimal setjmp/longjmp implementation. m_libcsetjmp.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2010-2017 Mozilla Inc
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.
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.
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
27 The GNU General Public License is contained in the file COPYING.
30 /* Contributed by Julian Seward <jseward@acm.org> */
32 /* This file must be compiled without link time optimisation, as otherwise
33 the asm functions below become undefined references at link time for
36 #include "pub_core_basics.h"
37 #include "pub_core_libcsetjmp.h" /* self */
39 /* See include/pub_tool_libcsetjmp.h for background and rationale. */
41 /* The alternative implementations are for ppc{32,64}-linux and
42 {amd64,x86}-{linux,darwin,solaris}. See #259977. That leaves only
43 {arm,s390x}-linux using the gcc builtins now.
46 /* ------------ ppc32-linux ------------ */
48 #if defined(VGP_ppc32_linux)
53 ".global VG_MINIMAL_SETJMP" "\n" // r3 = jmp_buf
54 "VG_MINIMAL_SETJMP:" "\n"
80 " stw 25, 100(3)" "\n"
81 " stw 26, 104(3)" "\n"
82 " stw 27, 108(3)" "\n"
83 " stw 28, 112(3)" "\n"
84 " stw 29, 116(3)" "\n"
85 " stw 30, 120(3)" "\n"
86 " stw 31, 124(3)" "\n"
87 // must use a caller-save register here as scratch, hence r4
97 ".global VG_MINIMAL_LONGJMP" "\n"
98 "VG_MINIMAL_LONGJMP:" "\n" // r3 = jmp_buf
100 // and park it in the restore slot for r3 (the ret reg)
103 // restore everything except r3
104 // then r3 last of all
106 " lwz 0, 128(3)" "\n"
108 " lwz 0, 132(3)" "\n"
113 // r3 is done at the end
120 " lwz 10, 40(3)" "\n"
121 " lwz 11, 44(3)" "\n"
122 " lwz 12, 48(3)" "\n"
123 " lwz 13, 52(3)" "\n"
124 " lwz 14, 56(3)" "\n"
125 " lwz 15, 60(3)" "\n"
126 " lwz 16, 64(3)" "\n"
127 " lwz 17, 68(3)" "\n"
128 " lwz 18, 72(3)" "\n"
129 " lwz 19, 76(3)" "\n"
130 " lwz 20, 80(3)" "\n"
131 " lwz 21, 84(3)" "\n"
132 " lwz 22, 88(3)" "\n"
133 " lwz 23, 92(3)" "\n"
134 " lwz 24, 96(3)" "\n"
135 " lwz 25, 100(3)" "\n"
136 " lwz 26, 104(3)" "\n"
137 " lwz 27, 108(3)" "\n"
138 " lwz 28, 112(3)" "\n"
139 " lwz 29, 116(3)" "\n"
140 " lwz 30, 120(3)" "\n"
141 " lwz 31, 124(3)" "\n"
149 #endif /* VGP_ppc32_linux */
152 /* ------------ ppc64-linux ------------ */
154 #if defined(VGP_ppc64be_linux)
157 ".section \".toc\",\"aw\"" "\n"
159 ".section \".text\"" "\n"
161 ".p2align 4,,15" "\n"
162 ".globl VG_MINIMAL_SETJMP" "\n"
163 ".section \".opd\",\"aw\"" "\n"
165 "VG_MINIMAL_SETJMP:" "\n"
166 ".quad .L.VG_MINIMAL_SETJMP,.TOC.@tocbase,0" "\n"
169 ".type VG_MINIMAL_SETJMP, @function" "\n"
170 ".L.VG_MINIMAL_SETJMP:" "\n"
181 " std 10, 80(3)" "\n"
182 " std 11, 88(3)" "\n"
183 " std 12, 96(3)" "\n"
184 " std 13, 104(3)" "\n"
185 " std 14, 112(3)" "\n"
186 " std 15, 120(3)" "\n"
187 " std 16, 128(3)" "\n"
188 " std 17, 136(3)" "\n"
189 " std 18, 144(3)" "\n"
190 " std 19, 152(3)" "\n"
191 " std 20, 160(3)" "\n"
192 " std 21, 168(3)" "\n"
193 " std 22, 176(3)" "\n"
194 " std 23, 184(3)" "\n"
195 " std 24, 192(3)" "\n"
196 " std 25, 200(3)" "\n"
197 " std 26, 208(3)" "\n"
198 " std 27, 216(3)" "\n"
199 " std 28, 224(3)" "\n"
200 " std 29, 232(3)" "\n"
201 " std 30, 240(3)" "\n"
202 " std 31, 248(3)" "\n"
203 // must use a caller-save register here as scratch, hence r4
205 " std 4, 256(3)" "\n"
207 " std 4, 264(3)" "\n"
213 ".globl VG_MINIMAL_LONGJMP" "\n"
215 ".section \".opd\",\"aw\"" "\n"
217 "VG_MINIMAL_LONGJMP:" "\n"
218 ".quad .L.VG_MINIMAL_LONGJMP,.TOC.@tocbase,0" "\n"
221 ".type VG_MINIMAL_LONGJMP, @function" "\n"
222 ".L.VG_MINIMAL_LONGJMP:" "\n"
224 // and park it in the restore slot for r3 (the ret reg)
227 // restore everything except r3
228 // then r3 last of all
237 // r3 is done at the end
247 " ld 13, 104(3)" "\n"
248 " ld 14, 112(3)" "\n"
249 " ld 15, 120(3)" "\n"
250 " ld 16, 128(3)" "\n"
251 " ld 17, 136(3)" "\n"
252 " ld 18, 144(3)" "\n"
253 " ld 19, 152(3)" "\n"
254 " ld 20, 160(3)" "\n"
255 " ld 21, 168(3)" "\n"
256 " ld 22, 176(3)" "\n"
257 " ld 23, 184(3)" "\n"
258 " ld 24, 192(3)" "\n"
259 " ld 25, 200(3)" "\n"
260 " ld 26, 208(3)" "\n"
261 " ld 27, 216(3)" "\n"
262 " ld 28, 224(3)" "\n"
263 " ld 29, 232(3)" "\n"
264 " ld 30, 240(3)" "\n"
265 " ld 31, 248(3)" "\n"
273 #elif defined(VGP_ppc64le_linux)
275 ".section \".toc\",\"aw\"" "\n"
277 ".section \".text\"" "\n"
279 ".p2align 4,,15" "\n"
280 ".globl VG_MINIMAL_SETJMP" "\n"
281 ".type VG_MINIMAL_SETJMP,@function" "\n"
282 "VG_MINIMAL_SETJMP:" "\n"
283 " .localentry VG_MINIMAL_SETJMP, .-VG_MINIMAL_SETJMP" "\n"
294 " std 10, 80(3)" "\n"
295 " std 11, 88(3)" "\n"
296 " std 12, 96(3)" "\n"
297 " std 13, 104(3)" "\n"
298 " std 14, 112(3)" "\n"
299 " std 15, 120(3)" "\n"
300 " std 16, 128(3)" "\n"
301 " std 17, 136(3)" "\n"
302 " std 18, 144(3)" "\n"
303 " std 19, 152(3)" "\n"
304 " std 20, 160(3)" "\n"
305 " std 21, 168(3)" "\n"
306 " std 22, 176(3)" "\n"
307 " std 23, 184(3)" "\n"
308 " std 24, 192(3)" "\n"
309 " std 25, 200(3)" "\n"
310 " std 26, 208(3)" "\n"
311 " std 27, 216(3)" "\n"
312 " std 28, 224(3)" "\n"
313 " std 29, 232(3)" "\n"
314 " std 30, 240(3)" "\n"
315 " std 31, 248(3)" "\n"
316 // must use a caller-save register here as scratch, hence r4
318 " std 4, 256(3)" "\n"
320 " std 4, 264(3)" "\n"
326 ".globl VG_MINIMAL_LONGJMP" "\n"
327 ".type VG_MINIMAL_LONGJMP, @function" "\n"
328 "VG_MINIMAL_LONGJMP:" "\n"
329 " .localentry VG_MINIMAL_LONGJMP, .-VG_MINIMAL_LONGJMP" "\n"
331 // and park it in the restore slot for r3 (the ret reg)
334 // restore everything except r3
335 // then r3 last of all
344 // r3 is done at the end
354 " ld 13, 104(3)" "\n"
355 " ld 14, 112(3)" "\n"
356 " ld 15, 120(3)" "\n"
357 " ld 16, 128(3)" "\n"
358 " ld 17, 136(3)" "\n"
359 " ld 18, 144(3)" "\n"
360 " ld 19, 152(3)" "\n"
361 " ld 20, 160(3)" "\n"
362 " ld 21, 168(3)" "\n"
363 " ld 22, 176(3)" "\n"
364 " ld 23, 184(3)" "\n"
365 " ld 24, 192(3)" "\n"
366 " ld 25, 200(3)" "\n"
367 " ld 26, 208(3)" "\n"
368 " ld 27, 216(3)" "\n"
369 " ld 28, 224(3)" "\n"
370 " ld 29, 232(3)" "\n"
371 " ld 30, 240(3)" "\n"
372 " ld 31, 248(3)" "\n"
379 #endif /* VGP_ppc64be_linux */
382 /* -------- amd64-{linux,darwin,solaris} -------- */
384 #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) || \
385 defined(VGP_amd64_solaris)
391 #if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris)
392 ".global VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf
393 "VG_MINIMAL_SETJMP:" "\n"
395 #elif defined(VGP_amd64_darwin)
396 ".globl _VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf
397 "_VG_MINIMAL_SETJMP:" "\n"
403 " movq %rax, 0(%rdi)" "\n"
404 " movq %rbx, 8(%rdi)" "\n"
405 " movq %rcx, 16(%rdi)" "\n"
406 " movq %rdx, 24(%rdi)" "\n"
407 " movq %rdi, 32(%rdi)" "\n"
408 " movq %rsi, 40(%rdi)" "\n"
409 " movq %rbp, 48(%rdi)" "\n"
410 " movq %rsp, 56(%rdi)" "\n"
411 " movq %r8, 64(%rdi)" "\n"
412 " movq %r9, 72(%rdi)" "\n"
413 " movq %r10, 80(%rdi)" "\n"
414 " movq %r11, 88(%rdi)" "\n"
415 " movq %r12, 96(%rdi)" "\n"
416 " movq %r13, 104(%rdi)" "\n"
417 " movq %r14, 112(%rdi)" "\n"
418 " movq %r15, 120(%rdi)" "\n"
419 // store the return address
420 " movq 0(%rsp), %rax" "\n"
421 " movq %rax, 128(%rdi)" "\n"
423 " movq $0, %rax" "\n"
428 #if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris)
429 ".global VG_MINIMAL_LONGJMP" "\n"
430 "VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf
432 #elif defined(VGP_amd64_darwin)
433 ".globl _VG_MINIMAL_LONGJMP" "\n"
434 "_VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf
439 // skip restoring rax; it's pointless
440 " movq 8(%rdi), %rbx" "\n"
441 " movq 16(%rdi), %rcx" "\n"
442 " movq 24(%rdi), %rdx" "\n"
443 // defer restoring rdi; we still need it
444 " movq 40(%rdi), %rsi" "\n"
445 " movq 48(%rdi), %rbp" "\n"
446 " movq 56(%rdi), %rsp" "\n"
447 " movq 64(%rdi), %r8" "\n"
448 " movq 72(%rdi), %r9" "\n"
449 " movq 80(%rdi), %r10" "\n"
450 " movq 88(%rdi), %r11" "\n"
451 " movq 96(%rdi), %r12" "\n"
452 " movq 104(%rdi), %r13" "\n"
453 " movq 112(%rdi), %r14" "\n"
454 " movq 120(%rdi), %r15" "\n"
455 // restore the return address
456 " movq 128(%rdi), %rax" "\n"
457 // restore rdi; this is the last use
458 " movq 32(%rdi), %rdi" "\n"
459 // make %rsp look like we really did a return
460 " addq $8, %rsp" "\n"
461 // continue at RA of original call. Note: this is a
462 // nasty trick. We assume that %rax is nonzero, and so the
463 // caller can differentiate this case from the normal _SETJMP
464 // return case. If the return address ever is zero, then
465 // we're hosed; but that seems pretty unlikely given that it
466 // would mean we'd be executing at the wraparound point of the
471 #if !defined(VGP_amd64_darwin)
476 #endif /* VGP_amd64_linux || VGP_amd64_darwin || VGP_amd64_solaris */
479 /* -------- x86-{linux,darwin,solaris} -------- */
481 #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) || \
482 defined(VGP_x86_solaris)
488 #if defined(VGP_x86_linux) || defined(VGP_x86_solaris)
489 ".global VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf
490 "VG_MINIMAL_SETJMP:" "\n"
492 #elif defined(VGP_x86_darwin)
493 ".globl _VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf
494 "_VG_MINIMAL_SETJMP:" "\n"
500 " movl %eax, 0(%eax)" "\n"
501 " movl %ebx, 4(%eax)" "\n"
502 " movl %ecx, 8(%eax)" "\n"
503 " movl %edx, 12(%eax)" "\n"
504 " movl %edi, 16(%eax)" "\n"
505 " movl %esi, 20(%eax)" "\n"
506 " movl %ebp, 24(%eax)" "\n"
507 " movl %esp, 28(%eax)" "\n"
508 // store the return address
509 " movl 0(%esp), %ebx" "\n"
510 " movl %ebx, 32(%eax)" "\n"
511 // un-trash ebx (necessary? i don't know)
512 " movl 4(%eax), %ebx" "\n"
514 " movl $0, %eax" "\n"
519 #if defined(VGP_x86_linux) || defined(VGP_x86_solaris)
520 ".global VG_MINIMAL_LONGJMP" "\n"
521 "VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf
523 #elif defined(VGP_x86_darwin)
524 ".globl _VG_MINIMAL_LONGJMP" "\n"
525 "_VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf
531 // skip restoring eax; it's pointless
532 " movl 4(%eax), %ebx" "\n"
533 " movl 8(%eax), %ecx" "\n"
534 " movl 12(%eax), %edx" "\n"
535 " movl 16(%eax), %edi" "\n"
536 " movl 20(%eax), %esi" "\n"
537 " movl 24(%eax), %ebp" "\n"
538 " movl 28(%eax), %esp" "\n"
539 // restore the return address
540 " movl 32(%eax), %eax" "\n"
541 // make %esp look like we really did a return
542 " addl $4, %esp" "\n"
543 // continue at RA of original call. Same zero-vs-nonzero
544 // trick/assumption as documented for the amd64-linux case.
548 #if !defined(VGP_x86_darwin)
553 #endif /* VGP_x86_linux || VGP_x86_darwin || VGP_x86_solaris */
555 #if defined(VGP_mips32_linux)
559 ".globl VG_MINIMAL_SETJMP; \n\t"
561 ".set noreorder \n\t"
562 "VG_MINIMAL_SETJMP: \n\t"
563 #if defined(__mips_hard_float)
564 " sdc1 $f20, 56($a0) \n\t"
565 " sdc1 $f22, 64($a0) \n\t"
566 " sdc1 $f24, 72($a0) \n\t"
567 " sdc1 $f26, 80($a0) \n\t"
568 " sdc1 $f28, 88($a0) \n\t"
569 " sdc1 $f30, 96($a0) \n\t"
571 " sw $gp, 44($a0) \n\t"
572 " sw $s0, 8($a0) \n\t"
573 " sw $s1, 12($a0) \n\t"
574 " sw $s2, 16($a0) \n\t"
575 " sw $s3, 20($a0) \n\t"
576 " sw $s4, 24($a0) \n\t"
577 " sw $s5, 28($a0) \n\t"
578 " sw $s6, 32($a0) \n\t"
579 " sw $s7, 36($a0) \n\t"
580 " sw $ra, 0($a0) \n\t"
581 " sw $sp, 4($a0) \n\t"
582 " sw $fp, 40($a0) \n\t"
584 " move $v0, $zero \n\t"
589 ".globl VG_MINIMAL_LONGJMP; \n\t"
591 ".set noreorder \n\t"
592 "VG_MINIMAL_LONGJMP: \n\t"
593 #if defined(__mips_hard_float)
594 " ldc1 $f20, 56($a0) \n\t"
595 " ldc1 $f22, 64($a0) \n\t"
596 " ldc1 $f24, 72($a0) \n\t"
597 " ldc1 $f26, 80($a0) \n\t"
598 " ldc1 $f28, 88($a0) \n\t"
599 " ldc1 $f30, 96($a0) \n\t"
601 " lw $gp, 44($a0) \n\t"
602 " lw $s0, 8($a0) \n\t"
603 " lw $s1, 12($a0) \n\t"
604 " lw $s2, 16($a0) \n\t"
605 " lw $s3, 20($a0) \n\t"
606 " lw $s4, 24($a0) \n\t"
607 " lw $s5, 28($a0) \n\t"
608 " lw $s6, 32($a0) \n\t"
609 " lw $s7, 36($a0) \n\t"
610 " lw $ra, 0($a0) \n\t"
611 " lw $sp, 4($a0) \n\t"
613 " lw $fp, 40($a0) \n\t"
614 " addiu $a1, $a1, 1 \n\t"
617 " move $v0, $a1 \n\t"
621 #endif /* VGP_mips32_linux */
623 #if defined(VGP_mips64_linux)
627 ".globl VG_MINIMAL_SETJMP; \n\t"
629 ".set noreorder \n\t"
630 "VG_MINIMAL_SETJMP: \n\t"
631 #if defined(__mips_hard_float)
632 " sdc1 $f24, 104($a0) \n\t"
633 " sdc1 $f25, 112($a0) \n\t"
634 " sdc1 $f26, 120($a0) \n\t"
635 " sdc1 $f27, 128($a0) \n\t"
636 " sdc1 $f28, 136($a0) \n\t"
637 " sdc1 $f29, 144($a0) \n\t"
638 " sdc1 $f30, 152($a0) \n\t"
639 " sdc1 $f31, 160($a0) \n\t"
641 " sd $gp, 88($a0) \n\t"
642 " sd $s0, 16($a0) \n\t"
643 " sd $s1, 24($a0) \n\t"
644 " sd $s2, 32($a0) \n\t"
645 " sd $s3, 40($a0) \n\t"
646 " sd $s4, 48($a0) \n\t"
647 " sd $s5, 56($a0) \n\t"
648 " sd $s6, 64($a0) \n\t"
649 " sd $s7, 72($a0) \n\t"
650 " sd $ra, 0($a0) \n\t"
651 " sd $sp, 8($a0) \n\t"
652 " sd $fp, 80($a0) \n\t"
654 " move $v0, $zero \n\t"
659 ".globl VG_MINIMAL_LONGJMP; \n\t"
661 ".set noreorder \n\t"
662 "VG_MINIMAL_LONGJMP: \n\t"
663 #if defined(__mips_hard_float)
664 " ldc1 $f24, 104($a0) \n\t"
665 " ldc1 $f25, 112($a0) \n\t"
666 " ldc1 $f26, 120($a0) \n\t"
667 " ldc1 $f27, 128($a0) \n\t"
668 " ldc1 $f28, 136($a0) \n\t"
669 " ldc1 $f29, 144($a0) \n\t"
670 " ldc1 $f30, 152($a0) \n\t"
671 " ldc1 $f31, 160($a0) \n\t"
673 " ld $gp, 88($a0) \n\t"
674 " ld $s0, 16($a0) \n\t"
675 " ld $s1, 24($a0) \n\t"
676 " ld $s2, 32($a0) \n\t"
677 " ld $s3, 40($a0) \n\t"
678 " ld $s4, 48($a0) \n\t"
679 " ld $s5, 56($a0) \n\t"
680 " ld $s6, 64($a0) \n\t"
681 " ld $s7, 72($a0) \n\t"
682 " ld $ra, 0($a0) \n\t"
683 " ld $sp, 8($a0) \n\t"
685 " ld $fp, 80($a0) \n\t"
686 " daddiu $a1, $a1, 1 \n\t"
689 " move $v0, $a1 \n\t"
693 #endif /* VGP_mips64_linux */
694 /*--------------------------------------------------------------------*/
696 /*--------------------------------------------------------------------*/