m_libcsetjmp.c revision 2d3c75979dd0bbf2606bf1a8e11b72ae6220e5db
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-2012 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/*--------------------------------------------------------------------*/
448/*--- end                                                          ---*/
449/*--------------------------------------------------------------------*/
450