Zhani Baramidze Zhani Baramidze - 27 days ago 107
C Question

how exactly do bare metal C applications start?

I'm trying to understand how bare metal C applications work exactly. I wrote my own startup assembly code that calls

__libc_init_array
, I saw it iterating over
preinit_array
section and calling all functions inside. As I understand gcc adds that section for some its own initialization routines that need to run before main, but then comes
_init()
function in the
.init
section.

Does gcc generate that function? Does it come from libc? Or do I have to provide one by my own? What are some good resources to learn those things?

Answer Source

what does symbols have to do with platform? is init_() generated by gcc on one platform and not on another?

Yes the startup and the epiloque routines are left to the implementation, and actually gcc does not generate it.

the libc provides those sysmbols - https://github.com/bminor/newlib/blob/e0f24404b3fcfa2c332ae14c3934546c91be3f42/newlib/libc/misc/init.c

Depending on your target hardware the initialisation may be done completely different way.

Example STM32Fxxx startup.

    .section    .text.Reset_Handler
    .weak   Reset_Handler
    .type   Reset_Handler, %function
Reset_Handler:
  ldr   sp, =_estack    /* Atollic update: set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
  movs  r1, #0
  b LoopCopyDataInit

CopyDataInit:
    ldr r3, =_sidata
    ldr r3, [r3, r1]
    str r3, [r0, r1]
    adds    r1, r1, #4

LoopCopyDataInit:
    ldr r0, =_sdata
    ldr r3, =_edata
    adds    r2, r0, r1
    cmp r2, r3
    bcc CopyDataInit
    ldr r2, =_sbss
    b   LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
    movs    r3, #0
    str r3, [r2], #4

LoopFillZerobss:
    ldr r3, = _ebss
    cmp r2, r3
    bcc FillZerobss

/* Call the clock system intitialization function.*/
    bl  SystemInit
/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
    bl  main

As you see in this implementation two functions are called - one SystemInit for very low lever hardware initialisation and __libc_init_array

it is an internal initialisation of the newlib library (nowadays most common used in the bare metal projects)

The problem is if you decide to do not use standard libraries and you do not want to link any standard libraries. Some tookchains provide weak functions with just the return statement, some not. If you are getting linker problems just comment this call in the startup file or provide an empty function yourself