1. 程式人生 > >bss段不佔據磁碟空間的理解

bss段不佔據磁碟空間的理解

elf檔案中.bss段: 存放未初始化的全域性變數,將.data和.bss分開的理由是為了節約磁碟空間,.bss不佔實際的磁碟空間。這句話該怎麼理解呢?  可以看下面的例子:

#include <stdio.h>
int a[1000];
int b[1000] = {1};
int main()
{
    printf("123\n");
    return 0;
}

這裡編寫了一個test.c的檔案,gcc編譯gcc test.c -o test之後,使用ls -l test命令可以得到可執行檔案的資訊,我們只關注檔案的大小為12608。 這裡寫圖片描述  使用命令size test檢視各個段的大小(不包含stack和heap段): 這裡寫圖片描述

  接著我們修改源程式:

#include <stdio.h>
int a[1000] = {1};
int b[1000] = {1};
int main()
{
    printf("123\n");
    return 0;
}

編譯之後,使用ls -l test命令再次檢視可執行檔案的資訊: 這裡寫圖片描述 使用命令size test檢視段的大小: 這裡寫圖片描述  可以看到大小從12608變成了16608,與之前相對比,該檔案佔據的大小漲了4000位元組,這不就是我們的陣列a[1000]的大小嗎?我們所在的改動僅僅是初始化了a[1000],讓這個陣列的所在段從.bss段改到了.data段。通過size test命令檢視bss段的大小也減小了。這就證明了.bss

段中的資料並沒有佔據磁碟空間,從而節約了磁碟的空間。

當程式載入執行時,就會為.bss段中的資料分配記憶體已經進行初始化了。  下面還有兩個疑問,那就是int a[1000]既然不佔據實際的磁碟空間(是指不佔據應該分配的記憶體大小),那麼它的大小和符號存在哪呢? .bss段佔據的大小存放在ELF檔案格式中的段表(Section Table)中,段表存放了各個段的各種資訊,比如段的名字、段的型別、段在elf檔案中的偏移、段的大小等資訊。  我們可以通過命令readelf -S test來檢視test可執行檔案的段表(這裡只截取了一部分): 這裡寫圖片描述

這裡再額外說明一個很有趣的地方,在elf檔案結構中,有一個字串表.strtab

,裡面存放的是elf檔案中各個段的名字以及變數名等字串,字串表中記錄了這些字串以及對應的下標,需要用到這些字串時,直接用偏移下標去取就行了。段表中存放的段的名字這一項,就是存的.strtab中對應字串的偏移。

.bss段所佔空間的大小存在哪裡解決了,那麼就剩下符號了。  符號當然對應的存在符號表.symtab中了。  我們可以通過命令readelf -s test來檢視: 這裡寫圖片描述 在第49行,我們看到了定義的全域性陣列b[1000]4000那一項表明資料的大小是4000位元組,OBJECT代表是一個變數,GLOBAL代表是作用域是全域性的。

最後我們總結一下: .bss不佔據實際的磁碟空間,只在段表中記錄大小,在符號表中記錄符號。當檔案載入執行時,才分配空間以及初始化。