diff --git a/libc/arch-common/bionic/crtbegin.c b/libc/arch-common/bionic/crtbegin.c index 1f8dfd2c6..29b02dc97 100644 --- a/libc/arch-common/bionic/crtbegin.c +++ b/libc/arch-common/bionic/crtbegin.c @@ -31,9 +31,9 @@ #include #define SECTION(name) __attribute__((__section__(name))) -SECTION(".preinit_array") void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1; -SECTION(".init_array") void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1; -SECTION(".fini_array") void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1; +SECTION(".preinit_array") init_func_t* __PREINIT_ARRAY__ = (init_func_t*)-1; +SECTION(".init_array.0") init_func_t* __INIT_ARRAY__ = (init_func_t*)-1; +SECTION(".fini_array.0") fini_func_t* __FINI_ARRAY__ = (fini_func_t*)-1; #undef SECTION __used static void _start_main(void* raw_args) { diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h index 0c2e78a01..be7526f5f 100644 --- a/libc/bionic/libc_init_common.h +++ b/libc/bionic/libc_init_common.h @@ -30,10 +30,13 @@ #include +typedef void init_func_t(int, char*[], char*[]); +typedef void fini_func_t(void); + typedef struct { - void (**preinit_array)(void); - void (**init_array)(void); - void (**fini_array)(void); + init_func_t** preinit_array; + init_func_t** init_array; + fini_func_t** fini_array; } structors_array_t; __BEGIN_DECLS diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index e3a447dbe..4a73918f2 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp @@ -60,10 +60,10 @@ __LIBC_HIDDEN__ void* __libc_sysinfo; extern "C" int __cxa_atexit(void (*)(void *), void *, void *); -static void call_array(void(**list)()) { +static void call_array(init_func_t** list, int argc, char* argv[], char* envp[]) { // First element is -1, list is null-terminated while (*++list) { - (*list)(); + (*list)(argc, argv, envp); } } @@ -183,8 +183,8 @@ __noreturn static void __real_libc_init(void *raw_args, // Several Linux ABIs don't pass the onexit pointer, and the ones that // do never use it. Therefore, we ignore it. - call_array(structors->preinit_array); - call_array(structors->init_array); + call_array(structors->preinit_array, args.argc, args.argv, args.envp); + call_array(structors->init_array, args.argc, args.argv, args.envp); // The executable may have its own destructors listed in its .fini_array // so we need to ensure that these are called when the program exits diff --git a/tests/Android.bp b/tests/Android.bp index 58f80170e..a7f622975 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -366,6 +366,7 @@ cc_test_library { "netinet_udp_test.cpp", "nl_types_test.cpp", "poll_test.cpp", + "prio_ctor_test.cpp", "pthread_test.cpp", "pty_test.cpp", "regex_test.cpp", diff --git a/tests/prio_ctor_test.cpp b/tests/prio_ctor_test.cpp new file mode 100644 index 000000000..0dfa66d9d --- /dev/null +++ b/tests/prio_ctor_test.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +static const char* record[4] = {}; +static int idx = 0; + +__attribute__((constructor(1000))) static void prio1000() { + record[idx++] = "prio1000"; +} + +__attribute__((constructor(1))) static void prio1() { + record[idx++] = "prio1"; +} + +__attribute__((constructor)) static void noprio() { + record[idx++] = "noprio"; +} + +TEST(prio_ctor, order) { + EXPECT_EQ(idx, 3); + EXPECT_STREQ(record[0], "prio1"); + EXPECT_STREQ(record[1], "prio1000"); + EXPECT_STREQ(record[2], "noprio"); +}