I am learning assembly and it amazed me that, a zero-initialized struct does not occupy in the memory. My code is like that.
// in file a.cpp
#include <stdint.h>
struct Bar {
char filename[8];
// ignore members here
uint32_t filesize;
}__attribute__((packed));
typedef struct FAT_ITEM FAT_ITEM;
Bar bar1 = {
"null",0
};
Bar bar2 = {
"",0
};
then I compile the codes
gcc -march=i386 -m16 -mpreferred-stack-boundary=2 -ffreestanding -O0 a.cpp a.o
ld -melf_i386 -N --oformat binary -o a.bin a.o
However, when I use dd
to read the binary in a.bin, I see
00000000: 6e75 6c6c 0000 0000 0000 0000 null........
(END)
bar2
does not appear in the memory.
the 32-bits zero comes from bar1.filesize
. And (END)
follows.
I am learning 16bits x86 assembly, so the compile options may be strange. But I think they won't cause this problem.
Can anyone help me and explain why bar2
is "ignored"?
The compiler that places zero-inited stuff in the BSS, which the default linker script doesn't allocate space for in a flat binary; it starts after the end of the other sections.
Zero it yourself on startup before your C code runs, or disable the compiler's use of the BSS (e.g. -fno-zero-initialized-in-bss
.
You can look at gcc -S
output; note the .lcomm
or .comm
directives which reserve BSS space for all zero-init static / global variables. When compiling a normal Linux executable, you don't want huge arrays of zeros explicitly stored in the executable.
See https://gcc.gnu.org/ml/gcc-help/2007-07/msg00097.html for some discussion, e.g. you could use an __attribute__
to put an array that actually needs to be zero-inited into a different section, if you don't want to write a zero-init loop that runs on startup. Then you can have some arrays that don't need to be initialized at all still in the BSS, but spend space in your binary for explicit zeros on other things that need it.