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的內容
對於以符號號碼開頭的行,下列說明描述了含有與用戶相關的信息的列:
編號行中的最後一列是符號名(修飾名和未修飾名)
來自 <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文件有關的信息:
那麼就至關於把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 |