diff --git a/ion/src/device/boot/flash.ld b/ion/src/device/boot/flash.ld index 37c3e5e02..fc68ffec2 100644 --- a/ion/src/device/boot/flash.ld +++ b/ion/src/device/boot/flash.ld @@ -36,15 +36,17 @@ SECTIONS { .text : { . = ALIGN(4); - - /* C++ code calls __cxa_pure_virtual when a pure-virtual method is called. - * This is an error case, so we just redirect it to abort. */ - PROVIDE(__cxa_pure_virtual = abort); - *(.text) *(.text.*) } >FLASH + .init_array : { + . = ALIGN(4); + _init_array_start = .; + KEEP (*(.init_array*)) + _init_array_end = .; + } >FLASH + .rodata : { . = ALIGN(4); *(.rodata) diff --git a/ion/src/device/boot/rt0.cpp b/ion/src/device/boot/rt0.cpp index 5aaade29b..b3a6a8b1a 100644 --- a/ion/src/device/boot/rt0.cpp +++ b/ion/src/device/boot/rt0.cpp @@ -6,11 +6,17 @@ extern "C" { #include #include "../device.h" -extern char _data_section_start_flash; -extern char _data_section_start_ram; -extern char _data_section_end_ram; -extern char _bss_section_start_ram; -extern char _bss_section_end_ram; +typedef void (*cxx_constructor)(); + +extern "C" { + char _data_section_start_flash; + char _data_section_start_ram; + char _data_section_end_ram; + char _bss_section_start_ram; + char _bss_section_end_ram; + cxx_constructor _init_array_start; + cxx_constructor _init_array_end; +} void abort() { #ifdef DEBUG @@ -38,6 +44,16 @@ void start() { size_t bssSectionLength = (&_bss_section_end_ram - &_bss_section_start_ram); memset(&_bss_section_start_ram, 0, bssSectionLength); + /* Call static C++ object constructors + * The C++ compiler creates an initialization function for each static object. + * The linker then stores the address of each of those functions consecutively + * between _init_array_start and _init_array_end. So to initialize all C++ + * static objects we just have to iterate between theses two addresses and + * call the pointed function. */ + for (cxx_constructor * c = &_init_array_start; c<&_init_array_end; c++) { + (*c)(); + } + Ion::Device::init(); ion_app(); diff --git a/liba/Makefile b/liba/Makefile index c27ce43f4..a01f8b0b6 100644 --- a/liba/Makefile +++ b/liba/Makefile @@ -56,6 +56,7 @@ tests += $(addprefix liba/test/, \ # The use of aeabi-rt could be made conditional to an AEABI target. # In practice we're always using liba on such a target. objs += $(addprefix liba/src/aeabi-rt/, \ + atexit.o \ memclr.o \ memcpy.o \ ) diff --git a/liba/src/aeabi-rt/atexit.c b/liba/src/aeabi-rt/atexit.c new file mode 100644 index 000000000..097301d2a --- /dev/null +++ b/liba/src/aeabi-rt/atexit.c @@ -0,0 +1,7 @@ +/* See the "Run-time ABI for the ARM Architecture", Section 4.4.5 */ + +int __cxa_atexit(void (* dtor)(void * this), void * object, void * handle); + +int __aeabi_atexit(void * object, void (*destroyer)(void *), void * dso_handle) { + return __cxa_atexit(destroyer, object, dso_handle); +} diff --git a/libaxx/Makefile b/libaxx/Makefile index 2f64bd449..6911cbcb3 100644 --- a/libaxx/Makefile +++ b/libaxx/Makefile @@ -1 +1,2 @@ objs += $(addprefix libaxx/src/, new.o) +objs += $(addprefix libaxx/src/cxxabi/, atexit.o pure_virtual.o) diff --git a/libaxx/src/cxxabi/atexit.cpp b/libaxx/src/cxxabi/atexit.cpp new file mode 100644 index 000000000..ee32fc39c --- /dev/null +++ b/libaxx/src/cxxabi/atexit.cpp @@ -0,0 +1,14 @@ +/* C++ expects the __dso_handle symbol to be defined to some unique value in + * each dynamic shared object. Even though we're not using dynamic loading, + * we still have to define __dso_handle. */ + +void * __dso_handle = nullptr; + +/* The __cxa_atexit function registers a function to be called when the program + * exits or when a shared library is unloaded. + * We don't support shared libraries and our program should never exit, so we + * can simply do nothing and return zero. */ + +extern "C" int __cxa_atexit(void (*dtor)(void *), void * object, void * handle) { + return 0; +} diff --git a/libaxx/src/cxxabi/pure_virtual.cpp b/libaxx/src/cxxabi/pure_virtual.cpp new file mode 100644 index 000000000..eee71e8aa --- /dev/null +++ b/libaxx/src/cxxabi/pure_virtual.cpp @@ -0,0 +1,10 @@ +extern "C" { +#include +} + +/* C++ code calls __cxa_pure_virtual when a pure-virtual method is called. + * This is an error case, so we just redirect it to abort. */ + +extern "C" void __cxa_pure_virtual() { + abort(); +}