1. 程式人生 > >鏈接學習之obj文件探索

鏈接學習之obj文件探索

計算 條目 stat table 中一 external 成了 nal cnblogs

Windows的gcc環境,往官網http://sourceforge.net/project/showfiles.php?group_id=2435 下載MinGW,安裝,安裝完畢後按照包

技術分享

配置環境變量

a.在PATH的值中加入"C:\Program Files\MinGWStudio\MinGW\bin"。這是尋找gcc編譯器的路徑。如果PATH中還有其他內容,需要用英文狀態下分號進行分割

b.新建LIBRARY_PATH變量,在其值中加入"C:\Program Files\MinGWStudio\MinGW\lib"。這是標準庫存放的路徑。

c.新建C_INCLUDE_PATH變量,在其值中加入"C:\Program Files\MinGWStudio\MinGW\include"。這是Include查找頭文件的路徑。

先是一個及其簡單的C程序

技術分享

Hello.c

預處理

C:\Users\居士\Desktop\Update\Link C>gcc -E hello.c -o hello.i

i文件局部

技術分享

如上圖#後面的數字 210代表行號 stdio.h中能找到對應代碼

技術分享

編譯

C:\Users\居士\Desktop\Update\Link C>gcc -S hello.i -o hello.s

編譯後的 內容仍然是文本,打開s文件仍然可以看懂其內容

技術分享

學過匯編的人能看懂裏面表達啥,對於我而言只認得pushl,movl,andl等幾個指令,以及%ebp,%esp這幾個寄存器,還有常數$-16,$0。其余cif_offset這些就需要百度才知道了。總體來說還是看不懂的。

匯編

C:\Users\居士\Desktop\Update\Link C>gcc -c hello.s -o hello.o

匯編得到的是一個二進制的文件,是一個可重定向目標文件,裏面包含著機體代碼。這裏雖然表面上是一個o文件,由於本人使用的是Windows平臺,編譯出來的還是類似於通過VC編譯出來的obj格式的文件,而並非Linux平臺下的ELF文件。

在網上找的命令可以通過下面命令看到格式化後的o文件

C:\Users\居士\Desktop\Update\Link C>readelf -a hello.o

技術分享

但是在windows下生成的實際上是obj文件,用VS的另一個工具可以打開,該工具在以下目錄

D:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\dumpbin.exe

命令為dumpbin /all {目標文件文件名} > {輸出文件的文件名}

因此之前看書上面說的ELF文件的格式就對不上了,文件的結構需要找別的資料去參考。這裏借助了dumpbin以外還使用了CFF Explorer。

obj文件內容分析

在網上看過別人分析的obj文件是用在VC下寫的一段很簡單的C++代碼生成的,和我這個用MinGW的gcc下的C程序有出入。

總的來說無論是obj還是o文件,都是基於COFF(Common Object File Format)文件,它與我們平常寫的代碼不一樣,它是有一個一定格式的文件,鏈接器(或加載器)則按照這個結構來鏈接(或執行)這些文件,先羅列一下整個obj文件的結構

File Header 文件頭

Optional Header

Section Header Table 節頭部表

Section Raw Data 節的原始數據

Relocation Table 重定向表

Symbol Table 符號表

String Table 字符串表

再看通過dumpbin生成的文件

FILE HEADER:文件頭

技術分享

這個文件頭在obj文件中占了0~13共14個字節。

技術分享

這個文件頭的大小是固定的,它實際上是winnt.h裏面的一個結構體。細心的可以發現結構中一些值是直接以數值的形式存放在文件中,例如machine的值14C,存放為4C 01,符號表的地址指針1B8,存放成B8 01。我想表達的是因為windows是采用了小段法存放數據的機器,高低位間作了互換。Winnt.h文件在C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include目錄中(我的是64位系統)。結構體定義如下

技術分享

各個字段的解析可以參考MSDN上的內容

結構體解析 https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms680313(v=vs.85).aspx

大體就是說了編譯時機器的情況,時間,還有與本文件關系大的符號表的位置,符號的數量,optional header的數量。

接下來就是各個節的說明了,先已第一個節作為例子,介紹完這個節的結構後再通過CFF Explorer對比o文件裏的內容。再去介紹各個節的作用。

技術分享

這裏包含了節的頭部,節的原始數據,還有一個重定向表,節的頭部是這樣的一個結構

技術分享

頭部的作用是描述整個節的信息,例如SizeOfRawData代表原始數據的數量,PointerToRawData即是原始數據起始的地址。NumberOfRelocations是重定向條目的數量。

節頭部數據結構詳情可參考MSDN中的以下位置 https://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx

Raw Data則是節的原始數據,這裏其實沒啥結構的,不同的節就存放他們對應的數據。

Relocations是重定位信息,實際上它是重定位表的一部分,只屬於這個節的一部分。這個重定向的一個條目結構如下,

技術分享

這個就是在鏈接時給引用外部的符號重定位時用的

以上僅是該o文件中最全的一個節的結構,當然還有可能會有其他的"節成員",只是當前這個C程序太簡單,以致其他成員未出現。但是不是每個節都有原始數據,有些節是空的,有些節就不帶重定向信息。

下面逐個看這個o文件裏面的每個節。

