Does a .bss string need null initialized variables take up space in the elf file?

If I understand correctly, the .bss section in ELF files is used to allocate space for zero initialized variables. Our tool chain creates ELF files, so my question is: should the .bss section really contain all these zeros? It seems such a terrible waste of spaces that, for example, I allocate a global array with ten megabytes, this leads to ten megabytes of zeros in the ELF file. What am I seeing here wrong?

+41
c ++ elf storage segments
Mar 04 '09 at 2:00
source share
4 answers

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.

+63
Mar 04 '09 at 14:21
source share

The .bss section in the ELF file is used for static data that is not initialized programmatically, but is guaranteed to be set to zero at run time. Here is a small example that will explain the difference.

 int main() { static int bss_test1[100]; static int bss_test2[100] = {0}; return 0; } 

In this case, bss_test1 is placed in .bss , since it is not initialized. bss_test2 , however, fits in the .data segment along with a bunch of zeros. The runtime loader basically allocates the amount of space reserved for .bss and zeroes it out before any custom code starts executing.

You can see the difference using objdump , nm or similar utilities:

 moozletoots$ objdump -t a.out | grep bss_test 08049780 l O .bss 00000190 bss_test1.3 080494c0 l O .data 00000190 bss_test2.4 

This is usually one of the first surprises that embedded developers embed ... never initialize statics to zero. The runtime loader (usually) takes care of this. As soon as you initialize something explicitly, you tell the compiler / linker to include the data in the executable image.

+20
Mar 04 '09 at 14:28
source share

A .bss section is not saved in the executable. Of the most common sections ( .text , .data , .bss ), only .text (actual code) and .data (initialized data) are present in the ELF file.

+2
Mar 04 '09 at 14:19
source share

That's right, .bss is physically absent in the file, and just information about its size is present for the dynamic loader to highlight the .bss section for the application. As a rule of thumb, only LOAD, TLS Segment receives memory for the application program, the rest are used for the dynamic loader.

About static executable, bss sections are also given space in execuatble

An embedded application that does not have a bootloader is a common occurrence.

Suman

+1
Mar 27 '09 at 17:38
source share



All Articles