blob: 5b72182a8530b5b4ff669fe4cc05ac2df94f9ebe [file] [log] [blame]
sewardj6c591e12011-04-11 16:17:51 +00001
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
sewardj0f157dd2013-10-18 14:27:36 +000010 Copyright (C) 2010-2013 Mozilla Inc
sewardj6c591e12011-04-11 16:17:51 +000011
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
sewardjda91ee72011-09-29 18:29:41 +000039/* 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*/
sewardj97d3ebb2011-04-11 18:36:34 +000043
sewardj2a88a012011-04-11 21:26:27 +000044/* ------------ ppc32-linux ------------ */
45
sewardj97d3ebb2011-04-11 18:36:34 +000046#if defined(VGP_ppc32_linux)
47
48__asm__(
49".text" "\n"
sewardj2a88a012011-04-11 21:26:27 +000050"" "\n"
sewardj97d3ebb2011-04-11 18:36:34 +000051".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"
sewardj2a88a012011-04-11 21:26:27 +000092"" "\n"
sewardj97d3ebb2011-04-11 18:36:34 +000093
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"
sewardj2a88a012011-04-11 21:26:27 +0000142"" "\n"
sewardj97d3ebb2011-04-11 18:36:34 +0000143
144".previous" "\n"
145);
146
147#endif /* VGP_ppc32_linux */
sewardj6c591e12011-04-11 16:17:51 +0000148
149
sewardj2a88a012011-04-11 21:26:27 +0000150/* ------------ 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
sewardj2a88a012011-04-11 21:26:27 +0000273#endif /* VGP_ppc64_linux */
274
sewardjfc824cb2011-09-29 17:33:58 +0000275
sewardjda91ee72011-09-29 18:29:41 +0000276/* ------------ amd64-{linux,darwin} ------------ */
sewardjfc824cb2011-09-29 17:33:58 +0000277
sewardjda91ee72011-09-29 18:29:41 +0000278#if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
sewardjfc824cb2011-09-29 17:33:58 +0000279
280__asm__(
281".text" "\n"
282"" "\n"
sewardjda91ee72011-09-29 18:29:41 +0000283
284#if defined(VGP_amd64_linux)
sewardjfc824cb2011-09-29 17:33:58 +0000285".global VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf
286"VG_MINIMAL_SETJMP:" "\n"
sewardjda91ee72011-09-29 18:29:41 +0000287
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
sewardjfc824cb2011-09-29 17:33:58 +0000296" 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
sewardjda91ee72011-09-29 18:29:41 +0000320
321#if defined(VGP_amd64_linux)
322".global VG_MINIMAL_LONGJMP" "\n"
sewardjfc824cb2011-09-29 17:33:58 +0000323"VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf
sewardjda91ee72011-09-29 18:29:41 +0000324
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
sewardjfc824cb2011-09-29 17:33:58 +0000332 // 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
sewardjda91ee72011-09-29 18:29:41 +0000364#if !defined(VGP_amd64_darwin)
sewardjfc824cb2011-09-29 17:33:58 +0000365".previous" "\n"
sewardjda91ee72011-09-29 18:29:41 +0000366#endif
sewardjfc824cb2011-09-29 17:33:58 +0000367);
368
sewardjda91ee72011-09-29 18:29:41 +0000369#endif /* VGP_amd64_linux || VGP_amd64_darwin */
sewardjfc824cb2011-09-29 17:33:58 +0000370
371
sewardjda91ee72011-09-29 18:29:41 +0000372/* ------------ x86-{linux,darwin} ------------ */
sewardjfc824cb2011-09-29 17:33:58 +0000373
sewardjda91ee72011-09-29 18:29:41 +0000374#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
sewardjfc824cb2011-09-29 17:33:58 +0000375
376__asm__(
377".text" "\n"
378"" "\n"
sewardjda91ee72011-09-29 18:29:41 +0000379
380#if defined(VGP_x86_linux)
sewardjfc824cb2011-09-29 17:33:58 +0000381".global VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf
382"VG_MINIMAL_SETJMP:" "\n"
sewardjda91ee72011-09-29 18:29:41 +0000383
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
sewardjfc824cb2011-09-29 17:33:58 +0000392" 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
sewardjda91ee72011-09-29 18:29:41 +0000410
411#if defined(VGP_x86_linux)
412".global VG_MINIMAL_LONGJMP" "\n"
sewardjfc824cb2011-09-29 17:33:58 +0000413"VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf
sewardjda91ee72011-09-29 18:29:41 +0000414
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
sewardjfc824cb2011-09-29 17:33:58 +0000423 // 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
sewardjda91ee72011-09-29 18:29:41 +0000440#if !defined(VGP_x86_darwin)
sewardjfc824cb2011-09-29 17:33:58 +0000441".previous" "\n"
sewardjda91ee72011-09-29 18:29:41 +0000442#endif
sewardjfc824cb2011-09-29 17:33:58 +0000443);
444
sewardjda91ee72011-09-29 18:29:41 +0000445#endif /* VGP_x86_linux || VGP_x86_darwin */
sewardjfc824cb2011-09-29 17:33:58 +0000446
dejanj5f790e82013-07-25 08:22:08 +0000447#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"
dejanj751c1e62013-08-15 13:37:29 +0000470".previous \n\t"
dejanj5f790e82013-07-25 08:22:08 +0000471" \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"
dejanj751c1e62013-08-15 13:37:29 +0000495" nop \n\t"
496".previous \n\t"
dejanj5f790e82013-07-25 08:22:08 +0000497);
498#endif /* VGP_mips32_linux */
499
sewardj6c591e12011-04-11 16:17:51 +0000500/*--------------------------------------------------------------------*/
501/*--- end ---*/
502/*--------------------------------------------------------------------*/