計算機系統篇之鏈接(10):.bss、.data 和 .rodata section 之間的區別
Author:stormQ
Friday, 08. May 2020 10:20PM
Section 名稱 | 區別1:用途不同 | 區別2:在目標文件中佔用的空間不同 |
---|---|---|
.rodata | 用於維護只讀數據,比如:常量字符串、帶 const 修飾的全局變量和靜態變量等 | 在目標文件中佔用空間 |
.data | 用於維護初始化的且初始值非0的全局變量和靜態變量(不帶 const 修飾) | 在目標文件中佔用空間 |
.bss | 用於維護未初始化的或初始值爲0的全局變量和靜態變量(不帶 const 修飾) | 不佔用目標文件的空間 |
注:
-
對於未初始化的全局變量和靜態變量的初始值在運行期會被賦爲0。從而,達到 .bss section 用於減少目標文件的大小的目的。
-
臨時變量(即局部非靜態變量)既不出現在
.data
中,也不出現在.bss
中。它由運行期棧維護。 -
嚴格地講,gcc 將 C 程序(以 .c 結尾的源文件)中的未初始化的全局變量標記爲
COMMON
,而不是放到.bss
section 中。對於 C++ 程序,無論是 gcc 還是 g++,都會將程序中未初始化的全局變量放到.bss
section 中。關於這一點,有興趣的可以自己驗證下。
區別1和區別2的驗證過程:
# 查看 sum.cpp
$ cat sum.cpp
int sum(int a, int b)
{
static int val_1;
static int val_2 = 0;
static int val_3 = 1;
static int val_4 = 0;
static int val_5 = 2;
const static int val_6 = 0;
return a + b;
}
# 生成可重定位目標文件 sum.o
$ g++ -c sum.cpp -o sum.o
# 查看 sum.o 的 sections
$ readelf -S sum.o
There are 12 section headers, starting at offset 0x340:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
0000000000000014 0000000000000000 AX 0 0 1
[ 2] .data PROGBITS 0000000000000000 00000054
0000000000000008 0000000000000000 WA 0 0 4
[ 3] .bss NOBITS 0000000000000000 0000005c
000000000000000c 0000000000000000 WA 0 0 4
[ 4] .rodata PROGBITS 0000000000000000 0000005c
0000000000000004 0000000000000000 A 0 0 4
[ 5] .comment PROGBITS 0000000000000000 00000060
0000000000000033 0000000000000001 MS 0 0 1
[ 6] .note.GNU-stack PROGBITS 0000000000000000 00000093
0000000000000000 0000000000000000 0 0 1
[ 7] .eh_frame PROGBITS 0000000000000000 00000098
0000000000000038 0000000000000000 A 0 0 8
[ 8] .rela.eh_frame RELA 0000000000000000 000002c8
0000000000000018 0000000000000018 I 10 7 8
[ 9] .shstrtab STRTAB 0000000000000000 000002e0
000000000000005c 0000000000000000 0 0 1
[10] .symtab SYMTAB 0000000000000000 000000d0
0000000000000180 0000000000000018 11 15 8
[11] .strtab STRTAB 0000000000000000 00000250
0000000000000078 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
從上面的 sum.o 的 sections 信息,可以看出:
1).data
的大小爲 8(Size 列的值爲 0000000000000008),在目標文件中佔用 8 字節(00000054~0000005c);
2).bss
的大小爲 12(Size 列的值爲 000000000000000c),在目標文件中佔用 0 字節(.bss
在目標文件中的偏移量爲 0000005c,.bss
下一個 section——comment
在目標文件中的偏移量爲 0000005c)。因此,可以得出結論:.bss
不佔用目標文件的空間。
3).rodata
的大小爲 4(Size 列的值爲 0000000000000004),在目標文件中佔用 4 字節(0000005c~00000060)。從而,驗證了"區別2:在目標文件中佔用的空間不同"。
4)sum.cpp 中初始化的且初始值非0的變量(不帶 const 修飾)有兩個:val_3、val_5,佔用 8 字節,與.data
的大小一致;未初始化的或初始值爲0的變量(不帶 const 修飾)有三個:val_1、val_2、val_4,佔用 12 字節,與.bss
的大小一致;帶 const 修飾的全局變量和靜態變量有一個:val_6,佔用 4 字節,與.rodata
的大小一致。從而,驗證了"區別1:用途不同"。
最後,可以總結出對於 C++ 程序中一個全局變量或靜態變量到底存放在.rodata
、.data
、.bss
中哪一個 section 的判斷規則爲:首先判斷全局變量或靜態變量是否帶 const 修飾。如果帶 const 修飾, 無論初始值是否爲0,都會存放到.rodata
section 中;否則,判斷是否已初始化且初始值是否爲0。如果已初始化且初始值非0,則存放到.data
section 中;否則,存放到.bss
section 中。
如果你覺得本文對你有所幫助,歡迎關注公衆號,支持一下!