GCC全过程详解+剖析生成的.o文件
使用GCC編譯一個(gè).c文件影藏了哪些過程?
?
GCC四步詳解
第一步:預(yù)處理(也叫預(yù)編譯)
????????gcc -E ?hello.c ?-o hello.i
? ??? ??或者 cpp hello.c > hello.i ? ? 【cpp是預(yù)編譯器】
? ??? ??將所有#define刪除,并且展開所有的宏定義
? ??? ??處理所有的條件預(yù)編譯指令,如#if #ifdef ?#undef ?#ifndef ?#endif #elif
? ??? ??處理#include,將包含的文件插入到此處,這是一個(gè)遞歸的過程
? ??? ??刪除所有注釋 ? // ? /* */
? ??? ??添加行號(hào)和文件名標(biāo)識(shí),以便于編譯時(shí)產(chǎn)生的錯(cuò)誤警告能顯示行號(hào)
? ??? ??保留#pragma編譯器指令
第二步:編譯
? ??? ??gcc ?-S ?hello.i ? -o ?hello.s
? ??? ??將預(yù)處理完的.i文件進(jìn)行一系列的詞法分析、語法分析、語義分析及優(yōu)
? ??? ??化后生成相應(yīng)的匯編代碼文件,這是整個(gè)程序構(gòu)建的最核心的部分,也是最復(fù)雜的部分
第三步:匯編
????????gcc ?-c ?hello.s ?-o ?hello.o或者 as ?hello.s -o ?hello.o
????????匯編是將第二步生成的匯編代碼變成機(jī)器可執(zhí)行的指令,每一個(gè)匯編語句幾乎都對(duì)應(yīng)一條機(jī)器指令
第四步:鏈接
?????????鏈接動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)
?
生成的目標(biāo)文件有什么,什么是目標(biāo)文件?
目標(biāo)文件就是源代碼經(jīng)過編譯后但未進(jìn)行鏈接的那些中間文件
Linux下的 .o文件就是目標(biāo)文件,目標(biāo)文件和可執(zhí)行文件內(nèi)容和
格式幾乎都一樣,所以我們可以廣義地將目標(biāo)文件和可執(zhí)行文化
看成一類型文件。他們都是按照ELF文件格式存儲(chǔ)的
?
Linux下有哪些ELF類型的文件?
.o文件、可執(zhí)行文件、核心轉(zhuǎn)儲(chǔ)文件(core dump)、.so文件(動(dòng)態(tài)鏈
鏈接庫(kù))
?
可執(zhí)行文件的概貌詳解
File ?Header 、.text section 、.data section 、.bss section
文件頭(File Header)
描述了整個(gè)文件的文件屬性,包括目標(biāo)文件是否可執(zhí)行、是靜態(tài)鏈接還 是動(dòng)
態(tài)鏈接及入口地址、目標(biāo)硬件、目標(biāo)操作系統(tǒng)等信息、段表(描述文件中各
個(gè)段的偏移位置及屬性等)
代碼段(.text)
存放了程序源代碼編譯后生成的機(jī)器指令
數(shù)據(jù)段(.data)
存放已初始化的全局靜態(tài)與非靜態(tài)變量和已初始化的局部靜態(tài)變量
.bss段
存放未初始化的全局變量(全局靜態(tài)和非靜態(tài)變量)和局部靜態(tài)變量
但是.bss段只是為這些變量預(yù)留位置而已,并沒有內(nèi)容,所以這些變量
在.bss段中也不占據(jù)空間
?
深入挖掘 .o文件
使用命令:
?
objdump ?-h ?xxxx.o
????????打印主要段的信息
objdump ?-x ?xxxx.o?
????????????打印更多的詳細(xì)信息
objdump ?-s ?xxx.o
????????????將所有段的內(nèi)容以16進(jìn)制方式打印出來
objdump ?-d ?xxx.o ?或者-S
????????????將所有包含指令的段反匯編
objdump ? -t ? xxx.o
????????????查看所有的符號(hào)以及他們所在段
readelf ?-h ? xxx.o
????????????查看.o文件的文件頭詳細(xì)信息
readelf ? -S ? xxx.o
????????????顯示.o文件中的所有段,即查看段表
size xxx.o
????????????查看.o文件中各個(gè)段所占大小
nm xxx.o?
????????????查看.o文件中所有的符號(hào)
使用命令gcc -c test.c編譯下面這個(gè)test.c程序生成test.o文件,然后查看test.o文件結(jié)構(gòu)
?
test.c
?/* this is a test code */
/* test.c */
int printf(const char *format, ...);
int g_var2 = 10;
int g_var2;
void func(int i)
{
printf("%d\n",i);
}
int main(void)
{
static int static_var1 = 20;
static int static_var2;
int var3 = 1;
int var4;
func(static_var1 + static_var2 + var3 + var4);
return var3;
}
然后查看生成的test.o文件的結(jié)構(gòu)
objdump -h test.o
行:
????.text ?:代碼段(存放函數(shù)的二進(jìn)制機(jī)器指令)
????.data :數(shù)據(jù)段(存已初始化的局部/全局靜態(tài)變量、未初始化的全局靜態(tài)變量)
????.bss ?:bss段(聲明未初始化變量所占大小)
????.rodata :只讀數(shù)據(jù)段(存放 " " 引住的只讀字符串)
????.comment :注釋信息段
????.node.GUN-stack :堆棧提示段
列:
????Size:段的長(zhǎng)度
????File Off :段的所在位置(即距離文件頭的偏移位置)
段的屬性:
????CONTENTS:表示該段在文件中存在
????ALLOC :表示只分配了大小,但沒有存內(nèi)容
?
?
關(guān)于.bss段
我們說.bss段是存放未初始化的全局變量(靜態(tài)與非靜態(tài))和局部靜態(tài)變量的
所以我們程序中的g_var2和stactic_var2應(yīng)該都在.bss段中被預(yù)留位置,所以
.bss段的size應(yīng)該是8個(gè)字節(jié),但是結(jié)果卻是4個(gè)字節(jié),怎么回事呢?
這就是不用的編譯器實(shí)現(xiàn)不一樣的原因了,有些編譯器會(huì)將未初始化的全局非靜態(tài)變量放在.bss段,有些則不放,只是預(yù)留一個(gè)未定義的全局變量符號(hào),等到最終鏈接成可執(zhí)行文件的時(shí)候再在.bss段分配空間。而我的編譯器是沒有將g_var2(全局未初始化的非靜態(tài)變量)放在任何段
下面讓我們真正的查看一下g_var2
首先,我們使用 ?readelf -S ?test.o ?查看段表(主要為了查看每個(gè)段的段號(hào))
然后我們?cè)偈褂?readelf -s ?test.o看一下符號(hào)表(我們定義的變量名都是符號(hào),包括函數(shù)名)
?
符號(hào)表里會(huì)顯示這個(gè)符號(hào)所在的位置
我們看到static_var1和g_var1所在段的段號(hào)為3(3是.data段),static_var2所在段的段號(hào)為4(4是.bss段),而g_var2卻沒有被放入任何一個(gè)段,只是用COM標(biāo)記了一下,那這個(gè)COM表示什么意思呢?COM標(biāo)記的符號(hào)被稱為弱符號(hào),一個(gè)變量名是弱符號(hào),則這個(gè)變量的大小在編譯的時(shí)候不能被確定,而在鏈接之后才能確定該變量的大小。test.o文件在鏈接之后,g_var2會(huì)被放入.bss段(當(dāng)然,也只是說明g_var2所需要的空間大小,并不會(huì)存放內(nèi)容),而在程序運(yùn)行的時(shí)候g_var2這樣的變量才會(huì)真正去占用內(nèi)存空間
強(qiáng)制將某變量或者某函數(shù)放入某個(gè)段
__attribute__((section(".data"))) ?int ? g_var2; ? //強(qiáng)制將g_var2放入.data段中
?
各種變量所在位置總結(jié)
????全局已初始化非靜態(tài)變量、局部已初始化靜態(tài)變量會(huì)被放入.data段
????全局未初始化靜態(tài)變量會(huì)被放入.bss段
????全圖未初始化非靜態(tài)變量不會(huì)被放入任何一個(gè)段,只是用COM標(biāo)記一下
總結(jié)
以上是生活随笔為你收集整理的GCC全过程详解+剖析生成的.o文件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cotex-M内核双堆栈指针MSP和PS
- 下一篇: git checkout -b dev