主流的可執(zhí)行文件有:windows下的PE和linux下的ELF舞蔽,他們都是COFF格式的變種荣病。
目標文件:源代碼編譯以后但未進行鏈接的中間文件,它和可執(zhí)行文件格式幾乎一樣渗柿。
各種命名
- 可重定位文件
.o
文件中包含代碼和數(shù)據(jù)个盆,可以被用來鏈接成可執(zhí)行文件或是共享目標文件脖岛,靜態(tài)鏈接庫歸為這一類。
比如我們編譯未連接的目標文件也是這一類 - 可執(zhí)行文件
包含了可執(zhí)行程序颊亮,一般沒有擴展名柴梆。都是鏈接以后的文件了。 - 共享目標文件
.so
包含代碼和數(shù)據(jù)终惑,可以和可重定向文件一起鏈接绍在,產(chǎn)生新的目標文件(不一定是可執(zhí)行文件)”⒂校或者是被動態(tài)鏈接器與可執(zhí)行文件結(jié)合作為進程映像的一部分運行(在堆和棧之間偿渡,靠近棧) - 核心轉(zhuǎn)存文件
core
當進程以外終止時,系統(tǒng)可以將進程地址空間的內(nèi)容以及終止時的一些其他信息轉(zhuǎn)存到核心轉(zhuǎn)存文件霸奕。
目標文件格式
這個目標文件溜宽,可以是上面的4中文件中的一種哈
目標文件中的信息是分類存放的,該放數(shù)據(jù)的放數(shù)據(jù)铅祸,該放代碼的放代碼坑质。一個分類成為節(jié),或者是段临梗。
將文件信息分段存放的目的在于:
- 運行時數(shù)據(jù)和指令分別被映射到不同的虛擬內(nèi)存區(qū)域中涡扼。
在內(nèi)存中:數(shù)據(jù)區(qū)可讀寫,代碼區(qū)只讀盟庞〕曰Γ可以防止程序指令被修改。 - 提高CPU緩存的命中率
數(shù)據(jù)和代碼段分離有利于提高局部性什猖。 - 使得代碼區(qū)可供下個
節(jié)省內(nèi)存票彪。
File Header
該段,主要存儲了不狮,整個文件的屬性降铸,包括文件是否可以執(zhí)行,動態(tài)鏈接還是靜態(tài)連接摇零,入口地址推掸,目標硬件,目標操作系統(tǒng)等息息驻仅。
還有就是一個段表谅畅,保存了該文件中所有端的便宜位置,以及段的屬性噪服。
頭部有一個對應的數(shù)據(jù)結(jié)構(gòu)毡泻,定義在/usr/include/elf.h
中。
其中包括:
e_ident
:主要對應著Magic
,是該文件標識碼粘优。
第一位對應DEL控制符(0x7f)仇味,接下來三位是ELF的ASCII呻顽,第五位01表示32位,02表示63位邪铲,第六位表示字節(jié)序芬位,第七位表示ELF文件的主版本號,主要是1带到,后面的一般用0填充了昧碉。
該字段又被解析為:
e_type
表示文件類型
ET_REL
:可重定向文件1
ET_EXEC
:可執(zhí)行文件2
ET_DYN
:共享目標文件3
e_machine
機器類型
主要是cpu平臺屬性。
e_shoff
段表的起始位置
指出段表在ELF文件中的位置
段表
段又對應一個結(jié)構(gòu)體揽惹,每個段一個被饿,該結(jié)構(gòu)體中主要包含,段名搪搏,段類型狭握,段標志位,段的虛擬地址疯溺,段偏移论颅,段長度,等等囱嫩。
段名只是個名字恃疯,段類型才真正表示該段的類型。
類型包括墨闲,標號為值:
- SHT_NULL無效段
- SHU_PROGBITS程序段今妄,代碼段,數(shù)據(jù)段都是該類型
- SHT_SYMTAB符號表
- SHU_STRTAB字符串表
- SHT_RELA重定位表
等等
段標志指示該段在虛擬地址空間中的屬性鸳碧,可寫盾鳞,需要分配空間,可執(zhí)行瞻离。
代碼段 .code
或.text
一般為.text
,包含了程序中的代碼部分腾仅。
已初始化全局變量和局部靜態(tài)變量 .data
已初始化的全局變量和靜態(tài)局部變量,存儲在.data
段中套利。
也就是我們聲明并定義了的那些變量攒砖。
但是一些字符串常量保存在.rodata
段中。
只讀數(shù)據(jù)段.rodata
該段存放只讀數(shù)據(jù)日裙,一般是程序中的只讀變量,const
修飾的變量和字符串常量惰蜜。
該段的存在保證了程序的安全性昂拂。
上述兩段中的數(shù)據(jù),在文件中就存儲了抛猖。
未初始化全局變量和局部靜態(tài)變量.bss
未初始化的變量格侯,因為沒有值或是默認值鼻听,所以目標文件中不占位置。
但是.bss
段在虛擬內(nèi)存中給這些變量留了空間
同時一些變量初始化為默認值联四,也有可能被編譯器放入.bss
段撑碴。
注釋信息段.comment
存放編譯器的信息,版本號之類的朝墩。
同時我們也可以自己定義一個段:
__attribute__((section("FOO"))) int i = 42;
可以顯示的聲明將該變量放入.FOO
段中醉拓。
重定位表.rel.text
和.rel.data
段類型為SHT_REL
。
編譯器在處理目標文件的時候收苏,不許對某些不問進行重定位亿卤,即代碼段和數(shù)據(jù)段中那些絕對地址的引用位置。這些息息都記錄在ELF文件的重定位表里面鹿霸。
每個需要重定位的代碼段或數(shù)據(jù)段排吴,都會有一個對應的重定位表。
.rel.text
是針對.text
段的重定位表懦鼠。
其中段表的sh_info
對應的值就是所針對的段的下表钻哩。
字符串表.strtab
或.shstrtab
.strtab
字符串表用來保存普通字符串,后一個.shstrtab段表字符串表肛冶,用來保存段表中用到的字符串街氢,常見的就是表名。我們自己定義的淑趾。 .shstrtab
其在段表中的下表就是File Head結(jié)構(gòu)中e_shstrndx
阳仔。所以,系統(tǒng)讀取了ELF文件的表頭扣泊,就可以獲得段表和段名近范,從而解析了整個ELF文件。
符號表.symtab
符號表中存儲著程序所有的(全局的延蟹,可以被其他模塊引用或引用其他模塊)變量名评矩,函數(shù)名,局部變量和函數(shù)阱飘,還有段名斥杜,行號信息(指令在源代碼中對應位置),每一個符號對應一個符號值沥匈,變量和函數(shù)的符號值就是他們的地址蔗喂。
符號表中的每一項也是一個結(jié)構(gòu)體
對應的是:符號名,符號值高帖,符號對應的類型的大小缰儿,符號類型,0散址,符號所在段乖阵。
st_info
:符號類型可選為:
-
STB_LOCAL
局部符號0宣赔,對于目標文件外部不可見 -
STB_GLOBAL
全度符號1,對外部可見 -
STB_WEAK
弱引用2
另外鏈接器還自己定義了幾個符號瞪浸。
符號修飾語函數(shù)簽名
修飾機制是用來防止靜態(tài)變量名字沖突的儒将。
.debug
在編譯的時候使用-g
,可以額外生成該段对蒲。