• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Implementation of setjmp ------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/__support/common.h"
10 #include "src/setjmp/setjmp_impl.h"
11 
12 #if !defined(LIBC_TARGET_ARCH_IS_X86_64)
13 #error "Invalid file include"
14 #endif
15 
16 namespace LIBC_NAMESPACE {
17 
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");
24 
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
35 
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));
44 
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));
53   return 0;
54 }
55 
56 } // namespace LIBC_NAMESPACE
57