計算機系統篇之鏈接(10):.bss、.data 和 .rodata section 之間的區別

計算機系統篇之鏈接(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,而不是放到.bsssection 中。對於 C++ 程序,無論是 gcc 還是 g++,都會將程序中未初始化的全局變量放到.bsssection 中。關於這一點,有興趣的可以自己驗證下。

區別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,都會存放到.rodatasection 中;否則,判斷是否已初始化且初始值是否爲0。如果已初始化且初始值非0,則存放到.datasection 中;否則,存放到.bsssection 中。

如果你覺得本文對你有所幫助,歡迎關注公衆號,支持一下!

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章