@@ -91,6 +91,35 @@ void cleanup_tls(uintptr_t addr, uintptr_t size) {
91
91
92
92
static void set_thread_ptr (uintptr_t val) { __arm_wsr64 (" tpidr_el0" , val); }
93
93
94
+ using InitCallback = void (int , char **, char **);
95
+ using FiniCallback = void (void );
96
+
97
+ extern " C" {
98
+ // These arrays are present in the .init_array and .fini_array sections.
99
+ // The symbols are inserted by linker when it sees references to them.
100
+ extern uintptr_t __preinit_array_start[];
101
+ extern uintptr_t __preinit_array_end[];
102
+ extern uintptr_t __init_array_start[];
103
+ extern uintptr_t __init_array_end[];
104
+ extern uintptr_t __fini_array_start[];
105
+ extern uintptr_t __fini_array_end[];
106
+ }
107
+
108
+ static void call_init_array_callbacks (int argc, char **argv, char **env) {
109
+ size_t preinit_array_size = __preinit_array_end - __preinit_array_start;
110
+ for (size_t i = 0 ; i < preinit_array_size; ++i)
111
+ reinterpret_cast <InitCallback *>(__preinit_array_start[i])(argc, argv, env);
112
+ size_t init_array_size = __init_array_end - __init_array_start;
113
+ for (size_t i = 0 ; i < init_array_size; ++i)
114
+ reinterpret_cast <InitCallback *>(__init_array_start[i])(argc, argv, env);
115
+ }
116
+
117
+ static void call_fini_array_callbacks () {
118
+ size_t fini_array_size = __fini_array_end - __fini_array_start;
119
+ for (size_t i = 0 ; i < fini_array_size; ++i)
120
+ reinterpret_cast <FiniCallback *>(__fini_array_start[i])();
121
+ }
122
+
94
123
} // namespace __llvm_libc
95
124
96
125
using __llvm_libc::app;
@@ -101,13 +130,7 @@ struct AuxEntry {
101
130
uint64_t value;
102
131
};
103
132
104
- extern " C" void _start () {
105
- // Skip the Frame Pointer and the Link Register
106
- // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
107
- // Section 6.2.3
108
- app.args = reinterpret_cast <__llvm_libc::Args *>(
109
- reinterpret_cast <uintptr_t *>(__builtin_frame_address (0 )) + 2 );
110
-
133
+ __attribute__ ((noinline)) static void do_start() {
111
134
auto tid = __llvm_libc::syscall (SYS_gettid);
112
135
if (tid <= 0 )
113
136
__llvm_libc::syscall (SYS_exit, 1 );
@@ -162,8 +185,31 @@ extern "C" void _start() {
162
185
163
186
__llvm_libc::self.attrib = &__llvm_libc::main_thread_attrib;
164
187
188
+ __llvm_libc::call_init_array_callbacks (
189
+ app.args ->argc , reinterpret_cast <char **>(app.args ->argv ),
190
+ reinterpret_cast <char **>(env_ptr));
191
+
165
192
int retval = main (app.args ->argc , reinterpret_cast <char **>(app.args ->argv ),
166
193
reinterpret_cast <char **>(env_ptr));
194
+
195
+ __llvm_libc::call_fini_array_callbacks ();
196
+
167
197
__llvm_libc::cleanup_tls (tls.addr , tls.size );
168
198
__llvm_libc::syscall (SYS_exit, retval);
169
199
}
200
+
201
+ extern " C" void _start () {
202
+ // Skip the Frame Pointer and the Link Register
203
+ // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
204
+ // Section 6.2.3. Note that this only works if the current function
205
+ // is not using any callee-saved registers (x19 to x28). If the
206
+ // function uses such registers, then their value is pushed on to the
207
+ // stack before the frame pointer an link register values. That breaks
208
+ // the assumption that stepping over the frame pointer and link register
209
+ // will take us to the previous stack pointer. That is the reason why the
210
+ // actual business logic of the startup code is pushed into a non-inline
211
+ // function do_start so that this function is free of any stack usage.
212
+ app.args = reinterpret_cast <__llvm_libc::Args *>(
213
+ reinterpret_cast <uintptr_t *>(__builtin_frame_address (0 )) + 2 );
214
+ do_start ();
215
+ }
0 commit comments