連接學習之obj文件探索

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

配置環境變量 windows

   

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程序 spa

Hello.c .net

   

預處理 3d

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

   

i文件局部 orm

如上圖#後面的數字 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

相關文章
相關標籤/搜索