[riot-devel] RIOT and static initializers in C++

DangNhat PhamHuu phamhuudangnhat at gmail.com
Sat Sep 20 20:49:31 CEST 2014


Hi Hiesgen, Raphael,
Thanks for sharing for finding with us :-)

Currently, on native port, a RIOT program will be started like this
(some details are omitted):
(default internal linker script is used in native port)
Loader loaded program to memory
→ call _start → call libc_start_main → call libc_csu_init
                                                            → call
main (will never be called like normal startup sequences in RIOT)

In __libc_csu_init , it will call the contructor functions which are
placed in __init_array table just like normal startup sequence for
Linux programs ([1]). In this table ( __init_array ) we have the RIOT
startup code and the code for C++ static initialization.
As we can see that in normal startup sequence, all functions in
__init_array will be executed before branching to main, but in RIOT,
RIOT’s startup code will never return after it has been called in
__libc_csu_init (RIOT’s startup code then init the kernel and create
the main thread with our application).
Unfortunately, gcc will placed constructor functions to __init_array
table in the order of their declarations. Thus, static initialization
for bar is placed after RIOT’s startup code and will never been
called.
To work around with this we can put the priority (101 to 65535, lower
is higher priority) for these constructor functions (in
/cpu/native/startup.c and our main.cpp) like this. [2] [3]

diff --git a/cpu/native/startup.c b/cpu/native/startup.c
index 88004aa..605de99 100644
--- a/cpu/native/startup.c
+++ b/cpu/native/startup.c
@@ -192,7 +192,7 @@ The order of command line arguments matters.\n");

 }

-  __attribute__((constructor)) static void startup(int argc, char **argv)
+  __attribute__((constructor (65535))) static void startup(int argc,
char **argv)
 {
     _native_init_syscalls();

#include "stdio.h"

using namespace std;

struct foo {
  foo() : data(1) { }
  int data;
};

static foo bar __attribute__ ((init_priority (101)));

int main() {
  printf("%d\n", bar.data);
}

Then you will see the static initialization has been called and 1 will
be printed.
As I haven’t found better solution for now, so it’s just a workaround
to make thing works.

For some other platforms such as arm-based ones (iot-lab_M3, etc.),
RIOT has provided the linker script with init_array section and
startup code with libc_init_array function. Therefore, C++ static
initialization can be used when C++ support has been provided for
these platforms.

P/S: please don’t use <iostream> but use <cstdio> instead as
currently, we don’t support some C++ headers like this [4].

[1] http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html
[2] https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
[3] https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#C_002b_002b-Attributes
[4] https://github.com/RIOT-OS/RIOT/wiki/Using-CPP-on-RIOT


More information about the devel mailing list