• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2011 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