亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

連接器,是把目標(biāo)文件連接成可執(zhí)行文件動(dòng)態(tài)庫的工具。

它是將高級(jí)語言代碼轉(zhuǎn)化成二進(jìn)制程序的最后一步。

編譯之后的目標(biāo)文件里,函數(shù)和全局變量的地址并不是真實(shí)內(nèi)存地址,而是一個(gè)重定位符號(hào)。

連接器的作用,就是把這些重定位符號(hào)處理成真實(shí)的內(nèi)存地址。

int printf(const char* fmt, ...);

int main()

printf("hello world");

return 0;

這段代碼在編譯時(shí)有2個(gè)沒法確定的數(shù)據(jù):一是printf()函數(shù)的地址,二是字符串常量"hello world"的地址。

printf()函數(shù)是個(gè)庫函數(shù),它的地址可以在動(dòng)態(tài)庫里,也可以在靜態(tài)庫里,還可以在其他.o文件里,編譯器是沒法提前知道的。

字符串常量"hello world"是一個(gè)全局常量,它要放在.rodata數(shù)據(jù)段里。

.rodata數(shù)據(jù)段的位置編譯器也是沒法確定的,因?yàn)樽罱K可能是多個(gè)目標(biāo)文件連接成1個(gè)可執(zhí)行程序,.rodata數(shù)據(jù)段的具體位置需要連接器來確定。

所以,編譯器就在生成.o文件時(shí)就添加1個(gè)重定位節(jié)、1個(gè)符號(hào)表,他們包含2個(gè)重定位信息:printf()和"hello world"。

然后,由連接器重寫真實(shí)的內(nèi)存地址。

上面代碼用gcc -c編譯成.o文件之后,用readelf -a查看它的信息,如下圖:

ELF頭

從ELF頭可以看出,編譯后的文件是可重定位文件,運(yùn)行的系統(tǒng)架構(gòu)是x86_64。

從它各個(gè)節(jié)的列表里可以找到.rela.text重定位節(jié).rodata節(jié),前者存儲(chǔ)重定位信息,后者存儲(chǔ)常量數(shù)據(jù)。

各個(gè)節(jié)的列表

重定位節(jié).rela.text的內(nèi)容有2條:

1,一個(gè)指向.rodata節(jié),表示這條重定位的地址在.rodata段里。

2,另一個(gè)沒有具體的節(jié),但給了一個(gè)函數(shù)名puts,表示要找的是這個(gè)函數(shù)(gcc在編譯時(shí)都是把printf轉(zhuǎn)化成puts函數(shù))。

重定位節(jié)和符號(hào)表

在上圖的符號(hào)表.symtab節(jié)里,也可以找到這2條信息:

1,其中的第5條(從0開始)就是"hello world"字符串的信息:它是一個(gè)LOCAL的字符串,也就是它的數(shù)據(jù)在當(dāng)前文件里的某個(gè)節(jié)(SECTION),這個(gè)節(jié)的索引號(hào)是5(Ndx列)

去上面的節(jié)列表里查找,可以發(fā)現(xiàn).rodata段確實(shí)是第5個(gè)節(jié)。

2,第11條就是puts()函數(shù)的信息,它是GLOBAL的全局函數(shù),不在當(dāng)前文件的某個(gè)節(jié)里(Ndx是UND,undefined),需要連接器去其他地方找(庫文件、其他.o文件,etc)。

Ndx這一列表示重定位數(shù)據(jù)所在的節(jié),當(dāng)前文件里實(shí)現(xiàn)的函數(shù)或變量都有節(jié)的索引號(hào),但外部全局函數(shù)的索引號(hào)都是不確定的(UND)。

代碼段,main函數(shù)的機(jī)器碼

代碼段.text里的main()函數(shù)的機(jī)器碼可以看出,裝載"hello world"字符串的指令和調(diào)用printf()的指令里的地址都是00 00 00 00。

也就是說,這里需要的真實(shí)內(nèi)存地址是32位的整數(shù),有待連接器進(jìn)一步填寫

