知識積累->目標文件裏有什麼(2)->解析一段代碼

編譯一段具有代表性的代碼:

int printf(const char *format,...);
int global_init_var=84;
int global_uninit_var;
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2;
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

我們使用gcc來編譯這個文件(參數-c表示只編譯不鏈接

gcc -c main.c

我們的到了一個1K的目標文件(文件大小可能會因爲編譯器版本及機器平臺不同而變化)

我們使用objdump指令查看此目標文件的結構和內容:

我們看到了6段內容:

text即代碼段;data即數據段:保存已經初始化的全局變量和已經初始化的局部靜態變量(我們之後會實驗證明);cstring裏面存儲的應該是字符串常量(我們之後會實驗證明);

後幾段我們以後再探究;

我們將分析一下代碼段的內容:

contents of section__text就是text數據以16進制打出來的內容,查看結果,可以很明顯的看出,裏面包含的正是main.c裏面的兩個函數func1和main;

data段保存的是那些已經初始化的全局靜態變量和已經初始化的局部靜態變量,在代碼中,這種變量一共有兩個:global_init_var和static_var;每個變量爲int類型,每個4字節,加起來正好8字節。

其值分別是84(16進製表示爲54,2進製表示爲01010100)和85(16進製爲55,2進製表示爲01010101);

在調用printf的時候,用到了一個字符串常量“%d\n”它屬於一種只讀數據,因此被放到了cstring段,它的大小爲4字節,恰好是一個指針的長度,可以認爲它存儲了一個指針;

有觀點認爲:bss段存儲的是未初始化的全局靜態變量和未初始化的局部靜態變量;

我們開始實驗上面說過的結論:

我們修改一下代碼:

新增一個字符串常量,新增一個字符串變量:

int printf(const char *format,...);
int global_init_var=84;
int global_uninit_var;
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2;
    char *p="Hello,World";//新增字符串常量
    char *q;//新增字符串變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

我們使用命令行查看相關內容 

我們發現,與上一段相比,cstring段有所增加,增加了8個字節;text段也有所增加,我們需要確認是否只有字符串常量存儲到了cstring段而變量沒有,我們再修改一下代碼,看一下生成的.o文件的相關信息

int printf(const char *format,...);
int global_init_var=84;
int global_uninit_var;
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2;
    //char *p="Hello,World";//註釋掉新增的字符串常量
    char *q;//新增字符串變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

我們可以看出,註釋掉了定義的字符串常量,cstring的長度恢復到了之前的4字節,雖然有新定義的字符串變量,但是沒有影響到cstring段。

因此:cstring裏面存儲的應該是字符串常量;

我們再調整一下代碼,查看一下data字段的內容信息

int printf(const char *format,...);
int global_init_var=84;
int global_init_var0=85;//新增了一個初始化的全局變量
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2;
    //char *p="Hello,World";//新增字符串常量
    char *q;//新增字符串變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

之前,data段的大小是 00000008(16進制),新增了一個初始化的全局變量之後,變成了0000000c(16進制),兩者之間之差恰好是4個字節;

我們再修改一下代碼,查看一下相關信息:

int printf(const char *format,...);
int global_init_var=84;
int global_init_var0=85;//新增了一個初始化的全局變量
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2=85;//新增一個初始化的局部靜態變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

data的長度變成了10(16進製爲10,2進製爲10000,10進製爲16),正好新增了4個字節;

我們再新增一些未初始化的全局靜態變量和局部靜態變量,查看一下結果:

int printf(const char *format,...);
int global_init_var=84;
int global_init_var0=85;
int global_uninit0;//新增了未一個初始化的全局變量
int global_uninit1;//新增了未一個初始化的全局變量
int global_uninit2;//新增了未一個初始化的全局變量
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2=85;
    int static static_var3;//新增一個未初始化的局部靜態變量
    int static static_var4;//新增一個未初始化的局部靜態變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

data段沒有變化;

因此:data(即數據段):保存已經初始化的全局變量和已經初始化的局部靜態變量;

我們修改一下代碼,研究一下bss段

int printf(const char *format,...);
int global_init_var=84;
int global_init_var0=85;
//int global_uninit0;//新增了未一個初始化的全局變量
//int global_uninit1;//新增了未一個初始化的全局變量
//int global_uninit2;//新增了未一個初始化的全局變量
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2=85;
    //int static static_var3;//新增一個未初始化的局部靜態變量
    int static static_var4;//新增一個未初始化的局部靜態變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

編譯,查看相關信息:

我們可以看出,未初始化的靜態局部變量會被放在bss段中

我們再修改一下代碼,查看相關信息

int printf(const char *format,...);
int global_init_var=84;
int global_init_var0=85;
int global_uninit0;//新增了未一個初始化的全局變量
//int global_uninit1;//新增了未一個初始化的全局變量
//int global_uninit2;//新增了未一個初始化的全局變量
void func1(int i){
    printf("%d\n",i);
}
int main(void) {
    static int static_var=85;
    int static static_var2=85;
    //int static static_var3;//新增一個未初始化的局部靜態變量
    int static static_var4;//新增一個未初始化的局部靜態變量
    int a=1;
    int b;
    func1(static_var+static_var2+a+b);
    return a;
}

bss段沒有變化!!!說明,未初始化的全局靜態變量並沒有存儲在bss段,有些資料(如《程序員的自我修養》)中的觀點,Linux操作系統將未初始化的全局靜態變量也存儲在bss段,但是mac並未遵循這一規則!

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