1
- // ===-- Implementation of crt for aarch64 --- ------------------------------===//
1
+ // ===-- Implementation of _start for aarch64 ------------------------------===//
2
2
//
3
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
4
// See https://llvm.org/LICENSE.txt for license information.
5
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
9
- #include " config/linux/app.h"
10
- #include " src/__support/OSUtil/syscall.h"
11
- #include " src/__support/threads/thread.h"
12
- #include " src/stdlib/atexit.h"
13
- #include " src/stdlib/exit.h"
14
- #include " src/string/memory_utils/inline_memcpy.h"
15
-
16
- #include < arm_acle.h>
17
-
18
- #include < linux/auxvec.h>
19
- #include < linux/elf.h>
20
- #include < stdint.h>
21
- #include < sys/mman.h>
22
- #include < sys/syscall.h>
23
- #include < unistd.h>
24
-
25
- extern " C" int main (int , char **, char **);
26
-
27
- // Source documentation:
28
- // https://github.com/ARM-software/abi-aa/tree/main/sysvabi64
29
-
30
- namespace LIBC_NAMESPACE {
31
-
32
- #ifdef SYS_mmap2
33
- static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap2;
34
- #elif SYS_mmap
35
- static constexpr long MMAP_SYSCALL_NUMBER = SYS_mmap;
36
- #else
37
- #error "mmap and mmap2 syscalls not available."
38
- #endif
39
-
40
- AppProperties app;
41
-
42
- static ThreadAttributes main_thread_attrib;
43
-
44
- void init_tls (TLSDescriptor &tls_descriptor) {
45
- if (app.tls .size == 0 ) {
46
- tls_descriptor.size = 0 ;
47
- tls_descriptor.tp = 0 ;
48
- return ;
49
- }
50
-
51
- // aarch64 follows the variant 1 TLS layout:
52
- //
53
- // 1. First entry is the dynamic thread vector pointer
54
- // 2. Second entry is a 8-byte reserved word.
55
- // 3. Padding for alignment.
56
- // 4. The TLS data from the ELF image.
57
- //
58
- // The thread pointer points to the first entry.
59
-
60
- const uintptr_t size_of_pointers = 2 * sizeof (uintptr_t );
61
- uintptr_t padding = 0 ;
62
- const uintptr_t ALIGNMENT_MASK = app.tls .align - 1 ;
63
- uintptr_t diff = size_of_pointers & ALIGNMENT_MASK;
64
- if (diff != 0 )
65
- padding += (ALIGNMENT_MASK - diff) + 1 ;
66
-
67
- uintptr_t alloc_size = size_of_pointers + padding + app.tls .size ;
68
-
69
- // We cannot call the mmap function here as the functions set errno on
70
- // failure. Since errno is implemented via a thread local variable, we cannot
71
- // use errno before TLS is setup.
72
- long mmap_ret_val = LIBC_NAMESPACE::syscall_impl<long >(
73
- MMAP_SYSCALL_NUMBER, nullptr , alloc_size, PROT_READ | PROT_WRITE,
74
- MAP_ANONYMOUS | MAP_PRIVATE, -1 , 0 );
75
- // We cannot check the return value with MAP_FAILED as that is the return
76
- // of the mmap function and not the mmap syscall.
77
- if (mmap_ret_val < 0 && static_cast <uintptr_t >(mmap_ret_val) > -app.page_size )
78
- LIBC_NAMESPACE::syscall_impl<long >(SYS_exit, 1 );
79
- uintptr_t thread_ptr = uintptr_t (reinterpret_cast <uintptr_t *>(mmap_ret_val));
80
- uintptr_t tls_addr = thread_ptr + size_of_pointers + padding;
81
- LIBC_NAMESPACE::inline_memcpy (reinterpret_cast <char *>(tls_addr),
82
- reinterpret_cast <const char *>(app.tls .address ),
83
- app.tls .init_size );
84
- tls_descriptor.size = alloc_size;
85
- tls_descriptor.addr = thread_ptr;
86
- tls_descriptor.tp = thread_ptr;
87
- }
88
-
89
- void cleanup_tls (uintptr_t addr, uintptr_t size) {
90
- if (size == 0 )
91
- return ;
92
- LIBC_NAMESPACE::syscall_impl<long >(SYS_munmap, addr, size);
93
- }
94
-
95
- static void set_thread_ptr (uintptr_t val) { __arm_wsr64 (" tpidr_el0" , val); }
96
-
97
- using InitCallback = void (int , char **, char **);
98
- using FiniCallback = void (void );
99
-
100
- extern " C" {
101
- // These arrays are present in the .init_array and .fini_array sections.
102
- // The symbols are inserted by linker when it sees references to them.
103
- extern uintptr_t __preinit_array_start[];
104
- extern uintptr_t __preinit_array_end[];
105
- extern uintptr_t __init_array_start[];
106
- extern uintptr_t __init_array_end[];
107
- extern uintptr_t __fini_array_start[];
108
- extern uintptr_t __fini_array_end[];
109
- }
110
-
111
- static void call_init_array_callbacks (int argc, char **argv, char **env) {
112
- size_t preinit_array_size = __preinit_array_end - __preinit_array_start;
113
- for (size_t i = 0 ; i < preinit_array_size; ++i)
114
- reinterpret_cast <InitCallback *>(__preinit_array_start[i])(argc, argv, env);
115
- size_t init_array_size = __init_array_end - __init_array_start;
116
- for (size_t i = 0 ; i < init_array_size; ++i)
117
- reinterpret_cast <InitCallback *>(__init_array_start[i])(argc, argv, env);
118
- }
119
-
120
- static void call_fini_array_callbacks () {
121
- size_t fini_array_size = __fini_array_end - __fini_array_start;
122
- for (size_t i = fini_array_size; i > 0 ; --i)
123
- reinterpret_cast <FiniCallback *>(__fini_array_start[i - 1 ])();
124
- }
125
-
126
- } // namespace LIBC_NAMESPACE
127
-
128
- using LIBC_NAMESPACE::app;
129
- using LIBC_NAMESPACE::AuxEntry;
130
-
131
- __attribute__ ((noinline)) static void do_start() {
132
- auto tid = LIBC_NAMESPACE::syscall_impl<long >(SYS_gettid);
133
- if (tid <= 0 )
134
- LIBC_NAMESPACE::syscall_impl<long >(SYS_exit, 1 );
135
- LIBC_NAMESPACE::main_thread_attrib.tid = static_cast <int >(tid);
136
-
137
- // After the argv array, is a 8-byte long NULL value before the array of env
138
- // values. The end of the env values is marked by another 8-byte long NULL
139
- // value. We step over it (the "+ 1" below) to get to the env values.
140
- uint64_t *env_ptr = app.args ->argv + app.args ->argc + 1 ;
141
- uint64_t *env_end_marker = env_ptr;
142
- app.env_ptr = env_ptr;
143
- while (*env_end_marker)
144
- ++env_end_marker;
145
-
146
- // Initialize the POSIX global declared in unistd.h
147
- environ = reinterpret_cast <char **>(env_ptr);
148
-
149
- // After the env array, is the aux-vector. The end of the aux-vector is
150
- // denoted by an AT_NULL entry.
151
- Elf64_Phdr *program_hdr_table = nullptr ;
152
- uintptr_t program_hdr_count;
153
- app.auxv_ptr = reinterpret_cast <AuxEntry *>(env_end_marker + 1 );
154
- for (auto *aux_entry = app.auxv_ptr ; aux_entry->id != AT_NULL; ++aux_entry) {
155
- switch (aux_entry->id ) {
156
- case AT_PHDR:
157
- program_hdr_table = reinterpret_cast <Elf64_Phdr *>(aux_entry->value );
158
- break ;
159
- case AT_PHNUM:
160
- program_hdr_count = aux_entry->value ;
161
- break ;
162
- case AT_PAGESZ:
163
- app.page_size = aux_entry->value ;
164
- break ;
165
- default :
166
- break ; // TODO: Read other useful entries from the aux vector.
167
- }
168
- }
169
-
170
- app.tls .size = 0 ;
171
- for (uintptr_t i = 0 ; i < program_hdr_count; ++i) {
172
- Elf64_Phdr *phdr = program_hdr_table + i;
173
- if (phdr->p_type != PT_TLS)
174
- continue ;
175
- // TODO: p_vaddr value has to be adjusted for static-pie executables.
176
- app.tls .address = phdr->p_vaddr ;
177
- app.tls .size = phdr->p_memsz ;
178
- app.tls .init_size = phdr->p_filesz ;
179
- app.tls .align = phdr->p_align ;
180
- }
181
-
182
- // This descriptor has to be static since its cleanup function cannot
183
- // capture the context.
184
- static LIBC_NAMESPACE::TLSDescriptor tls;
185
- LIBC_NAMESPACE::init_tls (tls);
186
- if (tls.size != 0 )
187
- LIBC_NAMESPACE::set_thread_ptr (tls.tp );
188
-
189
- LIBC_NAMESPACE::self.attrib = &LIBC_NAMESPACE::main_thread_attrib;
190
- LIBC_NAMESPACE::main_thread_attrib.atexit_callback_mgr =
191
- LIBC_NAMESPACE::internal::get_thread_atexit_callback_mgr ();
192
- // We register the cleanup_tls function to be the last atexit callback to be
193
- // invoked. It will tear down the TLS. Other callbacks may depend on TLS (such
194
- // as the stack protector canary).
195
- LIBC_NAMESPACE::atexit (
196
- []() { LIBC_NAMESPACE::cleanup_tls (tls.tp , tls.size ); });
197
- // We want the fini array callbacks to be run after other atexit
198
- // callbacks are run. So, we register them before running the init
199
- // array callbacks as they can potentially register their own atexit
200
- // callbacks.
201
- LIBC_NAMESPACE::atexit (&LIBC_NAMESPACE::call_fini_array_callbacks);
202
-
203
- LIBC_NAMESPACE::call_init_array_callbacks (
204
- static_cast <int >(app.args ->argc ),
205
- reinterpret_cast <char **>(app.args ->argv ),
206
- reinterpret_cast <char **>(env_ptr));
207
-
208
- int retval = main (static_cast <int >(app.args ->argc ),
209
- reinterpret_cast <char **>(app.args ->argv ),
210
- reinterpret_cast <char **>(env_ptr));
211
-
212
- LIBC_NAMESPACE::exit (retval);
213
- }
214
-
215
- extern " C" void _start () {
9
+ #include " startup/linux/do_start.h"
10
+ extern " C" [[noreturn]] void _start () {
216
11
// Skip the Frame Pointer and the Link Register
217
12
// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
218
13
// Section 6.2.3. Note that this only works if the current function
@@ -223,7 +18,7 @@ extern "C" void _start() {
223
18
// will take us to the previous stack pointer. That is the reason why the
224
19
// actual business logic of the startup code is pushed into a non-inline
225
20
// function do_start so that this function is free of any stack usage.
226
- app.args = reinterpret_cast <LIBC_NAMESPACE::Args *>(
21
+ LIBC_NAMESPACE:: app.args = reinterpret_cast <LIBC_NAMESPACE::Args *>(
227
22
reinterpret_cast <uintptr_t *>(__builtin_frame_address (0 )) + 2 );
228
- do_start ();
23
+ LIBC_NAMESPACE:: do_start ();
229
24
}
0 commit comments