1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
/*
__morestack
See i386/morestack.S for the lengthy, general explanation.
*/
.text
#if defined(__APPLE__) || defined(_WIN32)
#define UPCALL_NEW_STACK _upcall_new_stack
#define UPCALL_DEL_STACK _upcall_del_stack
#define UPCALL_CALL_C _upcall_call_shim_on_c_stack
#define MORESTACK ___morestack
#else
#define UPCALL_NEW_STACK upcall_new_stack
#define UPCALL_DEL_STACK upcall_del_stack
#define UPCALL_CALL_C upcall_call_shim_on_c_stack
#define MORESTACK __morestack
#endif
.globl UPCALL_NEW_STACK
.globl UPCALL_DEL_STACK
.globl UPCALL_CALL_C
.globl MORESTACK
#if defined(__linux__)
.hidden MORESTACK
#else
#if defined(__APPLE__)
.private_extern MORESTACK
#endif
#endif
#ifdef __ELF__
.type MORESTACK,@function
#endif
#if defined(__linux__) || defined(__APPLE__)
MORESTACK:
.cfi_startproc
pushq %rbp
// The CFA is 24 bytes above the register that it will
// be associated with for this frame (%rbp). That is 8
// bytes greater than a normal frame, to allow the unwinder
// to skip the partial frame of the original function.
.cfi_def_cfa_offset 24
// %rbp is -24 bytes from the CFA
.cfi_offset %rbp, -24
movq %rsp, %rbp
// Calculate the CFA as on offset from %ebp
.cfi_def_cfa_register %rbp
// Save the grandparent stack pointer for the unwinder
// FIXME: This isn't used
leaq 24(%rbp), %rax
pushq %rax
// FIXME: libgcc also saves rax. not sure if we need to
// Save argument registers of the original function
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx
pushq %r8
pushq %r9
// Calculate the address of the stack arguments.
// We have the base pointer, __morestack's return address,
// and __morestack's caller's return address to skip
movq %rbp, %rcx
addq $24, %rcx // Base pointer, return address x2
// The arguments to __morestack are passed in %r10 & %r11
pushq %r11 // Size of stack arguments
pushq %rcx // Address of stack arguments
pushq %r10 // The amount of stack needed
pushq $0 // Out pointer
movq UPCALL_NEW_STACK@GOTPCREL(%rip), %rsi
movq %rsp, %rdi
#ifdef __APPLE__
call UPCALL_CALL_C
#endif
#ifdef __linux__
call UPCALL_CALL_C@PLT
#endif
// Pop the new_stack_args struct
popq %rax
addq $24, %rsp
// Pop the saved arguments
popq %r9
popq %r8
popq %rcx
popq %rdx
popq %rsi
popq %rdi
// Pop the unwinding %rsp
addq $8, %rsp
movq 8(%rbp),%r10 // Grab the return pointer.
incq %r10 // Skip past the `ret` in our parent frame
movq %rax,%rsp // Switch to the new stack.
call *%r10 // Reenter the caller function
// Switch back to the rust stack
movq %rbp, %rsp
// Align the stack again
pushq $0
// FIXME: Should preserve %rax here
movq UPCALL_DEL_STACK@GOTPCREL(%rip), %rsi
movq $0, %rdi
#ifdef __APPLE__
call UPCALL_CALL_C
#endif
#ifdef __linux__
call UPCALL_CALL_C@PLT
#endif
addq $8, %rsp
popq %rbp
// FIXME: I don't think these rules are necessary
// since the unwinder should never encounter an instruction
// pointer pointing here.
.cfi_restore %rbp
.cfi_def_cfa %rsp, 16
ret
.cfi_endproc
#else
MORESTACK:
ret
#endif
|