|
8 | 8 |
|
9 | 9 | #include "src/__support/common.h" |
10 | 10 | #include "src/__support/macros/config.h" |
| 11 | +#include "src/setjmp/checksum.h" |
11 | 12 | #include "src/setjmp/setjmp_impl.h" |
12 | 13 |
|
13 | 14 | #if !defined(LIBC_TARGET_ARCH_IS_X86_64) |
|
16 | 17 |
|
17 | 18 | namespace LIBC_NAMESPACE_DECL { |
18 | 19 |
|
| 20 | +namespace jmpbuf {} // namespace jmpbuf |
| 21 | +[[gnu::naked]] |
19 | 22 | LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) { |
20 | | - register __UINT64_TYPE__ rbx __asm__("rbx"); |
21 | | - register __UINT64_TYPE__ r12 __asm__("r12"); |
22 | | - register __UINT64_TYPE__ r13 __asm__("r13"); |
23 | | - register __UINT64_TYPE__ r14 __asm__("r14"); |
24 | | - register __UINT64_TYPE__ r15 __asm__("r15"); |
25 | | - |
26 | | - // We want to store the register values as is. So, we will suppress the |
27 | | - // compiler warnings about the uninitialized variables declared above. |
28 | | -#pragma GCC diagnostic push |
29 | | -#pragma GCC diagnostic ignored "-Wuninitialized" |
30 | | - LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf->rbx) : "r"(rbx) :); |
31 | | - LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf->r12) : "r"(r12) :); |
32 | | - LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf->r13) : "r"(r13) :); |
33 | | - LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf->r14) : "r"(r14) :); |
34 | | - LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf->r15) : "r"(r15) :); |
35 | | -#pragma GCC diagnostic pop |
36 | | - |
37 | | - // We want the rbp of the caller, which is what __builtin_frame_address(1) |
38 | | - // should return. But, compilers generate a warning that calling |
39 | | - // __builtin_frame_address with non-zero argument is unsafe. So, we use |
40 | | - // the knowledge of the x86_64 ABI to fetch the callers rbp. As per the ABI, |
41 | | - // the rbp of the caller is pushed on to the stack and then new top is saved |
42 | | - // in this function's rbp. So, we fetch it from location at which this |
43 | | - // functions's rbp is pointing. |
44 | | - buf->rbp = *reinterpret_cast<__UINTPTR_TYPE__ *>(__builtin_frame_address(0)); |
45 | | - |
46 | | - // The callers stack address is exactly 2 pointer widths ahead of the current |
47 | | - // frame pointer - between the current frame pointer and the rsp of the caller |
48 | | - // are the return address (pushed by the x86_64 call instruction) and the |
49 | | - // previous stack pointer as required by the x86_64 ABI. |
50 | | - // The stack pointer is ahead because the stack grows down on x86_64. |
51 | | - buf->rsp = reinterpret_cast<__UINTPTR_TYPE__>(__builtin_frame_address(0)) + |
52 | | - sizeof(__UINTPTR_TYPE__) * 2; |
53 | | - buf->rip = reinterpret_cast<__UINTPTR_TYPE__>(__builtin_return_address(0)); |
54 | | - return 0; |
| 23 | + register __UINT64_TYPE__ rcx __asm__("rcx"); |
| 24 | + // Load cookie |
| 25 | + asm("mov %1, %0\n\t" : "=r"(rcx) : "m"(jmpbuf::register_mangle_cookie)); |
| 26 | + // store registers to buffer |
| 27 | + // do not pass any invalid values into registers |
| 28 | +#define STORE(REG) \ |
| 29 | + asm("mov %%" #REG ", %%rdx\n\t" \ |
| 30 | + "xor %%rdx, %%rcx\n\t" \ |
| 31 | + "mov %%rdx, %c[" #REG \ |
| 32 | + "](%%rdi)\n\t" ::[REG] "i"(offsetof(__jmp_buf, REG)) \ |
| 33 | + : "rdx"); |
| 34 | + |
| 35 | + STORE(rbx); |
| 36 | + STORE(rbp); |
| 37 | + STORE(r12); |
| 38 | + STORE(r13); |
| 39 | + STORE(r14); |
| 40 | + STORE(r15); |
| 41 | + asm(R"( |
| 42 | + lea 8(%%rsp),%%rdx |
| 43 | + xor %%rdx, %%rcx |
| 44 | + mov %%rdx,%c[rsp](%%rdi) |
| 45 | + mov (%%rsp),%%rdx |
| 46 | + xor %%rdx, %%rcx |
| 47 | + mov %%rdx,%c[rip](%%rdi) |
| 48 | + )" ::[rsp] "i"(offsetof(__jmp_buf, rsp)), |
| 49 | + [rip] "i"(offsetof(__jmp_buf, rip)) |
| 50 | + : "rdx"); |
| 51 | + |
| 52 | + // tail call to update checksum |
| 53 | + asm("jmp %P0" : : "i"(jmpbuf::update_checksum)); |
55 | 54 | } |
56 | 55 |
|
57 | 56 | } // namespace LIBC_NAMESPACE_DECL |
0 commit comments