第一個節是.text節,圖不再截了,就之前的那個圖,.text節存放的是已編譯的機器代碼。利用objdump工具可以看到這節的原始數據(也就是機器代碼整理後的結果),命令如下

技術分享

要看懂這些指令的話,還需要懂得處理器的指令集(參考《深入了解計算機系統》的第四章)。

第二節是是data節,按書上的介紹data節是存放已初始化的全局或靜態C變量,這個C程序中沒有用到全局變量或靜態變量,這節就沒有內容

技術分享

第三節是bss節,是存放未初始化的全局或靜態C變量,以及被初始化為0的全局或C變量,但是這個姐實際不占用控件

技術分享

第四個節是rdata節,放的就是只讀數據,這裏存在了一個宏定義,"hello c!"這樣的一個字符串,這部分數據就存放在這一節中

技術分享

第五個節叫"/4",rdata$zzz估計是別名,不知具體的作用,貌似是存放了編譯器的信息,版本之類的

技術分享

第六個節叫"/15",eh_frame,更加不知道他的作用,貌似是有對.text節的引用,難道是調用main函數外層的東西?

技術分享

節部分完結了之後就是符號表

技術分享

符號表的介紹直接引用MSDN的內容

對於以符號號碼開頭的行,下列說明描述了含有與用戶相關的信息的列:

  • 開頭的 3 位數字是符號索引/號碼。
  • 如果第三列包含 SECTx,則符號在對象文件的那一節中定義。 但如果出現 UNDEF,則它不在那個對象中定義並且必須在其他地方被解析。
  • 第五列 (Static, External) 說明符號是否只在那個對象的內部可見,或者是否是公共的(外部可見)。 靜態符號 _sym 不會鏈接到公共符號 _sym;這些符號是名為 _sym 的函數的兩種不同實例。

編號行中的最後一列是符號名(修飾名和未修飾名)

來自 <https://msdn.microsoft.com/zh-cn/library/b842y285.aspx>

每條符號表的記錄是一下的結構

技術分享

有幾條記錄是多出了一行的,那部分數據是對這個符號的補充說明,結構如下

技術分享

在符號表之後就是字符串表了,但是在dumpbin生成d文件中只是列舉了字符串表的大小

技術分享

但在其他資料中介紹,字符串表示存放著節名的字符串。聽過CFF Explorer中的內容查看,確實定義了4個字符川,就是重復的.rdata$zzz和.eh_frame

技術分享

dumpbin如何分析得出這個o文件

那又有一個問題來了,編譯系統是如何根據這份二進制的o文件來讀取到這些信息呢,嘗試一下通過CFF Explorer來分析讀取到這個文件的信息,人為模擬一下dumpbin的工作。這個過程推導出前面那個obj文件結構這個結論。

首先是讀取固定大小的文件頭,通過文件頭的結構獲取到幾個與本個o文件有關的信息:

  • 6個節
  • 符號表的起始位置是1B8,符號數量是12個

    那麽就相當於把o文件已經分成了幾塊

文件頭

未知部分1

符號表

未知部分2

0~13

14~1B7

1B8~??

??~329

那麽節這部分有可能存放在未知部分1中。查看各個節的頭部信息,分析出節1到節6是從104~18F。可以查看各個節的原始數據得出

技術分享

技術分享

其他節就不一一列舉了

另外還有各個節頭部信息中提及到的重定位信息,整個文件有中重定位信息只有兩個節:節1的重定位是190開始;節6的重定位信息是1AE開始,節1的重定位項有3個,節6的重定位項有1個,粗略推斷節1的重定位信息是重190~1AD,節6的重定位信息是1AE~1B7,每條重定位信息的長度大概是10個字節

技術分享

是對應

技術分享

0A 00估計對應Offset,10 00對應Symbol Index,14 00對應Type,可視Applied To這個就解析不清了,因為節6的重定位信息如下

技術分享技術分享

還有字符串表的信息,字符串的大小是一個4字節用小端法存儲的無符號整數,2E應該是2E 00 00 00,縱觀整個文件存放了這個信息的就在位置為2FC處,因此估計字符串表是從2FC處到329結尾處了

文件頭

未知部分1

節原始數據

重定向表

符號表

字符串表

0~13

14~103

104~18F

190~1B7

1B8~2FB

2FC~329

剩余的未知部分1應該就是存放節頭部信息的節頭部表,從14~103,也是通過數量以及數據的比對,節共有6個,此部分數據共240個,平均每個節頭部信息占40個字節,下面就拿了40個字節的信息

技術分享

可以看到節的名稱.text 2E 74 65 78 74;原始數據的起始地址104,就是04 01 00 00;重定向表190,就是90 01 00 00,其他成員就不列舉了。其他頭部也不列舉了。

最終得到的結構是

文件頭

節頭部表

姐原始數據

重定向表

符號表

字符串表

0~13

14~103

104~18F

190~1B7

1B8~2FB

2FC~329

再細分一下的就是

文件頭

0~13

1頭部

14~3B

2頭部

3C~63

3頭部

64~8B

4頭部

8C~B3

5頭部

B4~DB

6頭部

DC~103

1原始數據

104~127

4原始數據

128~133

節5原始數據

134~157

節6原始數據

158~18F

1重定向表

190~1AD

6重定向表

1AE~1B7

符號表

1B8~2FB

字符串表

2FC~329

鏈接學習之obj文件探索