diff --git a/cpu/native/startup.c b/cpu/native/startup.c index 2be966573bae8d22b8f30ec2fdf12d16f0b3a604..7a361fbd7c02e1bb9ef1f7d2ab341d55305f1a82 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -43,6 +43,9 @@ #include "native_internal.h" #include "tty_uart.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + typedef enum { _STDIOTYPE_STDIO = 0, /**< leave intact */ _STDIOTYPE_NULL, /**< redirect to "/dev/null" */ @@ -250,7 +253,22 @@ void usage_exit(int status) real_exit(status); } -__attribute__((constructor)) static void startup(int argc, char **argv) +/** @brief Initialization function pointer type */ +typedef void (*init_func_t)(int argc, char **argv, char **envp); +#ifdef __APPLE__ +/* Taken from the sources of Apple's dyld launcher + * https://github.com/opensource-apple/dyld/blob/3f928f32597888c5eac6003b9199d972d49857b5/src/dyldInitialization.cpp#L85-L104 + */ +/* Find the extents of the __DATA __mod_init_func section */ +extern init_func_t __init_array_start __asm("section$start$__DATA$__mod_init_func"); +extern init_func_t __init_array_end __asm("section$end$__DATA$__mod_init_func"); +#else +/* Linker script provides pointers to the beginning and end of the init array */ +extern init_func_t __init_array_start; +extern init_func_t __init_array_end; +#endif + +__attribute__((constructor)) static void startup(int argc, char **argv, char **envp) { _native_init_syscalls(); @@ -341,6 +359,39 @@ __attribute__((constructor)) static void startup(int argc, char **argv) _native_null_out_file = _native_log_output(stdouttype, STDOUT_FILENO); _native_input(stdintype); + /* startup is a constructor which is being called from the init_array during + * C runtime initialization, this is normally used for code which must run + * before launching main(), such as C++ global object constructors etc. + * However, this function (startup) misbehaves a bit when we call + * kernel_init below, which does not return until there is an abort or a + * power off command. + * We need all C++ global constructors and other initializers to run before + * we enter the normal application code, which may depend on global objects + * having been initalized properly. Therefore, we iterate through the + * remainder of the init_array and call any constructors which have been + * placed after startup in the initialization order. + */ + init_func_t *init_array_ptr = &__init_array_start; + DEBUG("__init_array_start: %p\n", (void *)init_array_ptr); + while (init_array_ptr != &__init_array_end) { + /* Skip everything which has already been run */ + if ((*init_array_ptr) == startup) { + /* Found ourselves, move on to calling the rest of the constructors */ + DEBUG("%18p - myself\n", (void *)init_array_ptr); + ++init_array_ptr; + break; + } + DEBUG("%18p - skip\n", (void *)init_array_ptr); + ++init_array_ptr; + } + while (init_array_ptr != &__init_array_end) { + /* call all remaining constructors */ + DEBUG("%18p - call\n", (void *)init_array_ptr); + (*init_array_ptr)(argc, argv, envp); + ++init_array_ptr; + } + DEBUG("done, __init_array_end: %p\n", (void *)init_array_ptr); + native_cpu_init(); native_interrupt_init(); #ifdef MODULE_NETDEV_TAP