It's been a while since I worked with ELF. But I think I still remember this stuff. No, it does not physically contain these zeros. If you look at the header of the ELF file program, you will see that each header has two numbers: one is the size in the file. And one more size that the partition has when allocated in virtual memory ( readelf -l ./a.out ):
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 RE 0x4 INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x00454 0x00454 RE 0x1000 LOAD 0x000454 0x08049454 0x08049454 0x00104 0x61bac RW 0x1000 DYNAMIC 0x000468 0x08049468 0x08049468 0x000d0 0x000d0 RW 0x4 NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
LOAD type headers are files that are copied to virtual memory when a file is loaded for execution. Other headers contain other information, such as shared libraries, that are needed. As you can see, the values ββof FileSize and MemSiz significantly different for the header containing the bss section (the second LOAD one):
0x00104 (file-size) 0x61bac (mem-size)
In this example, the code:
int a[100000]; int main() { }
The ELF specification states that part of a segment whose memory size is larger than the file size is simply filled with zeros in virtual memory. The segment display in sections of the second LOAD header is as follows:
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
So there are other sections. For constructor / destructor C ++. The same goes for Java. It then contains a copy of the .dynamic section and other materials useful for dynamic linking (I believe this is the place that contains the necessary shared libraries, among other things). After that, a .data section containing initialized global variables and local static variables. At the end, the .bss section appears, which is filled with zeros at boot time because the file size does not apply to it.
By the way, you can see in which output section a particular character will be placed using the -M linker option. For gcc, you use -Wl,-M to add an option to the linker. The above example shows that a stands out inside .bss . This can help you verify that your uninitialized objects are indeed in .bss and not somewhere else:
.bss 0x08049560 0x61aa0 [many input .o files...] *(COMMON) *fill* 0x08049568 0x18 00 COMMON 0x08049580 0x61a80 /tmp/cc2GT6nS.o 0x08049580 a 0x080ab000 . = ALIGN ((. != 0x0)?0x4:0x1) 0x080ab000 . = ALIGN (0x4) 0x080ab000 . = ALIGN (0x4) 0x080ab000 _end = .
GCC saves uninitialized global values ββin the GENERAL section by default for compatibility with older compilers, which allow you to globally define global values ββin a program without definition errors. Use -fno-common so that GCC uses .bss sections for object files (it doesnβt matter for the final linked executable because, as you can see, it gets into the .bss output section anyway. This is controlled by the script linker. Display it with using ld -verbose ). But this should not scare you, it is just an internal detail. See the gcc man page.