Electronic – Bare-metal start-up code for Cortex M3 .bss region initialization

armcortex-m3linkermicrocontrollerstm32

I have developed inspired from here a bare metal start-up code for arm cortex M3. However, I encounter the following problem: suppose I declare an uninitialized global variable, say of type unsigned char in main.c

#include ...
unsigned char var; 
...
int main()
{
 ...
}

this makes the .bss region in STM32 f103 starting at _BSS_START=0x20000000 and ending at _BSS_END = 0x20000001. Now, the start up code

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

tries to initialize to zero the whole .bss region. However, inside that while loop the pointer increases with 4 bytes, therefore after one step bss_start_p = 0x20000004 hence it will always be different than bss_end_p which leads to an infinite loop etc.

Is there any standard solution to this? Am I suppose to "force" somehow the dimension of the .bss region to be a multiple of 4? Or should I use a pointer to unsigned char to walk through .bss region? Perhaps something like:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```

Best Answer

As you suspect, this is happening because the unsigned int data type is 4 bytes in size. Each *bss_start_p = 0; statement actually clears four bytes of the bss area.

The bss memory range needs to be aligned correctly. You could simply define _BSS_START and _BSS_END so that the total size is a multiple of four, but this is usually handled by allowing the linker script to define the start and stop locations.

As an example, here is the linker section in one of my projects:

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

The ALIGN(4) statements take care of things.

Also, you may wish to change

while(bss_start_p != bss_end_p)

to

while(bss_start_p < bss_end_p).

This won't prevent the problem (since you might be clearing 1-3 more bytes than you wish), but it could minimize the impact :)