Browse Source

Merge pull request #6858 from gebart/pr/native-init-ctors

native: Finish iterating constructor calls before moving on to native_cpu_init
pr/rotary
Joakim Nohlgård 5 years ago committed by GitHub
parent
commit
39fcc8bc62
  1. 53
      cpu/native/startup.c

53
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

Loading…
Cancel
Save