why the global variable 'i' got the memory of size 8 bytes when it was stored in BSS but got 4 bytes when it was stored in data segment?
First, why 4 bytes in data segment?
As many folks already answered this - The .data segment contains any global or static variables that are initialized beforehand. An integer is of 4 bytes in size and that is reflecting in data segment size when you have global int i=10;
in your program.
Now, why 8 bytes in .bss segment?
You are observing this behavior because of the default linker script of GNU linker GNU ld. You can get information about linker script here.
While linking, GNU linker (GNU ld) is using the default linker script.
The default linker script specifies the alignment for .bss segment.
If you want to see the default linker script, you can do it using command -
gcc -Wl,-verbose main.c
The output of this gcc
command will contain following statement:
using internal linker script:
==================================================
// The content between these two lines is the default linker script
==================================================
In the default linker script, you can find the .bss
section:
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
Here, you can see . = ALIGN(. != 0 ? 64 / 8 : 1);
which indicates the default alignment as 8 bytes.
The program:
#include <stdio.h>
int i;
void main()
{
}
when built with default linker script, 'i' get the memory of size 8 bytes in BSS because of 8 bytes alignment:
# size a.out
text data bss dec hex filename
1040 484 24 1548 60c a.out
[bss = 24 bytes (16 + 8)]
GNU linker provides a provision to pass your own linker script to it and in that case, it uses the script passed to it to build the target instead of default linker script.
Just to try this, you can copy the content of default linker script in a file and use this command to pass your linker script to GNU ld
:
gcc -Xlinker -T my_linker_script main.c
Since you can have your own linker script, so you can make changes in it and see the change in behavior.
In the .bss
section, change this . = ALIGN(. != 0 ? 64 / 8 : 1);
to . = ALIGN(. != 0 ? 32 / 8 : 1);
. This will change the default alignment from 8 bytes to 4 bytes. Now build your target using linker script with this change.
The output is:
# size a.out
text data bss dec hex filename
1040 484 20 1544 608 a.out
Here you can see bss
size is 20
bytes (16 + 4) because of 4 bytes alignment.
Hope this answer your question.