: true;
}
+using InitCallback = void(int, char **, char **);
+using FiniCallback = void(void);
+
+extern "C" {
+// These arrays are present in the .init_array and .fini_array sections.
+// The symbols are inserted by linker when it sees references to them.
+extern uintptr_t __preinit_array_start[];
+extern uintptr_t __preinit_array_end[];
+extern uintptr_t __init_array_start[];
+extern uintptr_t __init_array_end[];
+extern uintptr_t __fini_array_start[];
+extern uintptr_t __fini_array_end[];
+}
+
+static void call_init_array_callbacks(int argc, char **argv, char **env) {
+ size_t preinit_array_size = __preinit_array_end - __preinit_array_start;
+ for (size_t i = 0; i < preinit_array_size; ++i)
+ reinterpret_cast<InitCallback *>(__preinit_array_start[i])(argc, argv, env);
+ size_t init_array_size = __init_array_end - __init_array_start;
+ for (size_t i = 0; i < init_array_size; ++i)
+ reinterpret_cast<InitCallback *>(__init_array_start[i])(argc, argv, env);
+}
+
+static void call_fini_array_callbacks() {
+ size_t fini_array_size = __fini_array_end - __fini_array_start;
+ for (size_t i = 0; i < fini_array_size; ++i)
+ reinterpret_cast<FiniCallback *>(__fini_array_start[i])();
+}
+
} // namespace __llvm_libc
using __llvm_libc::app;
__llvm_libc::self.attrib = &__llvm_libc::main_thread_attrib;
+ __llvm_libc::call_init_array_callbacks(
+ app.args->argc, reinterpret_cast<char **>(app.args->argv),
+ reinterpret_cast<char **>(env_ptr));
+
int retval = main(app.args->argc, reinterpret_cast<char **>(app.args->argv),
reinterpret_cast<char **>(env_ptr));
+
+ __llvm_libc::call_fini_array_callbacks();
+
__llvm_libc::cleanup_tls(tls.addr, tls.size);
__llvm_libc::syscall(SYS_exit, retval);
}
--- /dev/null
+//===-- Loader test to test init and fini array iteration -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "utils/IntegrationTest/test.h"
+
+class A {
+private:
+ int val[1024];
+
+public:
+ A(int i, int a) {
+ for (int k = 0; k < 1024; ++k)
+ val[k] = 0;
+ val[i] = a;
+ }
+
+ // TODO: When we have implementation for __cxa_atexit, an explicit definition
+ // of the destructor should be provided to test that path of registering the
+ // destructor callback for a global.
+ ~A() = default;
+
+ int get(int i) const { return val[i]; }
+};
+
+int GLOBAL_INDEX = 512;
+int INITVAL_INITIALIZER = 0x600D;
+
+A global(GLOBAL_INDEX, INITVAL_INITIALIZER);
+
+int initval = 0;
+__attribute__((constructor)) void set_initval() {
+ initval = INITVAL_INITIALIZER;
+}
+__attribute__((destructor)) void reset_initval() { initval = 0; }
+
+int preinitval = 0;
+void set_preinitval() { preinitval = INITVAL_INITIALIZER; }
+__attribute__((destructor)) void reset_preinitval() { preinitval = 0; }
+
+using PreInitFunc = void();
+__attribute__((section(".preinit_array"))) PreInitFunc *preinit_func_ptr =
+ &set_preinitval;
+
+TEST_MAIN() {
+ ASSERT_EQ(global.get(GLOBAL_INDEX), INITVAL_INITIALIZER);
+ ASSERT_EQ(initval, INITVAL_INITIALIZER);
+ ASSERT_EQ(preinitval, INITVAL_INITIALIZER);
+ return 0;
+}