]> git.lizzy.rs Git - rust.git/blob - src/rt/arch/x86_64/morestack.S
rt: Give upcall_new_stack the same convention as other upcalls
[rust.git] / src / rt / arch / x86_64 / morestack.S
1 /*
2         __morestack
3
4         See i386/morestack.S for the lengthy, general explanation.
5 */
6
7 .text
8
9 #if defined(__APPLE__) || defined(_WIN32)
10 #define UPCALL_NEW_STACK        _upcall_new_stack
11 #define UPCALL_DEL_STACK        _upcall_del_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 MORESTACK               __morestack
17 #endif
18
19 .globl UPCALL_NEW_STACK
20 .globl UPCALL_DEL_STACK
21 .globl MORESTACK
22
23 #if defined(__linux__)
24         .hidden MORESTACK
25 #else
26 #if defined(__APPLE__)
27         .private_extern MORESTACK
28 #endif
29 #endif
30
31 #ifdef __ELF__
32         .type MORESTACK,@function
33 #endif
34
35
36 #if defined(__linux__) || defined(__APPLE__)
37 MORESTACK:
38         .cfi_startproc
39
40         pushq %rbp
41         // The CFA is 24 bytes above the register that it will
42         // be associated with for this frame (%rbp). That is 8
43         // bytes greater than a normal frame, to allow the unwinder
44         // to skip the partial frame of the original function.
45         .cfi_def_cfa_offset 24
46         // %rbp is -24 bytes from the CFA
47         .cfi_offset %rbp, -24
48         movq %rsp, %rbp
49         // Calculate the CFA as on offset from %ebp
50         .cfi_def_cfa_register %rbp
51
52         // Save the grandparent stack pointer for the unwinder
53         // FIXME: This isn't used
54         leaq 24(%rbp), %rax
55         pushq %rax
56
57         // FIXME: libgcc also saves rax. not sure if we need to
58
59         // Save argument registers of the original function
60         pushq   %rdi
61         pushq   %rsi
62         pushq   %rdx
63         pushq   %rcx
64         pushq   %r8
65         pushq   %r9
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
86         // Pop the saved arguments
87         popq %r9
88         popq %r8
89         popq %rcx
90         popq %rdx
91         popq %rsi
92         popq %rdi
93
94         // Pop the unwinding %rsp
95         addq $8, %rsp
96
97         movq 8(%rbp),%r10       // Grab the return pointer.
98         incq %r10               // Skip past the `ret` in our parent frame
99         movq %rax,%rsp          // Switch to the new stack.
100
101         call *%r10              // Reenter the caller function
102
103         // Switch back to the rust stack
104         movq %rbp, %rsp
105
106         // Align the stack again
107         pushq $0
108
109         // FIXME: Should preserve %rax here
110 #ifdef __APPLE__
111         call UPCALL_DEL_STACK
112 #endif
113 #ifdef __linux__
114         call UPCALL_DEL_STACK@PLT
115 #endif
116
117         addq $8, %rsp
118         popq %rbp
119         // FIXME: I don't think these rules are necessary
120         // since the unwinder should never encounter an instruction
121         // pointer pointing here.
122         .cfi_restore %rbp
123         .cfi_def_cfa %rsp, 16
124         ret
125         
126         .cfi_endproc
127
128 #else
129 MORESTACK:
130         ret
131 #endif