Code: Select all
/*
* Area fill code, it is a macro because here functions cannot be called
* until stacks are initialized.
*/
static void fill32(void *start, void *end, uint32_t filler) {
uint32_t *p1 = start;
uint32_t *p2 = end;
while (p1 < p2)
*p1++ = filler;
}
The comment doesn't match the actual code. It's a function, not a macro.
And even if it did, I think that clearing the currently in use stack from a naked function is ugly, and just plain wrong, even if it happens to work most of the time. The compiler's documentation explicitly discourages such use.
The crt0 code also violates strict aliasing rules. The compiler doesn't need to care that the memory between &_data and &_edata happens to overlap some global variable, and is permitted to do unexpected things because of that (and it often does). It may happen to work in this case, but...
http://dbp-consulting.com/StrictAliasing.pdf
If you still don't believe me:
Code: Select all
#include <stdio.h>
/* these are provided by default linker sciprts under linux */
extern int __data_start;
extern int _edata;
int a = 7;
short b = 1;
int c = 6;
#define barrier() asm volatile("" ::: "memory")
int main(void) {
short s1 = b;
/*barrier();*/
int *pa = &__data_start;
int *pc = &_edata;
while (pa < pc)
*pa++ = 0;
/*barrier();*/
short s2 = b;
printf("s1: %hd, s2: %hd\n", s1, s2);
return 0;
}
compile using
Code: Select all
gcc -O2 test.c -otest
And see for yourself.
Then, uncomment the two barrier() calls before and after the while loop, and see the change.
In the first case, the program should print:
s1: 1, s2: 1
while in the second:
s1: 1, s2: 0
The compiler's behavior in both cases is correct, even if it's not what you'd expect.