Skip to content

Commit f23076f

Browse files
author
Siva Chandra Reddy
committed
[libc] Add init and fini array iteration to the loader.
Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D130966
1 parent 6a48dc0 commit f23076f

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

libc/loader/linux/x86_64/start.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,35 @@ static bool set_thread_ptr(uintptr_t val) {
9090
: true;
9191
}
9292

93+
using InitCallback = void(int, char **, char **);
94+
using FiniCallback = void(void);
95+
96+
extern "C" {
97+
// These arrays are present in the .init_array and .fini_array sections.
98+
// The symbols are inserted by linker when it sees references to them.
99+
extern uintptr_t __preinit_array_start[];
100+
extern uintptr_t __preinit_array_end[];
101+
extern uintptr_t __init_array_start[];
102+
extern uintptr_t __init_array_end[];
103+
extern uintptr_t __fini_array_start[];
104+
extern uintptr_t __fini_array_end[];
105+
}
106+
107+
static void call_init_array_callbacks(int argc, char **argv, char **env) {
108+
size_t preinit_array_size = __preinit_array_end - __preinit_array_start;
109+
for (size_t i = 0; i < preinit_array_size; ++i)
110+
reinterpret_cast<InitCallback *>(__preinit_array_start[i])(argc, argv, env);
111+
size_t init_array_size = __init_array_end - __init_array_start;
112+
for (size_t i = 0; i < init_array_size; ++i)
113+
reinterpret_cast<InitCallback *>(__init_array_start[i])(argc, argv, env);
114+
}
115+
116+
static void call_fini_array_callbacks() {
117+
size_t fini_array_size = __fini_array_end - __fini_array_start;
118+
for (size_t i = 0; i < fini_array_size; ++i)
119+
reinterpret_cast<FiniCallback *>(__fini_array_start[i])();
120+
}
121+
93122
} // namespace __llvm_libc
94123

95124
using __llvm_libc::app;
@@ -175,8 +204,15 @@ extern "C" void _start() {
175204

176205
__llvm_libc::self.attrib = &__llvm_libc::main_thread_attrib;
177206

207+
__llvm_libc::call_init_array_callbacks(
208+
app.args->argc, reinterpret_cast<char **>(app.args->argv),
209+
reinterpret_cast<char **>(env_ptr));
210+
178211
int retval = main(app.args->argc, reinterpret_cast<char **>(app.args->argv),
179212
reinterpret_cast<char **>(env_ptr));
213+
214+
__llvm_libc::call_fini_array_callbacks();
215+
180216
__llvm_libc::cleanup_tls(tls.addr, tls.size);
181217
__llvm_libc::syscall(SYS_exit, retval);
182218
}

libc/test/integration/loader/linux/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,12 @@ add_integration_test(
5151
libc.src.errno.errno
5252
libc.src.sys.mman.mmap
5353
)
54+
55+
add_integration_test(
56+
init_fini_array_test
57+
SUITE libc-loader-tests
58+
LOADER
59+
libc.loader.linux.crt1
60+
SRCS
61+
init_fini_array_test.cpp
62+
)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===-- Loader test to test init and fini array iteration -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "utils/IntegrationTest/test.h"
10+
11+
class A {
12+
private:
13+
int val[1024];
14+
15+
public:
16+
A(int i, int a) {
17+
for (int k = 0; k < 1024; ++k)
18+
val[k] = 0;
19+
val[i] = a;
20+
}
21+
22+
// TODO: When we have implementation for __cxa_atexit, an explicit definition
23+
// of the destructor should be provided to test that path of registering the
24+
// destructor callback for a global.
25+
~A() = default;
26+
27+
int get(int i) const { return val[i]; }
28+
};
29+
30+
int GLOBAL_INDEX = 512;
31+
int INITVAL_INITIALIZER = 0x600D;
32+
33+
A global(GLOBAL_INDEX, INITVAL_INITIALIZER);
34+
35+
int initval = 0;
36+
__attribute__((constructor)) void set_initval() {
37+
initval = INITVAL_INITIALIZER;
38+
}
39+
__attribute__((destructor)) void reset_initval() { initval = 0; }
40+
41+
int preinitval = 0;
42+
void set_preinitval() { preinitval = INITVAL_INITIALIZER; }
43+
__attribute__((destructor)) void reset_preinitval() { preinitval = 0; }
44+
45+
using PreInitFunc = void();
46+
__attribute__((section(".preinit_array"))) PreInitFunc *preinit_func_ptr =
47+
&set_preinitval;
48+
49+
TEST_MAIN() {
50+
ASSERT_EQ(global.get(GLOBAL_INDEX), INITVAL_INITIALIZER);
51+
ASSERT_EQ(initval, INITVAL_INITIALIZER);
52+
ASSERT_EQ(preinitval, INITVAL_INITIALIZER);
53+
return 0;
54+
}

0 commit comments

Comments
 (0)