]> git.lizzy.rs Git - rust.git/blob - src/rt/arch/x86_64/morestack.S
auto merge of #6026 : isanbard/rust/ca73fbf72615575f106ee18160580711aca89d85, r=catam...
[rust.git] / src / rt / arch / x86_64 / morestack.S
1 // Mark stack as non-executable
2 #if defined(__linux__) && defined(__ELF__)
3 .section        .note.GNU-stack, "", @progbits
4 #endif
5
6 /*
7         __morestack
8
9         See i386/morestack.S for the lengthy, general explanation.
10 */
11
12 .text
13
14 #if defined(__APPLE__) || defined(_WIN32)
15 #define UPCALL_NEW_STACK        _upcall_new_stack
16 #define UPCALL_DEL_STACK        _upcall_del_stack
17 #define MORESTACK               ___morestack
18 #else
19 #define UPCALL_NEW_STACK        upcall_new_stack
20 #define UPCALL_DEL_STACK        upcall_del_stack
21 #define MORESTACK               __morestack
22 #endif
23
24 .globl UPCALL_NEW_STACK
25 .globl UPCALL_DEL_STACK
26 .globl MORESTACK
27
28 #if defined(__linux__) || defined(__FreeBSD__)
29         .hidden MORESTACK
30 #else
31 #if defined(__APPLE__)
32         .private_extern MORESTACK
33 #endif
34 #endif
35
36 #ifdef __ELF__
37         .type MORESTACK,@function
38 #endif
39
40
41 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
42 MORESTACK:
43         .cfi_startproc
44
45         pushq %rbp
46         // The CFA is 24 bytes above the register that it will
47         // be associated with for this frame (%rbp). That is 8
48         // bytes greater than a normal frame, to allow the unwinder
49         // to skip the partial frame of the original function.
50         .cfi_def_cfa_offset 24
51         // %rbp is -24 bytes from the CFA
52         .cfi_offset %rbp, -24
53         movq %rsp, %rbp
54         // Calculate the CFA as on offset from %ebp
55         .cfi_def_cfa_register %rbp
56
57         subq $56, %rsp
58
59         // Save argument registers of the original function
60         movq %rdi,       (%rsp)
61         movq %rsi,      8(%rsp)
62         movq %rdx,     16(%rsp)
63         movq %rcx,     24(%rsp)
64         movq %r8,      32(%rsp)
65         movq %r9,      40(%rsp)
66
67         // Calculate the address of the stack arguments.
68         // We have the base pointer, __morestack's return address,
69         // and __morestack's caller's return address to skip
70         movq %rbp, %rax
71         addq $24, %rax  // Base pointer, return address x2
72
73         // The arguments to __morestack are passed in %r10 & %r11
74
75         movq %r11, %rdx // Size of stack arguments
76         movq %rax, %rsi // Address of stack arguments
77         movq %r10, %rdi // The amount of stack needed
78
79 #ifdef __APPLE__
80         call UPCALL_NEW_STACK
81 #endif
82 #ifdef __linux__
83         call UPCALL_NEW_STACK@PLT
84 #endif
85 #ifdef __FreeBSD__
86         call UPCALL_NEW_STACK@PLT
87 #endif
88
89         // Pop the saved arguments
90         movq      (%rsp), %rdi
91         movq     8(%rsp), %rsi
92         movq    16(%rsp), %rdx
93         movq    24(%rsp), %rcx
94         movq    32(%rsp), %r8
95         movq    40(%rsp), %r9
96
97         addq $56, %rsp
98
99         movq 8(%rbp),%r10       // Grab the return pointer.
100         incq %r10               // Skip past the `ret` in our parent frame
101         movq %rax,%rsp          // Switch to the new stack.
102
103         call *%r10              // Reenter the caller function
104
105         // Switch back to the rust stack
106         movq %rbp, %rsp
107
108         // Save the return value
109         pushq %rax
110
111 #ifdef __APPLE__
112         call UPCALL_DEL_STACK
113 #endif
114 #ifdef __linux__
115         call UPCALL_DEL_STACK@PLT
116 #endif
117 #ifdef __FreeBSD__
118         call UPCALL_DEL_STACK@PLT
119 #endif
120
121         popq %rax // Restore the return value
122         popq %rbp
123         ret
124
125         .cfi_endproc
126
127 #else
128 MORESTACK:
129         ret
130 #endif