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

DangNhat PhamHuu phamhuudangnhat at gmail.com
Mon Sep 22 19:17:00 CEST 2014


Hi Ludwig,

sorry, I overlooked that this solution still makes it necessary to
specify priorities for initializers

Yeah, this is what I intend to say. :P. This solution is safe but it lead
to an exception for standard C++ in RIOT and is against the friendliness of
RIOT. ( *attribute* ((init_priority (x))) is gcc-specific btw)

The problem we have is startup will be called and never return before other
constructors in __init_array, so we can manually call these constructors,
which haven’t been called before startup. Something like this.

git diff ../../cpu/native/startup.c
diff --git a/cpu/native/startup.c b/cpu/native/startup.c
index 88004aa..2f2f54b 100644--- a/cpu/native/startup.c+++
b/cpu/native/startup.c
@@ -318,5 +318,24 @@ __attribute__((constructor)) static void startup(int argc,
     board_init();

     puts("RIOT native hardware initialization complete.\n");++    /*
manually call other contructors in __init_array which haven't been
called */+    typedef void (*func_ptr)(void);+    extern func_ptr
__init_array_start[];+    extern func_ptr __init_array_end[];++    int
size = __init_array_end - __init_array_start;+    int i, flag = 0;++
 for (i = 0; i < size; i++) {+        if (__init_array_start[i] ==
startup) {+            flag = 1;+            continue;+        }+
  if (flag == 1){+            (__init_array_start[i])();+        }+
}+
     kernel_init();
 }

The code is similar to the one has been mentioned by Pekka Nikander but we
don’t want to call every constructors which has been called (this included
startup, and will lead to infinite recursion). This piece of code still
have one thing that I’m not very sure: __init_array_start and
__init_array_start seem to be linker script-specific and they are defined
in the default linker script (we can get the linker script used by linker
by adding -Wl,--verbose in our LINKFLAGS). These names could be different
among other platforms.

Haven’t tested much yet but with the Hiesgen’s example, it worked on my
Linux Mint 17. :D

In any case, defining the lowest possible priority for native’s
startup.c seems like a good idea to me for now.

If we follow the idea above, we wouldn’t need to define the priority for
startup.
By the way, I can’t find the clear relationship between the constructor
objects with priority and the default one (without priority). On my
machine, it always call the constructors with priority first (even with the
lowest priority). :-)

Cheers,
​

/**
 * @Name: Phạm Hữu Đăng Nhật
 * @StudentID: 51002279
 * @Class: MT10KTTN
 * Ho Chi Minh University of Technology
 * @Mobile: 0164.968.2716
 */

On 22 September 2014 19:29, Ludwig Ortmann <ludwig.ortmann at fu-berlin.de>
wrote:

> Hi,
>
> sorry, I overlooked that this solution still makes it necessary to
> specify priorities for initializers:
>
> > static foo bar __attribute__ ((init_priority (101)));
>
> So, I agree that this still is not overly satisfactory.
>
> In any case, defining the lowest possible priority for native's
> startup.c seems like a good idea to me for now.
>
> Cheers,
> Ludwig
>
> On Sat, Sep 20, 2014 at 10:13:15PM +0200, Ludwig Ortmann wrote:
> > Hi all,
> >
> > Great work!
> > I never got around to fully understand the startup sequence internals (I
> looked into it a bit because the current  implementation also had problems
> in an older FreeBSD release but then the infection went away with the next
> release..) and it sounds like this is a fine solution.
> > Will you open a pull request?
> >
> > Cheers, Ludwig
> >
> > On 20. September 2014 20:49:31 MESZ, DangNhat PhamHuu <
> phamhuudangnhat at gmail.com> wrote:
> > >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
> > >_______________________________________________
> > >devel mailing list
> > >devel at riot-os.org
> > >http://lists.riot-os.org/mailman/listinfo/devel
> >
> > _______________________________________________
> > devel mailing list
> > devel at riot-os.org
> > http://lists.riot-os.org/mailman/listinfo/devel
> _______________________________________________
> devel mailing list
> devel at riot-os.org
> http://lists.riot-os.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.riot-os.org/pipermail/devel/attachments/20140923/c45ae44d/attachment-0001.html>


More information about the devel mailing list