1 //===-- Implementation of setjmp ------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "src/__support/common.h"
10 #include "src/setjmp/setjmp_impl.h"
12 #if !defined(LIBC_TARGET_ARCH_IS_X86_64)
13 #error "Invalid file include"
16 namespace LIBC_NAMESPACE
{
18 LLVM_LIBC_FUNCTION(int, setjmp
, (__jmp_buf
* buf
)) {
19 register __UINT64_TYPE__ rbx
__asm__("rbx");
20 register __UINT64_TYPE__ r12
__asm__("r12");
21 register __UINT64_TYPE__ r13
__asm__("r13");
22 register __UINT64_TYPE__ r14
__asm__("r14");
23 register __UINT64_TYPE__ r15
__asm__("r15");
25 // We want to store the register values as is. So, we will suppress the
26 // compiler warnings about the uninitialized variables declared above.
27 #pragma GCC diagnostic push
28 #pragma GCC diagnostic ignored "-Wuninitialized"
29 LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf
->rbx
) : "r"(rbx
) :);
30 LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf
->r12
) : "r"(r12
) :);
31 LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf
->r13
) : "r"(r13
) :);
32 LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf
->r14
) : "r"(r14
) :);
33 LIBC_INLINE_ASM("mov %1, %0\n\t" : "=m"(buf
->r15
) : "r"(r15
) :);
34 #pragma GCC diagnostic pop
36 // We want the rbp of the caller, which is what __builtin_frame_address(1)
37 // should return. But, compilers generate a warning that calling
38 // __builtin_frame_address with non-zero argument is unsafe. So, we use
39 // the knowledge of the x86_64 ABI to fetch the callers rbp. As per the ABI,
40 // the rbp of the caller is pushed on to the stack and then new top is saved
41 // in this function's rbp. So, we fetch it from location at which this
42 // functions's rbp is pointing.
43 buf
->rbp
= *reinterpret_cast<__UINTPTR_TYPE__
*>(__builtin_frame_address(0));
45 // The callers stack address is exactly 2 pointer widths ahead of the current
46 // frame pointer - between the current frame pointer and the rsp of the caller
47 // are the return address (pushed by the x86_64 call instruction) and the
48 // previous stack pointer as required by the x86_64 ABI.
49 // The stack pointer is ahead because the stack grows down on x86_64.
50 buf
->rsp
= reinterpret_cast<__UINTPTR_TYPE__
>(__builtin_frame_address(0)) +
51 sizeof(__UINTPTR_TYPE__
) * 2;
52 buf
->rip
= reinterpret_cast<__UINTPTR_TYPE__
>(__builtin_return_address(0));
56 } // namespace LIBC_NAMESPACE