天天看點

了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

目錄

一、準備工作

二、編譯過程

1.預處理

2.編譯

3.彙編

4.連結 

 三、分析 ELF 檔案

1.ELF 檔案的段

 2.反彙編 ELF

 四、參考資料

一、準備工作

先建立一 個工作目錄 test1,然後用文本編輯器生成一個 C 語言編寫的簡單 hello.c 程式為示例,其源代碼如下所示:

#include <stdio.h>
int main(void)
{
printf("Hello World! \n");
return 0;
}
           

二、編譯過程

1.預處理

預處理的過程主要包括以下過程:

(1) 将所有的#define 删除,并且展開所有的宏定義,并且處理所有的條件預編

譯指令,比如#if #ifdef #elif #else #endif 等。

(2) 處理#include 預編譯指令,将被包含的檔案插入到該預編譯指令的位置。

(3) 删除所有注釋“//”和“”。

(4) 添加行号和檔案辨別,以便編譯時産生調試用的行号及編譯錯誤警告行号。

(5) 保留所有的#pragma 編譯器指令,後續編譯過程需要使用它們。

使用 gcc 進行預處理的指令如下:

 gcc -E hello.c -o hello.i

2.編譯

編譯過程就是對預處理完的檔案進行一系列的詞法分析,文法分析,語義分析及優化後生成相應的彙編代碼。

使用 gcc 進行編譯的指令如下:

 gcc -S hello.i -o hello.s
了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

3.彙編

彙編過程調用對彙編代碼進行處理,生成處理器能識别的指令,儲存在字尾為.o的目标檔案中。由于每一個彙編語句幾乎都對應一條處理器指令,是以,彙編相對于編譯過程比較簡單,通過調用 Binutils 中的彙編器 as 根據編指令和處理器指令的對照表一一翻譯即可。當程式由多個源代碼檔案構成時,每個檔案都要先完成彙編工作,生成.o 目标檔案後,才能進入下一步的連結工作。注意:目标檔案已經是最終程式的某一部分了,但是在連結之前還不能執行。

使用 gcc 進行彙編的指令如下: 

gcc -c hello.s -o hello.o
了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

4.連結 

連結也分為靜态連結和動态連結,其要點如下:

(1) 靜态連結是指在編譯階段直接把靜态庫加入到可執行檔案中去,這樣可執行檔案會比較大。連結器将函數的代碼從其所在地(不同的目标檔案或靜态連結庫中)拷貝到最終的可執行程式中。為建立可執行檔案,連結器必須要完成的主要任務是:符号解析(把目标檔案中符号的定義和引用聯系起來)和重定位(把符号定義和記憶體位址對應起來然後修改所有對符号的引用)。

(2) 動态連結則是指連結階段僅僅隻加入一些描述資訊,而程式執行時再從系統中把相應動态庫加載到記憶體中去。

1.在 Linux 系統中,gcc 編 譯鍊 接時的動态庫搜尋路徑順序通常為:首先從 gcc 指令的參數-L 指定的路徑尋找 ;再從環境變量LIBRARY_PATH 指 定的路徑尋址;再從預設路徑/lib、/usr/lib、 /usr/local/lib 尋找 。

2.在 Linux 系統中,執 行二 進制 檔案 時的 動态 庫搜 索路 徑的 順序 通常 為:首 先搜 索編 譯目标 代碼 時指 定的 動态 庫搜 索路 徑;再從環境變量 LD_LIBRARY_PATH 指定的路徑尋址;再從配置檔案/etc/ld.so.conf 中指定動态庫搜尋路徑 ;再從預設路徑/lib、/usr/lib尋找。

3.在 Linux 系統 中, 可以用 ldd指令檢視一個可執行程式依賴的共享庫。 由于連結動态庫和靜态庫的路徑可能有重合,是以如果在路徑中有同名的靜态庫檔案和動态庫檔案,比如 libtest.a 和 libtest.so,gcc 連結時預設優先選擇動态庫,會連結libtest.so,如果要讓 gcc 選擇連結 libtest.a 則可以指定 gcc 選項-static,該選項會強制使用靜态庫進行連結。以 Hello World 為例:

如果使用指令“gcc hello.c -o hello”則會使用動态庫進行連結,生成的

ELF 可執行檔案的大小(使用 Binutils 的 size 指令檢視)和連結的動态庫

(使用 Binutils 的 ldd 指令檢視)如下所示:

gcc hello.c -o hello

size hello //使用 size 檢視大小

ldd hello //可以看出該可執行檔案連結了很多其他動态庫,主要是 Linux的glibc動态

了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

 三、分析 ELF 檔案

1.ELF 檔案的段

ELF 檔案格式如下圖所示,位于 ELF Header 和 Section Header Table 之間的都是段(Section)。一個典型的 ELF 檔案包含下面幾個段:

.text:已編譯程式的指令代碼段。

.rodata:ro 代表 read only,即隻讀資料(譬如常數 const)。

.data:已初始化的 C 程式全局變量和靜态局部變量。

.bss:未初始化的 C 程式全局變量和靜态局部變量。

.debug:調試符号表,調試器用此段的資訊幫助調試。

可以使用 readelf -S 檢視其各個 section 的資訊如下:

readelf -S hello
了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

 2.反彙編 ELF

由于 ELF 檔案無法被當做普通文本檔案打開,如果希望直接檢視一個 ELF 檔案包含的指令和資料,需要使用反彙編的方法。

使用 objdump -D 對其進行反彙編如下:

objdump -D hello
了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

 使用 objdump -S 将其反彙編并且将其 C 語言源代碼混合顯示出來:

gcc -o hello -g hello.c 

objdump -S hello

了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

 四、參考資料

gcc編譯工具集中各軟體的用途,了解EFF檔案格式_fat_yuchen的部落格-CSDN部落格

了解gcc編譯工具集中各軟體的用途與EFF檔案格式一、準備工作二、編譯過程 三、分析 ELF 檔案 四、參考資料

https://blog.csdn.net/fat_yuchen/article/details/120657292