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

Ludwig Ortmann ludwig.ortmann at fu-berlin.de
Mon Sep 22 19:21:17 CEST 2014


Hi,

I tested some alternative approaches today, sadly these only work on
Linux, at least out of the box.

The one I like most (and it looks most promising as well) is
overriding the implementation of __libc_start_main.
The problem is, that on FreeBSD (and OS X) it ends up not being
called.
I think this may be solved by LD_PRELOAD'ing a library that only takes
care of overriding the libc implementation of this function.
The downside of that approach would be that RIOT native would not be
one binary one can simply run anymore.
Here's the branch that works on Linux only at the moment:
https://github.com/LudwigOrtmann/RIOT/tree/native-startup-2

The other approach (which works with gcc only and I could not get to
work on OSX even with gcc) is to use --wrap to wrap the call to main
with the native startup code:
https://github.com/LudwigOrtmann/RIOT/tree/native-startup

I am once again seriously considering just dropping the support for
OSX and FreeBSD altogether...

Opinions welcome!

Cheers, Ludwig

On Mon, Sep 22, 2014 at 02:29:22PM +0200, Ludwig Ortmann 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


More information about the devel mailing list