程式設計師的自我修養2目標檔案

2021-03-04 09:56:13 字數 4295 閱讀 1094

table of contents

1、概述目標檔案格式與結構 1

2、舉例說明目標檔案中的各段 3

①編譯並生成目標檔案 3

②使用objdump-h 命令檢視各段基本情況 4

③使用objdump –s –d 挖掘各段內容 5

3、檔案頭 8

4、段表 9

5、重定位表: 11

6、字串表: 11

7、鏈結的介面:符號與符號表 11

8、符號修飾與函式簽名 14

9、強符號與弱符號、強引用與弱引用 15

10、除錯資訊: 16

11、用到的命令: 17

12 動態儲存變數和暫存器變數 17

目標檔案(win .obj/linux .o)裡有什麼?或者說源**在編譯後是怎麼儲存的?

格式:已經是可執行檔案的格式,只是沒有經過鏈結,其中有符號或者位址沒有被調整,本身按照可執行檔案格式儲存。

現在流行的可執行檔案的格式,在windows平台下是pe,在linux平台下是elf格式,前者是擴充套件名為.exe的檔案後者無副檔名。

不光可執行檔案和目標檔案按照這種格式儲存,動態鏈結庫(win .dll/linux .so)和靜態鏈結庫(win .lib/linux .a)。

elf檔案標準把系統中使用elf格式的檔案歸結為:relocatable file (.o .

a) , executable file ,share object file (.so .dll)等。

可以使用file命令檢視檔案格式。

目標檔案和可執行檔案的格式發展歷史幾乎是os發展史,unix最早的可執行檔案格式為a.out格式,設計很簡單,到後來共享庫的概念出現時,a.out格式越來越捉襟見肘了,於是設計了coff格式來解決問題。

unix system v release 3提出了coff格式,微軟基於coff制訂了pe標準,制定、協議、標準!!unix system v release 4在coff的基礎上引入了elf格式。所以pe和elf十分相似。

coff的主要貢獻是在目標檔案中引入了段機制,不同的檔案可以擁有不同數量及不同型別的段。

我們猜想目標檔案中至少有編譯後的指令、資料!除這些之外,目標檔案中還包含了鏈結時所需資訊,如符號表、除錯資訊、字串等。

結構:檔案內容按照不同的屬性放在不同的section/segment,他們都是一定長度的區域,不加區別,唯一的區別實在elf的鏈結檢視和裝載檢視。

**段:.code/.text

資料段:.data存放初始化過的全域性(靜態)變數和靜態區域性變數

.bss段比較特殊,它包含未初始化的靜態變數,但並不是儲存。因為未初始化的靜態變數的值為0,在.

data中開闢空間放它們是對磁碟的浪費。.bss段並不屬於檔案內容,不佔空間。記錄了未初始化的靜態變數的和,為它們預留空間,因為程式執行時需要它們。

file head檔案頭

描述了整個檔案的屬性,包括檔案是否可執行、是靜態鏈結還是動態鏈結(若可執行),目標硬體、目標作業系統等,檔案頭中還有包括段表,是描述檔案中各段資訊的陣列,描述了各段在檔案中的偏移位置及屬性。

**和資料為什麼要分開放?

1、**唯讀,資料可讀寫,當可執行檔案被裝載後,可以被對映到許可權不同的儲存空間。

2、現代cpu的快取機制,分指令cache和資料cache,提高命中率。

3、當程式存在多個副本時,**段共享,資料私有。

-h引數是將各段的基本資訊列印出來(顯示關鍵段、省略輔助性段)。-x會列印出更多的資訊,但是又多又複雜。

暫且忽略後三個段,先關注.txt/.data/.bss

最容易理解的是段的長度size,段所在的位置file offset。第二行是屬性,contents表示該段在檔案中存在。

有乙個專門的命令size可以檢視elf檔案的**段、資料段、bss段。

挖掘各段的內容,我們還是離不開objdump這個利器,-s引數可以將所有段的內容以十六進製制的形式列印出來,-d引數可以將包指令的段反彙編。

最左邊一列是偏移量,中間4列是十六進製制內容,最右邊一列是ascii形式。對於**段.text,共84位元組的內容與size命令的結果一致。

.data段存放已經初始化了的全域性(靜態)變數和區域性靜態變數。前面一共兩個這樣的變數,每個變數4位元組,所以一共8個位元組。

所以.data段一共8位元組大小。.data段的***和55000000對應的是84和85,為什麼不是***呢?

這是cpu的位元組序的問題,也就是所以為的大小端問題。所謂的小端模式,是指資料的高位儲存在記憶體的高位址中,而資料的低位儲存在記憶體的低位址中。

我們在呼叫printf時,使用了乙個字串常量「%d\n」,它是一種唯讀資料,所以被放到了.rodata段:25640a00恰好是字串:

%d\n\0.rodata段存放存放唯讀資料,一般是程式裡面的唯讀變數(如const修飾的變數)和字串常量。

