The why:
For a program running from the ROM of a microcontroller there likely is no loader, and the task of zeroing BSS would fall to the program's runtime startup routine (crt0 in the old days). According to the avr-libc manual, you have the option of placing uninitialized variables in the .bss section (which should be all zero) or the .noinit section, which is a .bss subset that does not get zeroed on startup.
This quotation is from linuxquestions.org. I did not use that option. Do
Code: Select all
avr-gcc -I. -c -S -mmcu=<avr device> usbdrv.c
. It outputs usbdrv.o and usbdrv.s. The latter is an assembler source, the C source file translated into assembler. Looking into it, you'll see
Code: Select all
.global __do_copy_data
.global __do_clear_bss
The global variable under discussion is declared in usbdrv.c:
This variable is used, but not declared, in usbdrvasm.S. But gcc (or avr-gcc, it's the same) considers all undeclared variables in an assembler source as externals. So, in usbdrv.s, it looks like this:
Now, if common variables are taken as globals by gcc, we have that usbDeviceId debuts as zero in the executable! The code to clear the .bss section CANNOT be seen in the assembler sources generated by gcc. It lies in some library and put ahead of the programmer's code by the linker. What do you know?