]> git.lizzy.rs Git - rust.git/blob - src/rt/arch/x86_64/morestack.S
rt: Make unwinding through __morestack work on mac
[rust.git] / src / rt / arch / x86_64 / morestack.S
1     .text
2
3 // __morestack
4 //
5 // LLVM generates a call to this to allocate more stack space in a functiono
6 // prolog when we run out.
7
8 #if defined(__APPLE__) || defined(_WIN32)
9 #define UPCALL_NEW_STACK        _upcall_new_stack
10 #define UPCALL_DEL_STACK        _upcall_del_stack
11 #define UPCALL_CALL_C           _upcall_call_shim_on_c_stack
12 #define MORESTACK               ___morestack
13 #else
14 #define UPCALL_NEW_STACK        upcall_new_stack
15 #define UPCALL_DEL_STACK        upcall_del_stack
16 #define UPCALL_CALL_C           upcall_call_shim_on_c_stack
17 #define MORESTACK               __morestack
18 #endif
19
20         // Naturally, nobody can agree as to
21         // which arguments should go in which
22         // registers:
23 #if defined(_WIN32)
24 #  define ARG0 %rcx
25 #  define ARG1 %rdx
26 #  define ARG2 %r8
27 #else
28 #  define ARG0 %rdi
29 #  define ARG1 %rsi
30 #  define ARG2 %rdx
31 #endif
32
33 .globl UPCALL_NEW_STACK
34 .globl UPCALL_DEL_STACK
35 .globl UPCALL_CALL_C
36 .globl MORESTACK
37
38 // FIXME: What about _WIN32?    
39 #if defined(__linux__)
40         .hidden MORESTACK
41 #else
42 #if defined(__APPLE__)
43         .private_extern MORESTACK
44 #endif
45 #endif
46
47 #ifdef __ELF__
48         .type MORESTACK,@function
49 #endif
50
51 #if defined(__linux__) || defined(__APPLE__)
52 MORESTACK:
53         .cfi_startproc
54         
55         // Set up a normal backtrace
56         pushq %rbp
57         .cfi_def_cfa_offset 16
58         .cfi_offset %rbp, -16
59         movq %rsp, %rbp
60         .cfi_def_cfa_register %rbp
61
62         // During unwinding we want to skip our caller since it's not
63         // a complete frame and will make the unwinder sad
64         // Don't understand this line
65         .cfi_offset 16, 0
66         // Tell the unwinding where to get the stack pointer for
67         // our grandparent frame
68         .cfi_offset %rsp, -24
69
70         // Save the grandparent stack pointer for the unwinder
71         leaq 16(%rbp), %rax
72         pushq %rax
73
74         // During unwinding we want to skip our caller since it's not
75         // a complete frame and will make the unwinder sad
76         // Don't understand this line
77         .cfi_offset 16, 0
78         // Tell the unwinding where to get the stack pointer for
79         // our grandparent frame
80         .cfi_offset %rsp, -24
81
82         // Save the grandparent stack pointer for the unwinder
83         leaq 16(%rbp), %rax
84         pushq %rax
85
86         // FIXME: libgcc also saves rax. not sure if we need to
87
88         // Save argument registers
89         pushq   %rdi
90         pushq   %rsi
91         pushq   %rdx
92         pushq   %rcx
93         pushq   %r8
94         pushq   %r9
95
96         // Calculate the address of the stack arguments.
97         // We have the base pointer, __morestack's return address,
98         // and __morestack's caller's return address to skip
99         movq %rbp, %rcx
100         addq $24, %rcx  // Base pointer, return address x2
101
102         pushq %r11 // Size of stack arguments
103         pushq %rcx // Address of stack arguments
104         pushq %r10 // The amount of stack needed
105         pushq $0   // Out pointer
106
107         movq UPCALL_NEW_STACK@GOTPCREL(%rip), %rsi
108         movq %rsp, %rdi
109 #ifdef __APPLE__
110         call UPCALL_CALL_C
111 #endif
112 #ifdef __linux__
113         call UPCALL_CALL_C@PLT
114 #endif
115
116         // Pop the new_stack_args struct
117         popq %rax
118         addq $24, %rsp
119
120         // Pop the saved arguments
121         popq %r9
122         popq %r8
123         popq %rcx
124         popq %rdx
125         popq %rsi
126         popq %rdi
127
128         // Pop the unwinding %rsp
129         addq $8, %rsp
130
131         movq 8(%rbp),%r10       // Grab the return pointer.
132         incq %r10               // Skip past the `ret` in our parent frame
133         movq %rax,%rsp          // Switch to the new stack.
134
135         call *%r10              // Reenter the caller function
136
137         // Switch back to the rust stack
138         movq %rbp, %rsp
139
140         // Align the stack again
141         pushq $0
142         
143         movq UPCALL_DEL_STACK@GOTPCREL(%rip), %rsi
144         movq $0, %rdi
145 #ifdef __APPLE__
146         call UPCALL_CALL_C
147 #endif
148 #ifdef __linux__
149         call UPCALL_CALL_C@PLT
150 #endif
151
152         addq $8, %rsp
153         popq %rbp
154         .cfi_restore %rbp
155         .cfi_def_cfa %rsp, 8
156         ret
157         
158         .cfi_endproc
159
160 #else
161 MORESTACK:
162         ret
163 #endif