Bare-metal start-up code for Cortex M3 .bss region initialization
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 :)
Just change !=
to <
. That's usually a better approach anyway, as it deals with problems like this.
The standard solution is memset()
:
#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)
If you can't use the standard library, then you'll have to decide if it's ok in your case to round the size of the memory area up to 4 bytes and continue using unsigned int *
; or if you need to be strict about it, in which case you'd need to use unsigned char *
.
If you do round up the size, like in your first loop, then bss_start_p
may indeed end up greater than bss_end_p
but thats easy to deal with a less-than comparison <
instead of an inequality test.
Of course, you could also fill most of the memory area with 32-bit transfers, and only the last few bytes with 8-bit transfers, but that's more work for little gain, particularly here when it's only a piece of startup code.