global_uinit_var和static_var2存放在.bss段,更確切的說是為他們倆預留了空間,看到該段只有4位元組,而不是8位元組。我們可以通過符號表看到只有static_var2放在了.

bss段,這跟不同語言與不同的編譯器有關,有些編譯器會將全域性未初始化變數放在.bss段,有些則不會。

除了.txt/.data/.

bss這三個常用的段之外,elf檔案也可能包含其他的段,用來儲存與程式相關的其它資訊。.rodata已經說過了。.***ment存放是編譯器版本資訊。

.debug存放除錯資訊

.dynami動態鏈結資訊

.hash符號雜湊表

.line除錯時的行號表

.note額外的編譯器資訊,如程式的公司名稱、發布版本號等

.symtab符號表

.shstrtab段名錶

.strtab字串表,用於儲存elf檔案中用到的各種字串。

以.開頭的表明這些段名是系統保留的,應用程式也可以使用一些非系統保留的名字作為段名。比如我們可以在elf檔案中插入乙個叫music的段,裡面存放了一首*****,當elf檔案執行起來以後,可以讀取這首**。

現在有乙個image.jpg,大小0x節,我們想把它作為目標檔案的乙個段,怎麼做?

我們在符號表裡看到,「_binary_image_jpg_start」,」…end」,」…size」,表示該**在記憶體中的起始位址、結束位址和大小,我們可以在程式中直接宣告並使用它們。

我們有時希望某些**和變數能夠到指定的段中去,以實現某些特定的功能,如:為了滿足某些硬體記憶體和io布局,或者像是linux作業系統核心中用來完成一些初始化等。gcc提供了一種擴充套件機制,是程式設計師可以制定變數到所處的段:

__attribute__((section(「foo」)))int global = 42;

__attribute__((section(「bar」)))void foo()

elf header描述了整個檔案的基本屬性、比如elf檔案版本、目標機器型號、程式入口位址等。

使用readelf –h檢視目標檔案,檔案頭是個結構體,裡面的變數代表各個屬性值,readelf –h 相當於解析了這個結構體。與elf相關的資料結構在/usr/include的elf.h中。

可以看到,檔案頭中定義了elf魔數、檔案機器位元組長度、資料儲存方式、版本、執行平台、abi版本、elf檔案型別、硬體平台、硬體平台版本、入口位址、程式頭入口位址、段表的位置和長度。

entry point address:入口位址,規定elf程式的入口虛擬位址,作業系統在載入完該程式後從這個位址開始執行程序的命令。可重定位檔案一般沒有入口位址,這個值為0.

start of section header段表在檔案中的偏移。也就是說段表從節開始。

size of section header段表描述符的大小,即描述每個段需要多少位元組。

number of section header :段表描述符的數量,這個值等於elf檔案中擁有的段的數量

elf標準規定用16個位元組的魔數來確認檔案型別、來識別elf檔案的平台屬性。,比如比如上圖中的data/class/version/os/abi/abi version等。比如elf檔案的最開始4個位元組是所有elf檔案必須相同的標識碼,ox7f,ox45,ox4c,ox46,第乙個位元組對應ascii中的del字元,後三個剛好吃elf的ascii碼值。

幾乎所有可執行檔案的格式開始都是魔數,a.out格式的最開始兩個位元組為ox01,ox07;pe/coff

最開始兩個位元組為ox4d,ox5a,即mz。用魔數來確認檔案的型別,作業系統在載入可執行檔案時會確認魔數是否正確,如果不正確則拒絕載入。

程式設計師的自我修養

做到這些,你也能成為一名優秀的程式設計師 1 迷戀技術,保持對 的熱情 興趣是最好的老師,如果不是最初對程式設計充滿興趣,應該很少有人會選擇程式設計師這個行業,但同時程式設計師是乙個有點乏味枯燥的工作。如果你不迷戀技術,對 充滿熱情,那你只能做乙個平淡的程式設計師。2 在實踐中成長,磨礪技術 程式設...

程式設計師自我提高的幾點建議

4 復用性和模組化思想 每個程式設計師在開發乙個功能模組或函式的時候,應該多思考,不要侷限在完成當前任務的簡單思路上,思考一下,該設計的模組能否脫離這個系統存在,是否能夠通過最簡單的修改方式在其他系統或應用環境直接引用。通過這兩年中的實踐與觀察,發現我們團隊一些同事在起步階段,經常經歷 重寫的事情,...

遊戲程式設計師的學習

遊戲開發 乙個遊戲程式設計師的學習資料 一 書籍 演算法與資料結構 資料結構 c語言版 嚴蔚敏 吳偉民清華出版社 我覺得其配套習題集甚至比原書更有價值,每個較難的題都值得做一下。introduction to algorithms 第二版中文名 演算法導論 關於演算法的標準學習教材與工程參考手冊,在...