00 00 00 00也就是高級(jí)語言里的NULL,在代碼里都是無效的內(nèi)存地址,如果不重填的話肯定會(huì)發(fā)生段錯(cuò)誤

lea指令裝載全局變量時(shí)使用的內(nèi)存地址,是變量地址當(dāng)前指令地址的偏移量

rip,指令指針寄存器,它存的是當(dāng)前指令的地址,x86_64對(duì)全局變量的尋址,都是使用的這種方式。

如果是靜態(tài)連接,連接器把靜態(tài)庫.a和main函數(shù)的.o文件合在一起,然后修改這兩個(gè)地址就可以了。

如果是動(dòng)態(tài)連接,還需要用到全局偏移量表(GOT,global offset table)和PLT(過程連接表,procedure linkage table)。

動(dòng)態(tài)連接之后的ELF頭

gcc動(dòng)態(tài)連接之后生成的可執(zhí)行文件。

以前gcc都是生成可執(zhí)行文件EXEC,現(xiàn)在都是生成動(dòng)態(tài)庫DYN直接運(yùn)行了(即使main函數(shù)所在的文件也這樣)。

上圖ELF頭可以看出類型是DYN,入口地址是0x530。

節(jié)的列表

動(dòng)態(tài)鏈接之后文件有特別多的節(jié),其中以.dyn開頭的都是動(dòng)態(tài)庫相關(guān)的節(jié)。

.plt.plt.got.got,這3個(gè)就是動(dòng)態(tài)連接所必須的節(jié)。

.rela.plt和.rodata依然存在,內(nèi)容和靜態(tài)連接得差不多。

所需的動(dòng)態(tài)庫信息

因?yàn)槌绦蜻\(yùn)行時(shí)要首先加載所需的動(dòng)態(tài)庫,所以必須含有動(dòng)態(tài)庫的信息,如上圖。

這個(gè)程序比較簡(jiǎn)單,只需要libc.so.6庫。

以下兩圖是重定位節(jié)的內(nèi)容和動(dòng)態(tài)庫支持的庫函數(shù)列表,可以看到他們都包含puts()函數(shù),即main()函數(shù)所需的printf()

重定位節(jié)

動(dòng)態(tài)庫函數(shù)的信息

最后簡(jiǎn)單說一下plt和got的內(nèi)容:

plt分為2個(gè)節(jié).plt.plt.got

.plt是只讀的可執(zhí)行代碼,.plt.got是可寫的數(shù)據(jù)。

操作系統(tǒng)不允許在運(yùn)行時(shí)修改代碼只允許在運(yùn)行時(shí)修改數(shù)據(jù),所以動(dòng)態(tài)連接的程序要想獲得庫函數(shù)的地址必須要一個(gè)小技巧[呲牙]

加載器必須把庫函數(shù)的地址放在一個(gè)全局函數(shù)指針變量里,然后讓一段過渡代碼去調(diào)用這個(gè)函數(shù)指針,從而實(shí)現(xiàn)動(dòng)態(tài)運(yùn)行。

這個(gè)全局的函數(shù)指針就是.plt.got里的一項(xiàng)。

當(dāng)程序需要多個(gè)庫函數(shù)時(shí),這些函數(shù)指針就形成了一個(gè)函數(shù)指針數(shù)組,這就是.plt.got表

調(diào)用(多個(gè))庫函數(shù)的過渡代碼數(shù)組就是.plt表:它是有運(yùn)行權(quán)限的,而且是只讀的。

如下圖:

1,最開始的時(shí)候,這個(gè)函數(shù)指針是加載器的加載函數(shù)

2,當(dāng)?shù)谝淮握{(diào)用puts()函數(shù),加載函數(shù)會(huì)去動(dòng)態(tài)庫里查找它的真實(shí)地址,并填寫在這里。

3,之后再調(diào)用時(shí),就直接調(diào)用puts()函數(shù)了。

這是linux系統(tǒng)動(dòng)態(tài)庫函數(shù)的需求加載機(jī)制。

如果是普通變量,把它的地址放在.got表里就行。

動(dòng)態(tài)庫函數(shù)的需求加載

分享到:
標(biāo)簽:連接器
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定