]> git.lizzy.rs Git - rust.git/blob - src/rt/arch/i386/morestack.S
Auto merge of #27529 - dotdash:c_u8, r=eddyb
[rust.git] / src / rt / arch / i386 / 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         This function is normally used to implement stack growth using the
10         mechanism devised by Ian Lance Taylor for gccgo, described here:
11
12         http://gcc.gnu.org/wiki/SplitStacks
13
14         Each Rust function contains an LLVM-generated prologue that compares the
15         stack space required for the current function to the space remaining in
16         the current stack segment, maintained in a platform-specific TLS slot.
17         The stack limit is strategically maintained by the Rust runtime so that
18         it is always in place whenever a Rust function is running.
19
20         In Rust, however, we currently do not use __morestack for stack growth
21         purposes.  Rather each task has one large stack segment. When this
22         __morestack function is run, we interpret this as a "stack overflow"
23         event rather than an event requiring an allocation of a new stack.
24
25         In the early days, this implementation did indeed have all of the fiddly
26         bits in order to manage split stacks in the sense of always growing
27         stacks. For posterity, the implementation can be found at commit
28         c8e77d5586aed50821e0b9361b2e24c96ade816c if we ever need to refer back
29         to it.
30
31         -- The __morestack calling convention --
32
33         For reasons of efficiency the __morestack calling convention
34         is bizarre. The calling function does not attempt to align the
35         stack for the call, and on x86_64 the arguments to __morestack
36         are passed in scratch registers in order to preserve the
37         original function's arguments.
38
39         Once __morestack has switched to the new stack, instead of
40         returning, it then calls into the original function, resuming
41         execution at the instruction following the call to
42         __morestack. Thus, when the original function returns it
43         actually returns to __morestack, which then deallocates the
44         stack and returns again to the original function's caller.
45
46         -- Unwinding --
47
48         All this trickery causes hell when it comes time for the
49         unwinder to navigate it's way through this function. What
50         will happen is the original function will be unwound first
51         without any special effort, then the unwinder encounters
52         the __morestack frame, which is sitting just above a
53         tiny fraction of a frame (containing just a return pointer
54         and, on 32-bit, the arguments to __morestack).
55
56         We deal with this by claiming that little bit of stack
57         is actually part of the __morestack frame, encoded as
58         DWARF call frame instructions (CFI) by .cfi assembler
59         pseudo-ops.
60
61         One final complication (that took me a week to figure out)
62         is that OS X 10.6+ uses its own 'compact unwind info',
63         an undocumented format generated by the linker from
64         the DWARF CFI. This compact unwind info doesn't correctly
65         capture the nuance of the __morestack frame, so we need to
66         prevent the linker from attempting to convert its DWARF unwind
67         information.
68 */
69
70 .text
71
72 #if defined(__APPLE__)
73 #define MORESTACK               ___morestack
74 #define EXHAUSTED               _rust_stack_exhausted
75 #else
76 #if defined(__linux__) || defined(__FreeBSD__)
77 #define MORESTACK               __morestack
78 #define EXHAUSTED               rust_stack_exhausted@plt
79 #else
80 #define MORESTACK               ___morestack
81 #define EXHAUSTED               _rust_stack_exhausted
82 #endif
83 #endif
84
85 .globl MORESTACK
86
87 // FIXME: What about __WIN32__?
88 #if defined(__linux__) || defined(__FreeBSD__)
89         .hidden MORESTACK
90 #else
91 #if defined(__APPLE__)
92         .private_extern MORESTACK
93 #endif
94 #endif
95
96 #ifdef __ELF__
97         .type MORESTACK,@function
98 #endif
99
100 MORESTACK:
101         .cfi_startproc
102
103         // This base pointer setup differs from most in that we are
104         // telling the unwinder to consider the Canonical Frame
105         // Address (CFA) for this frame to be the value of the stack
106         // pointer prior to entry to the original function, whereas
107         // the CFA would typically be the value of the stack
108         // pointer prior to entry to this function. This will allow
109         // the unwinder to understand how to skip the tiny partial
110         // frame that the original function created by calling
111         // __morestack.
112
113         // In practical terms, our CFA is 12 bytes greater than it
114         // would normally be, accounting for the two arguments to
115         // __morestack, and an extra return address.
116
117         // FIXME(#9854) these cfi directives don't work on windows.
118
119         pushl %ebp
120
121 #if defined(__APPLE__)
122         // The pattern of the return address being saved twice to the same location
123         // tells the OS X linker that it should not attempt to convert the DWARF
124         // unwind information to the compact format.
125         .cfi_offset %eip, -4
126         .cfi_offset %eip, -4
127 #endif
128
129         // The CFA is 20 bytes above the register that it is
130         // associated with for this frame (which will be %ebp)
131         .cfi_def_cfa_offset 20
132         // %ebp is -20 bytes from the CFA
133         .cfi_offset %ebp, -20
134         movl %esp, %ebp
135         // Calculate the CFA as an offset from %ebp
136         .cfi_def_cfa_register %ebp
137
138         // re-align the stack
139         subl $12,%esp
140         call EXHAUSTED
141         // the exhaustion function guarantees that it can't return
142
143         .cfi_endproc