]> git.lizzy.rs Git - rust.git/blob - src/rt/arch/x86_64/morestack.S
rt: Make 64-bit __morestack grow and shrink properly
[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 RUST_NEW_STACK2     _rust_new_stack2
10 #define RUST_DEL_STACK      _rust_del_stack
11 #define RUST_DEL_STACK      _rust_del_stack
12 #define RUST_GET_PREV_STACK _rust_get_prev_stack
13 #define UPCALL_CALL_C       _upcall_call_shim_on_c_stack
14 #define MORESTACK           ___morestack
15 #else
16 #define RUST_NEW_STACK2     rust_new_stack2
17 #define RUST_DEL_STACK      rust_del_stack
18 #define RUST_DEL_STACK      rust_del_stack
19 #define RUST_GET_PREV_STACK rust_get_prev_stack
20 #define UPCALL_CALL_C       upcall_call_shim_on_c_stack
21 #define MORESTACK           __morestack
22 #endif
23
24         // Naturally, nobody can agree as to
25         // which arguments should go in which
26         // registers:
27 #if defined(_WIN32)
28 #  define ARG0 %rcx
29 #  define ARG1 %rdx
30 #  define ARG2 %r8
31 #else
32 #  define ARG0 %rdi
33 #  define ARG1 %rsi
34 #  define ARG2 %rdx
35 #endif
36
37 .globl RUST_NEW_STACK2
38 .globl RUST_DEL_STACK
39 .globl UPCALL_CALL_C
40 .globl MORESTACK
41
42 // FIXME: What about _WIN32?    
43 #if defined(__linux__)
44         .hidden MORESTACK
45 #else
46 #if defined(__APPLE__)
47         .private_extern MORESTACK
48 #endif
49 #endif
50
51 #ifdef __ELF__
52         .type MORESTACK,@function
53 #endif
54
55 #if defined(__linux)
56 MORESTACK:
57         .cfi_startproc
58
59         # Set up a normal backtrace
60         pushq %rbp
61         .cfi_def_cfa_offset 16
62         .cfi_offset %rbp, -16
63         movq %rsp, %rbp
64         .cfi_def_cfa_register %rbp
65
66         // Alignment
67         pushq $0
68
69         // FIXME: libgcc also saves rax. not sure if we need to
70
71         // Save argument registers
72         pushq   %rdi
73         pushq   %rsi
74         pushq   %rdx
75         pushq   %rcx
76         pushq   %r8
77         pushq   %r9
78
79         // Calculate the address of the stack arguments
80         movq %rbp, %rcx
81         addq $16, %rcx   // Add the saved %rbp, and return address
82         addq %r11, %rcx // Add the size of stack arguments
83
84         pushq %rbp // Save the Rust stack pointer
85         pushq %r11 // Size of stack arguments
86         pushq %rcx // Address of stack arguments
87         pushq %r10 // The amount of stack needed
88
89         leaq RUST_NEW_STACK2@PLT(%rip), %rsi
90         movq %rsp, %rdi
91         call UPCALL_CALL_C@PLT
92
93         // Pop the new_stack_args struct
94         addq $32, %rsp
95
96         // Pop the saved arguments
97         popq %r9
98         popq %r8
99         popq %rcx
100         popq %rdx
101         popq %rsi
102         popq %rdi
103         
104         movq 8(%rbp),%r10       // Grab the return pointer.
105         incq %r10               // Skip past the `ret` in our parent frame
106         movq %rax,%rsp          // Switch to the new stack.
107
108         call *%r10              // Reenter the caller function
109
110         leaq RUST_GET_PREV_STACK@PLT(%rip), %rsi
111         movq $0, %rdi
112         call UPCALL_CALL_C@PLT
113
114         // Switch back to the rust stack, positioned
115         // where we pushed %ebp
116         movq %rax, %rsp
117
118         // Align the stack again
119         pushq $0
120         
121         leaq RUST_DEL_STACK@PLT(%rip), %rsi
122         movq $0, %rdi
123         call UPCALL_CALL_C@PLT
124
125         addq $8, %rsp
126         popq %rbp
127         ret
128         
129         .cfi_endproc
130 #else
131 MORESTACK:
132         ret
133 #endif