I have a C++ toolchain for the ARM chip SAMD21g18 and I have just recently implemented the __libc_init_array function, so that global C++ objects have their constructors called before main().
I am using the code shown here: https://embeddedartistry.com/blog/2019/04/17/exploring-startup-implementations-newlib-arm/
/* Handle ELF .{pre_init,init,fini}_array sections. */
#include <sys/types.h>
#ifdef HAVE_INITFINI_ARRAY
/* These magic symbols are provided by the linker. */
extern void (*__preinit_array_start []) (void) __attribute__((weak));
extern void (*__preinit_array_end []) (void) __attribute__((weak));
extern void (*__init_array_start []) (void) __attribute__((weak));
extern void (*__init_array_end []) (void) __attribute__((weak));
#ifdef HAVE_INIT_FINI
extern void _init (void);
#endif
/* Iterate over all the init routines. */
void
__libc_init_array (void)
{
size_t count;
size_t i;
count = __preinit_array_end - __preinit_array_start;
for (i = 0; i < count; i++)
__preinit_array_start[i] ();
#ifdef HAVE_INIT_FINI
_init (); //NOTE: I have actually removed this because I Have no init() function
#endif
count = __init_array_end - __init_array_start;
for (i = 0; i < count; i++)
__init_array_start[i] ();
}
#endif
And I have added the following two sections to my linker script:
.preinit_array:
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > ram AT > flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} > ram AT > flash
When debugging a sample project, I see in the debugger that the "count" variable before the last for loop in the function, has value 1, which means the compiler must have found one constructor. I have used arm-none-eabi-objdump to check the section, and it has indeed size 4 (meaning one pointer was added to the section).
However, when the CPU tries to jump to that constructor function, it crashes (in gdb, an exception is raised). I looked at the memory address of the pointer, with the debugger, and it was a very high address, starting at 0xEXXXXXXX, but I think it's an incorrect address becasue in my linker script I Have not those addresses assigined to any function. My linker script is basically this: https://github.com/ataradov/mcu-starter-projects/blob/master/samd21/linker/samd21j18.ld
What could be going on? Is the init() function important for this or, as I Have done, can it be commented? I don't know where that function was supposed to come from nor my toolchain was finding it.