Correct way to initialise C library in newlib nano build?

Asked by S. Mäki-Mantila on 2017-09-08

I'm having trouble setting up newlib nano build for STM32F409 Cortex-M4 to call C library initialisations.

I used minimum.c as base edited linker script nokeep.ld:

  FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x20000 /* 128K */
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 /* 64K */

With this minimum example compiles and I can run it.

Now if I try to modify example to call library initialisations. I suspect that call to _start should do that? In original example (startup_ARMCM4.S) __START is defined to main. I tried minimum example without __START defined and added call to main:

#ifndef __START
#define __START _start
 bl __START

 bl main

Now what happens is that CPU gets to signal handler HardFault or UsageFault when running _start function.

   0x0000007c <+56>: cmp r0, #0
   0x0000007e <+58>: beq.n 0x86 <_start+66>
   0x00000080 <+60>: ldr r0, [pc, #48] ; (0xb4 <_start+112>)
   0x00000082 <+62>: nop.w
   0x00000086 <+66>: bl 0x154 <__libc_init_array>
   0x0000008a <+70>: movs r0, r4
   0x0000008c <+72>: movs r1, r5
   0x0000008e <+74>: bl 0xc4 <main>

I can run code to *0x86 and somewhere in __libc_init_array it will get signal handler called. I can't get to breakpoint in *0x8a:

Program received signal SIGINT, Interrupt.
UsageFault_Handler () at startup_ARMCM4.S:237
237 b .
(gdb) bt
#0 UsageFault_Handler () at startup_ARMCM4.S:237
#1 <signal handler called>
#2 0x000001bc in ?? ()
#3 0x0000016c in __libc_init_array ()
#4 0x20000060 in impure_data ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Should I even call _start? I can call __libc_init_array instead of _start directly but it wont call any constructors, should it?

This won't get called:
void init_test_var(void) {
 test_var = 0x10;

To summarize. How should one call C library init on newlib nano build? And should __libc_init_array handle all constructors?

Question information

English Edit question
GNU Arm Embedded Toolchain Edit question
No assignee Edit question
Last query:
Last reply:
S. Mäki-Mantila (smantila) said : #1

There might be bug or something fishy happening in the linker state.

I have tracked the problem to _init function that gets called from: _start -> __libc_init_array -> _init. And the issue seems to come from '-Wl,--gc-sections' that is used in linker stage.

Minimum sample code and others too use GC=-Wl,--gc-sections flag for linker but if this is not used code is generated correctly and version works correctly (without -Wl,--gc-sections):
00000210 <_init>:
 210: b5f8 push {r3, r4, r5, r6, r7, lr}
 212: bf00 nop
 214: bcf8 pop {r3, r4, r5, r6, r7}
 216: bc08 pop {r3}
 218: 469e mov lr, r3
 21a: 4770 bx lr

Now if one compiles with the flag 'GC=-Wl,--gc-sections' for linker it will crash. As these functions seem to be linked wrong and
CPU will execute straight over to 0x194 and crash:

0000018c <_init>:
 18c: b5f8 push {r3, r4, r5, r6, r7, lr}
 18e: bf00 nop

00000190 <_fini>:
 190: b5f8 push {r3, r4, r5, r6, r7, lr}
 192: bf00 nop

00000194 <_global_impure_ptr>:
 194: 0000 2000

I tested this with the latest 6-2017-q2-update and also (gcc 5.4.1) 5-2016-q3-update. Both seem to work the same.

Launchpad Janitor (janitor) said : #2

This question was expired because it remained in the 'Open' state without activity for the last 15 days.

Greg Whiteley (greg-whiteley) said : #3

Thanks for these notes - they were very helpful to me.

The following mod to nokeep.ld got me up and running:

@@ -50,8 +50,8 @@

- *(.init)
- *(.fini)
+ KEEP(*(.init)) /* need to KEEP() otherwise gc-sections drops the second half in crtn.o */
+ *(.fini) /* but we'll never run .fini so ok to drop */

   /* .ctors */

(you can KEEP() .fini too if you need it of course)

Not sure if this is a bug that needs fixing upstream or not.