From zero to main(): Bare metal C

Thanks for nice article.

Recently I started reading this blog and its really helpful.

I mostly code in IDE so I am not familiar with commands line. Like you wrote some command to look into .elf file. I tried same. I was able to get address for function but unable to find _sbss, _ebss. Can you please help?

Also I am planing to learn commands line program for arm. Would be great if you can suggest any blog,

Hi @chandan_bhatia. _sbss, _ebss, and others are added in the linker script. We set that up in the next episode in the series. Check this out:

Hi @francois , This is a very well written article. Thank you for your contribution.

1 Like

The dump of minimal.elf has the first two bytes as 0x0020 0x0020, so how is it that the stack pointer deduced in the following sentence is 0x20002000? Am I missing something

Hi Rookie,
value is stored in little endian format i.e. least significant byte in lowest address.

@aushacker so we will get 0x00200020, no?

No, working L to R, LSB to MSB:
… … … 00
… … 20 00
… 00 20 00
20 00 20 00

1 Like

ooh right… 0x0020 is actually two bytes (in my head i somehow assumed it was a single byte) and so I was simply doing the first two steps of your explanation. Thanks

Thank you @francois for sharing your knowledge through this article and this series.

I have a question about the initialisation of static variables in the Reset_Handler function.
I might be being pedantic, but would it make more sense to write:

    if (data_ptr != init_values_ptr ) { // I have changed this line
        for (; data_ptr < &_edata;) {
            *data_ptr++ = *init_values_ptr++;

instead of

if (init_values_ptr != data_ptr) {
    for (; data_ptr < &_edata;) {
        *data_ptr++ = *init_values_ptr++;

since, we are setting the values at the addresses of the static variables with the init values, not the other way around?

It is slightly better you are right. Thanks for the note!

A post was split to a new topic: ARMv8M Documentation

Hi Francois,

Thanks for the nice post. One question, always the const variable and global initialized variables are stored after the .text and in .rodata of .text section ?
I thought only the constant variables (const) are stored in .rodata.

They’re both stored at the end of .text. What that section is called vary by linker script and by compiler. Typically only const ends up in rodata, and initialized variables are in .data which is both in ROM (init values) and in RAM (working memory).

Hi @francois the Adafruit CMSIS-DAP debug adapter you linked in your post appears to be discontinued. Can you recommend an alternative that’s compatible with both, the Metro M0 board and your series of blog posts? :slight_smile: Thanks!

@francois You referenced the Reset boot-up behavior as Section 5.9.2 of the Cortex-M3 TRM
For the Cortex-M4 TRM I cannot find anything similar. Would it be fine to just assume the same steps as in the Cortex-M3?

Yes, I noticed they removed that section for the M4 TRM. I think it’s moved to a ARM-v7m manual rather than specific core. In any case, it’s fine to use the same steps.

@francois Why is it uint32_t *init_values_ptr = &_etext; taken at the end of the text section and not uint32_t *init_values_ptr = &_stext; taken at the start of the text section?

From part 2:

.text :
        KEEP(*(.vectors .vectors.*))
        _etext = .;
    } > rom

Because initial values for data are added to flash after the .text section, this is what the AT > rom bit does. Since _etext points to the end of the text section, that’s where we expect the initialization values to be found. It would be better if we had a variable explicitly pointing to the address that AT > rom resolves to, but that’s not something you can do AFAIK.


Could a Nucleo-G070RB be used for “From zero to main(): Bare metal C” in place of the Metro M0 Express and the CMSIS-DAP Adapter.

I see no reason why not. You’ll need to change the memory map of course.