- 論壇徽章:
- 13
|
本帖最后由 _nosay 于 2016-11-24 18:12 編輯
最近為了理解elf格式規(guī)范中的各種重定位類(lèi)型,暈了。跑出去玩了幾天,終于為每種重定位類(lèi)型,找到了對(duì)應(yīng)的case。elf規(guī)范總共定義了10種重定位類(lèi)型,之所以需要這么多種不同類(lèi)型的重定位信息,是由于如下原因:
① 硬件對(duì)變量和函數(shù)的尋址方式不同,尋找變量要求絕對(duì)地址,尋找函數(shù)要求相對(duì)地址;
② 不同場(chǎng)合下,程序員對(duì)最終可執(zhí)行文件或動(dòng)態(tài)庫(kù)的期望不一樣(位置無(wú)關(guān)、動(dòng)態(tài)庫(kù)函數(shù)重定位延遲),從而加了不同的編譯選項(xiàng)(比如-fPIC、-Ox等);
③ C語(yǔ)言的static、extern特性,導(dǎo)致不同特性的變量或函數(shù)地址可以被確定的時(shí)機(jī)不同;
④ 內(nèi)核加載可執(zhí)行文件,約定從固定地址0x80480000開(kāi)始,但加載.so的起始地址無(wú)法約定(一個(gè)可執(zhí)行程序只有一個(gè)main(),但可能依賴(lài)多個(gè)動(dòng)態(tài)庫(kù))。
疑問(wèn):那整個(gè)系統(tǒng)中,可執(zhí)行程序也不只一個(gè)呀,都約定從相同的起始地址加載,不會(huì)沖突嗎?
因?yàn)槊總(gè)進(jìn)程訪問(wèn)的都是虛擬地址,由內(nèi)核在背后負(fù)責(zé)將不同進(jìn)程的相同虛擬地址,映射到不同的實(shí)際物理地址(屬于內(nèi)核范疇,不理解沒(méi)關(guān)系,不影響對(duì)本貼關(guān)鍵內(nèi)容的理解)。
- 靜態(tài)鏈接/動(dòng)態(tài)鏈接簡(jiǎn)單理解
.c文件中的代碼最終被執(zhí)行,需要經(jīng)歷如下過(guò)程:
① 編譯:詞法解析 → 語(yǔ)法解析 → 靜態(tài)鏈接
② 加載:加載可執(zhí)行文件 → 可執(zhí)行文件啟動(dòng)或執(zhí)行時(shí),加載依賴(lài)的.so文件 → 動(dòng)態(tài)鏈接
本帖僅關(guān)注靜態(tài)鏈接、動(dòng)態(tài)鏈接過(guò)程,靜態(tài)鏈接與動(dòng)態(tài)鏈接區(qū)別:
① 靜態(tài)鏈接處于將1個(gè)或多個(gè).o文件“拼湊”成可執(zhí)行文件階段,處理對(duì)象是文件,文件中的代碼區(qū)沒(méi)有只讀屬性,鏈接過(guò)程中可以直接修改;動(dòng)態(tài)鏈接處于可執(zhí)行文件或.so文件已被加載到內(nèi)存階段,處理對(duì)象是內(nèi)存,內(nèi)核為代碼區(qū)所在的內(nèi)存區(qū)域設(shè)置了只讀屬性,如果代碼區(qū)有內(nèi)容需要重定位,需要在編譯或靜態(tài)鏈接時(shí),事先準(zhǔn)備一個(gè)間接位置(加載到內(nèi)存不會(huì)被設(shè)置只讀屬性),動(dòng)態(tài)鏈接是對(duì)該間接位置進(jìn)行重定位。
② 通過(guò)下圖可以看出,靜態(tài)鏈接將.o的各個(gè)節(jié)“撕開(kāi)”,屬性相同的節(jié)“拼湊”為可執(zhí)行文件的段;動(dòng)態(tài)鏈接是將“整個(gè)”.so文件安排在與可執(zhí)行文件鏡像相獨(dú)立的位置(圖中最簡(jiǎn)化了.o、.so、可執(zhí)行文件的內(nèi)容,用于說(shuō)明靜態(tài)鏈接與動(dòng)態(tài)鏈接的區(qū)別,它們的內(nèi)容遠(yuǎn)遠(yuǎn)不止.data、.text)。
另外,.so文件還涉及到位置無(wú)關(guān)(-fPIC)、延遲加載的選擇(應(yīng)該是跟優(yōu)化級(jí)別有關(guān)),接下來(lái)即將詳細(xì)總結(jié)。
ld.png (18.34 KB, 下載次數(shù): 543)
下載附件
2016-11-21 20:05 上傳
編譯階段,.o文件的全局變量位置不確定,因?yàn)檫@時(shí)無(wú)法確定還有其它哪些.o文件,以及鏈接器將來(lái)會(huì)按什么順序“排列”這些.o文件(見(jiàn)靜態(tài)鏈接示意圖),鏈接階段,.so文件的全局變量位置也不確定,是因?yàn)檫@時(shí)不知道.so文件將來(lái)被加載到進(jìn)程空間的什么位置(見(jiàn)動(dòng)態(tài)鏈接示意圖)。既然不能確定,只能瞎寫(xiě),但計(jì)算機(jī)世界一是一、二是二,瞎寫(xiě)完一定要留下一個(gè)“交待”(重定位項(xiàng)),等將來(lái)時(shí)機(jī)成熟時(shí),再補(bǔ)上正確的值。
table_R_386_32.png (1.81 KB, 下載次數(shù): 554)
下載附件
2016-11-24 13:36 上傳
R_386_32計(jì)算公式:S+A。
S:對(duì)于.o文件,表示全局變量被鏈接器安排的位置或其所在xx節(jié)的起始位置;對(duì)于.so文件,表示全局變量被加載到的虛擬地址。
A:被重定位處的原始值(4字節(jié),由重定位項(xiàng)offset指向)。
暈了,沒(méi)關(guān)系,先看具體的case(看完R_386_32,再理解其它重定位類(lèi)型就有感覺(jué)了):
6處的指令“a1 00 00 00 00”,由于此時(shí)無(wú)法預(yù)測(cè)g1經(jīng)過(guò)加載后的地址,就先寫(xiě)一個(gè)假地址0,16處指令“a1 04 00 00 00”,由于此時(shí)無(wú)法預(yù)測(cè)g3經(jīng)過(guò)鏈接后的位置,就先寫(xiě)一個(gè)假地址4。但0、4都不是編譯器隨意寫(xiě)上的,因?yàn)殡S后做重定位計(jì)算時(shí)要將它們作為A值。
另外,g4是未初始化的static全局變量,所以被“放在”.bss段,所以重定位項(xiàng)指定用.bss節(jié)位置作為S值(“放在”加了引號(hào),是因?yàn)?bss在文件中不占空間,只有一個(gè)結(jié)構(gòu)用于指示加載到內(nèi)存時(shí),它應(yīng)該處于的位置以及大小,比如一萬(wàn)個(gè)0,在程序要執(zhí)行時(shí),才需要為這些0分配內(nèi)存為它們所代表的變量占據(jù)位置,而在文件中不需要分配一萬(wàn)個(gè)字節(jié),它只需要能提供一個(gè)簡(jiǎn)短的信息,提供加載時(shí)能正確的分配一萬(wàn)個(gè)字節(jié)并填充為0即可)。
R_386_32.png (73.5 KB, 下載次數(shù): 556)
下載附件
2016-11-24 11:11 上傳
為了驗(yàn)證圖中提出的問(wèn)題,繼續(xù)分析鏈接該.o文件得到的.so文件:
R_386_32_so.png (138.5 KB, 下載次數(shù): 554)
下載附件
2016-11-24 11:49 上傳
可以看出,對(duì).o留下的不同類(lèi)型重定位項(xiàng),處理結(jié)果不一樣,暫時(shí)只關(guān)注g1、g3,鏈接器(ld)在.so文件中為g1仍然留了一條R_386_32重定位項(xiàng),而為g3留了一條R_386_RELATIVE重定位項(xiàng),再次處理這兩條重定位項(xiàng),就已經(jīng)是加載到內(nèi)存后由動(dòng)態(tài)鏈接器完成了(ld-linux.so.2),計(jì)算公式中的成員含義也會(huì)改變,比如S表示符號(hào)加載到的虛擬地址。
不是說(shuō)內(nèi)核會(huì)為代碼對(duì)應(yīng)的內(nèi)存區(qū)域設(shè)置只讀屬性么,加載到內(nèi)存后還能修改的了嗎?
準(zhǔn)確的說(shuō),內(nèi)核將代碼加載到內(nèi)存,需要做很多處理,設(shè)置只讀只是其中一個(gè),并且在完成重定位之后:“加載→重定位→設(shè)置只讀→執(zhí)行”。
上述這種不加-fPIC選項(xiàng)編譯得到的.so文件,只是單純將一個(gè)完整的二進(jìn)制文件分隔成可執(zhí)行文件和.so文件,將重定位操作延遲到加載時(shí)了,并沒(méi)有發(fā)揮.so關(guān)鍵設(shè)計(jì)意圖:.so共享。
因?yàn)楦鱾(gè)進(jìn)程的虛擬空間使用情況不一樣,會(huì)導(dǎo)致這種情況:進(jìn)程A的100地址空閑,并將libc.so加載到100開(kāi)始的虛擬空間,將.so鏡像中各個(gè)重定位處依據(jù)100地址計(jì)算重定位值,進(jìn)程B的200地址空閑,如果直接將內(nèi)存中已經(jīng)存在的libc.so鏡像映射到200位置,之前按100地址修改的重定位處,就不滿足進(jìn)程B的要求了,所以只能再加載一份libc.so并映射到自己的虛擬空間(稍后說(shuō)明的位置無(wú)關(guān)就是為了解決這個(gè)問(wèn)題)。
table_R_386_PC32.png (1.68 KB, 下載次數(shù): 599)
下載附件
2016-11-24 13:37 上傳
R_386_PC32計(jì)算公式:S+A-P。
S:對(duì)于.o文件,表示鏈接階段全局變量被安排的位置或其所在xx節(jié)起始位置;
對(duì)于.so文件,表示全局變量被加載到的虛擬地址。
A:被重定位處的原始值(4字節(jié),由重定位項(xiàng)offset指向)。
P:重定位項(xiàng)中的offset值。對(duì)于.o、.so文件,表示被重定位處在.o、.so文件中的偏移;對(duì)于可執(zhí)行文件,表示被重定位處被加載到的虛擬地址。
10處的指令“e8 fc ff ff ff”,由于此時(shí)無(wú)法預(yù)測(cè)f1()經(jīng)過(guò)加載后的地址,就先寫(xiě)一個(gè)假地址-4,15處指令“e8 fc ff ff ff”,由于此時(shí)無(wú)法預(yù)測(cè)f2()經(jīng)過(guò)鏈接后的位置,就先寫(xiě)一個(gè)假地址-4。
-4-P解釋?zhuān)菏紫萈代表被重定位處位置(對(duì)于10處指令,P=11,對(duì)于15處指令,P=16),則P+4分別代表下一條指令位置15、1a(運(yùn)行時(shí)就是下一條指令的虛擬地址),而硬件在處理機(jī)器碼e8(call指令)時(shí),不是將緊接著后面的4字節(jié)直接作為跳轉(zhuǎn)地址,而是要加上下一條指令的地址,所以重定位時(shí)只好事先-(P+4)。
對(duì)比說(shuō)明R_386_32的case,g1的A值為0,g3的A值為4,而這里兩條重定位項(xiàng)的A值都是-4,因?yàn)樗鼈兊牟罹囿w現(xiàn)在這兩處,P值本身就不同。
R_386_PC32.png (39.46 KB, 下載次數(shù): 596)
下載附件
2016-11-22 13:05 上傳
為什么f1()、f2()都有重定位項(xiàng),fun()沒(méi)有?
重定位項(xiàng)的生成是根據(jù)調(diào)用,而不是定義。
另外,有了對(duì)R_386_32的理解基礎(chǔ),可以想象將該.o文件鏈接成.so文件,鏈接器會(huì)如何處理重定位項(xiàng),并動(dòng)手驗(yàn)證一下(注意:有些電腦編譯.so文件必須加-fPIC選項(xiàng),一方面可能跟系統(tǒng)是32/64位有關(guān),另一方面可能跟編譯器版本有關(guān))。
R_386_PC32_so.png (54.85 KB, 下載次數(shù): 645)
下載附件
2016-11-24 13:34 上傳
非static函數(shù)fun()調(diào)用static函數(shù)f3(),為什么直接使用相對(duì)偏移即可 ?
當(dāng)前.so加載位置確定,f3()加載位置就確定了,不能確定fun()位置(同鏈接階段無(wú)法通過(guò)R_386_32重定位類(lèi)型確定g1位置一個(gè)道理),那么此時(shí)計(jì)算的相對(duì)位置不也失效了嗎?
table_R_386_GOT32.png (1.82 KB, 下載次數(shù): 615)
下載附件
2016-11-24 13:44 上傳
R_386_GOT32計(jì)算公式:G+A-P。
G:鏈接階段生成的GOT表位置。
A:被重定位處的原始值(4字節(jié),由重定位項(xiàng)offset指向)。
P:重定位項(xiàng)中的offset值,表示被重定位處在.o文件中的偏移。
對(duì)于G的解釋?zhuān)岬紾OT表,什么是GOT表?
通過(guò)R_386_32、R_386_PC32的說(shuō)明可知,不加-fPIC選項(xiàng)編譯得到的.so文件,并沒(méi)有給計(jì)算機(jī)帶來(lái)什么實(shí)惠,因?yàn)樗拇a根據(jù)前一個(gè)進(jìn)程對(duì)它的加載地址完成重定位后,之后其它進(jìn)程不能直接將它映射到自己的虛擬空間使用,因?yàn)樗鼈儗?duì)重定位計(jì)算的基準(zhǔn)不一樣。
got表正是用于將需要重定位的內(nèi)容剝離出來(lái),從大范圍(整個(gè).so的代碼區(qū)域)匯聚到小范圍(.got表),即將加載地址對(duì)代碼區(qū)域的影響,轉(zhuǎn)移到對(duì).got表的影響。所以說(shuō),.so共享并不是完全的共享,各個(gè)進(jìn)程仍然有一個(gè).got表的副本,而.got表往往很小。
主要利用兩個(gè)技巧:
① 在程序編寫(xiě)階段,雖然不知道以下兩條指令真正執(zhí)行后ebx寄存會(huì)得到什么值,但能確定它的含義是當(dāng)時(shí)eip寄存器的值,那么跟這條指令相對(duì)位置固定的運(yùn)行時(shí)地址,在邏輯上都能在編譯階段“獲知”:
call L1
L1: pop ebx
② 那么,在.so文件中相對(duì)于指令區(qū)域確定位置生成一個(gè).got表,.so被執(zhí)行時(shí).got表的絕對(duì)地址也是可以“獲知”的。這樣,就可以用.got表項(xiàng)的絕對(duì)地址,覆蓋原本在指令區(qū)域的重定位處,而.got表中存放將來(lái)才能確定的最終重定位的符號(hào)地址。
一份代碼區(qū)域,多份.got表:
PIC.png (22.66 KB, 下載次數(shù): 604)
下載附件
2016-11-23 11:01 上傳
理解mmap()函數(shù),有助于更深入理解上圖,在此只大概說(shuō)明(涉及內(nèi)核的內(nèi)存管理和文件系統(tǒng)):
mmap.png (6.92 KB, 下載次數(shù): 565)
下載附件
2016-11-23 12:13 上傳
① 假設(shè)進(jìn)程A先將libc.so映射到自己的一塊虛擬空間,當(dāng)首次訪問(wèn)這塊區(qū)間時(shí)發(fā)生缺頁(yè)異常,分配物理頁(yè)面并讀入內(nèi)容,然后建立映射。接著,進(jìn)程B也將libc.so映射到自己的一塊虛擬空間,首次訪問(wèn)這塊區(qū)間仍然會(huì)發(fā)生缺頁(yè)異常,但與其建立映射的物理頁(yè)面,就不用再重新分配讀入了。從而,物理內(nèi)存只需要一份.so的內(nèi)容,就可以供A、B兩個(gè)進(jìn)程使用。
② 思維敏銳的可能會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題:.so文件中如果有全局變量,被多個(gè)進(jìn)程共享,不是會(huì)相互干擾嗎?
COW(寫(xiě)時(shí)復(fù)制):內(nèi)核為虛擬頁(yè)面、物理頁(yè)面都設(shè)置了一些屬性,比如如果對(duì)某個(gè)虛擬頁(yè)面進(jìn)行寫(xiě)操作,就重新分配一個(gè)物理頁(yè)面,復(fù)制內(nèi)容并重新建立映射(為.so數(shù)據(jù)區(qū)分配的頁(yè)面,就具有這樣的屬性)。
③ 各個(gè)進(jìn)程將.so文件映射到自己的虛擬空間,數(shù)據(jù)區(qū)、代碼區(qū)的相對(duì)位置,仍然保持和剛鏈接過(guò)后一致,所以在代碼區(qū)向.got的重定位計(jì)算仍然有效,只不過(guò)動(dòng)態(tài)鏈接器為不同進(jìn)程向.got表初始化全局變量的地址時(shí),要向.got表進(jìn)行寫(xiě)操作,導(dǎo)致每個(gè)進(jìn)程有一個(gè).got副本。
編譯說(shuō)明R_386_32時(shí)使用的case代碼,加上-fPIC選項(xiàng),就能看到編譯器為g1、g2變量在.o文件中生成了R_386_GOT32重定位項(xiàng)(以及為g3、g4變量在.o文件中生成了R_386_GOTOFF重定位項(xiàng),稍后說(shuō)明)。
R_386_GOT32.png (105.25 KB, 下載次數(shù): 549)
下載附件
2016-11-24 15:10 上傳
6、b處兩條指令執(zhí)行后,ecx寄存器會(huì)得到.got表加載地址,為什么?
① 前面已經(jīng)說(shuō)明過(guò)R_386_PC32重定位類(lèi)型,7處經(jīng)過(guò)這種類(lèi)型重定位后,執(zhí)行時(shí)會(huì)跳轉(zhuǎn)到__x86.get_pc_thunk.cx,得到b處指令的加載地址(CPU沒(méi)有提供直接獲取當(dāng)前ip的指令,所以利用call會(huì)將返回地址壓棧的特點(diǎn));
② R_386_GOTPC,提示鏈接器創(chuàng)建.got表,并修改d處的值,保證執(zhí)行時(shí)用它加ecx寄存器可以得到.got表地址(可以通過(guò)R_386_GLOB_DAT類(lèi)型分析過(guò)程,編譯得到的.so驗(yàn)證):
通過(guò)①可能確定,執(zhí)行過(guò)6處指令后ecx得到的b處指令的加載地址,拿什么和它相加可以得到.got表位置呢?
+A:從ecx所指位置往后推2字節(jié)(機(jī)器碼“81 c1”),就到了被重定位處(重定位項(xiàng)中的offset/規(guī)范文檔中的P);
+G-P:再向后推.got表相對(duì)此處的距離,就到.got表了。
注意:$0x2只是作為鏈接器計(jì)算重定位值的A,在執(zhí)行時(shí)就被G-P-2覆蓋了,不要疑惑為什么要從ecx減2,它的含義根本就不是減數(shù)。
table_R_386_GLOB_DAT.png (2.12 KB, 下載次數(shù): 546)
下載附件
2016-11-24 13:44 上傳
R_386_GLOB_DAT計(jì)算公式:S。
對(duì)比R_386_32、R_386_GOT32,就是在編譯.o文件時(shí),加了-fPIC選項(xiàng),R_386_GOT32重定位類(lèi)型就是希望將重定位處從代碼區(qū)域轉(zhuǎn)移到.got表,鏈接階段創(chuàng)建.got表,完成代碼區(qū)域重定位,添加對(duì).got表項(xiàng)的重定位項(xiàng)(轉(zhuǎn)移≠消除)。
將說(shuō)明R_386_GOT32時(shí)編譯得到的.o文件,鏈接成.so文件:
R_386_GLOB_DAT.png (126.13 KB, 下載次數(shù): 554)
下載附件
2016-11-23 14:53 上傳
① 532、537處(對(duì)應(yīng).o文件中6、b處)指令,確實(shí)可以將.got表位置計(jì)算到ecx寄存器中(不過(guò)是結(jié)束位置,后面指令取.got表項(xiàng)地址時(shí),用的是負(fù)偏移,可能不同編譯器不一樣吧,用開(kāi)始位置、結(jié)束位置計(jì)算,道理是一樣的);
② g1、g2的重定位類(lèi)型變成R_386_GLOB_DAT,它是用于告訴動(dòng)態(tài)鏈接器,在確定g1、g2地址時(shí),放到它們的.got表項(xiàng)里(0x1fe8、0x1ff4)。
table_R_386_PLT32.png (1.69 KB, 下載次數(shù): 550)
下載附件
2016-11-24 15:56 上傳
R_386_PLT32計(jì)算公式:L+A-P
與R_386_GOT32、R_386_GLOB_DAT道理相似,R_386_PLT32、R_386_JUMP_SLOT也是為支持PIC定義的重定位類(lèi)型,前者面向的是全局變量,后者面向函數(shù)。
不過(guò)由于為了支持“動(dòng)態(tài)庫(kù)函數(shù)重定位延遲”,在.got.plt表跳轉(zhuǎn)前,還多了一層.plt表跳轉(zhuǎn),.plt表里是一些鏈接器為重定位函數(shù)生成的跳轉(zhuǎn)代碼片段,計(jì)算公式中的L表示為重定位函數(shù)生成的跳轉(zhuǎn)代碼片段在.so文件中的位置(可以通過(guò)R_386_JUMP_SLOT類(lèi)型分析過(guò)程,編譯得到的.so驗(yàn)證)。
R_386_PLT32.png (52.38 KB, 下載次數(shù): 542)
下載附件
2016-11-23 14:33 上傳
table_R_386_JUMP_SLOT.png (1.99 KB, 下載次數(shù): 543)
下載附件
2016-11-24 15:56 上傳
R_386_JUMP_SLOT計(jì)算公式:S
相比鏈接器對(duì)R_386_GLOB_DAT重定位項(xiàng)的處理,R_386_JUMP_SLOT重定位項(xiàng)的處理過(guò)程更復(fù)雜,不光在.so文件中創(chuàng)建.got.plt表,還為f1()、f2()對(duì)應(yīng)生成了f1@plt、f2@plt代碼片段,并將代碼中對(duì)f1()、f2()的調(diào)用,分別替換成對(duì)f1@plt、f2@plt的調(diào)用,同時(shí)對(duì)f1()、f2()的重定位類(lèi)型變成了R_386_JUMP_SLOT,這個(gè)重定位類(lèi)型不會(huì)在.so文件一加載時(shí)就被動(dòng)態(tài)鏈接器處理,而是調(diào)用f1()、f2()的指令首次被執(zhí)行時(shí),才進(jìn)行重定位操作(比如我喜歡學(xué)習(xí)內(nèi)核,但我目前的工作跟內(nèi)核并沒(méi)有多大關(guān)系,聰明的人都是等工作需要的時(shí)候,再學(xué) )。
不防看一下f1()首次被調(diào)用的過(guò)程:
① 562地址處的指令執(zhí)行后,ebx寄存器指向.got.plt表開(kāi)始位置0x2000;
② 568、56d處原本對(duì)f1()、f2()的調(diào)用,被替換為對(duì)f1@plt、f2@plt的調(diào)用:
<f1@plt>:
410: jmp *0x18(%ebx) ;0x2018,f1()在.got.plt表中占據(jù)的表項(xiàng)位置,表項(xiàng)內(nèi)容初始值為0x416,即首次執(zhí)行這條指令時(shí),相當(dāng)于“jmp 0x416”
416: push $0x18
41b: jmp 3d0 <_init+0x2c>
有點(diǎn)奇怪,首次從410→416干嘛要特意繞個(gè)圈?
這個(gè)圈只會(huì)在第一次執(zhí)行f1@plt時(shí)才會(huì)繞,當(dāng)416、41b處指令調(diào)用動(dòng)態(tài)鏈接器,將f1()地址填到.got.plt表項(xiàng)0x2018后,以后再執(zhí)行410處指令時(shí),就相當(dāng)于“jmp f1”了。即:
第一次執(zhí)行f1@plt:410 → 416、41b → f1()
第二次執(zhí)行f1@plt:410 → f1()
而且鏈接器將所有調(diào)用f1()的地方都替換成調(diào)用f1@plt了,所以410→416這個(gè)圈,只會(huì)繞一次,不過(guò)即使這樣,每次調(diào)用f1(),也要先“call <fl@plt>”,所以延遲加載雖然“聰明”,但有得也有失。
R_386_JUMP_SLOT.png (182.62 KB, 下載次數(shù): 536)
下載附件
2016-11-24 16:41 上傳
table_R_386_COPY.png (2.1 KB, 下載次數(shù): 551)
下載附件
2016-11-24 17:21 上傳
R_386_COPY計(jì)算公式:冇
初始化的全局變量和未初始化全局變量,被安排的位置是不同的,分別在.data、.bss,那么,如果某個(gè)模塊通過(guò)extern引用了另外一個(gè)模塊中定義的全局變量,編譯階段是不知道這個(gè)變量是否被初始化了,因?yàn)樗究床坏狡渌?c文件,所以就暫時(shí)把該變量安排在.bss,等鏈接階段得知它如果有初始值的話,就依據(jù)此重定位項(xiàng),修改一下.bss相應(yīng)位置的值。
R_386_COPY.png (105.07 KB, 下載次數(shù): 560)
下載附件
2016-11-24 17:20 上傳
table_R_386_RELATIVE.png (1.84 KB, 下載次數(shù): 544)
下載附件
2016-11-24 17:46 上傳
R_386_RELATIVE計(jì)算公式:B+A
B:.so文件加載地址。
分析R_386_32類(lèi)型時(shí),已經(jīng)說(shuō)明過(guò)R_386_RELATIVE,靜態(tài)變量位置在鏈接階段可以確定在.so文件中的偏移,那么計(jì)算它的加載地址,自然是加上.so文件的加載地址B就可以了。
table_R_386_GOTOFF.png (1.87 KB, 下載次數(shù): 541)
下載附件
2016-11-24 17:34 上傳
R_386_GOTOFF計(jì)算公式:S+A-GOT
編譯說(shuō)明R_386_32時(shí)使用的case代碼,加上-fPIC選項(xiàng),就能看到編譯器為g3、g4變量在.o文件中生成了R_386_GOTOFF重定位項(xiàng)(在分析R_386_GOT32類(lèi)型時(shí)提到過(guò),基于靜態(tài)變量相對(duì)于.so文件加載地址,距離固定,利用GOT表位置進(jìn)行重定位)。
R_386_GOTOFF.png (42.32 KB, 下載次數(shù): 655)
下載附件
2016-11-24 17:58 上傳
table_R_386_GOTPC.png (1.58 KB, 下載次數(shù): 953)
下載附件
2016-11-24 17:28 上傳
R_386_GOTPC計(jì)算公式:GOT+A-P
分析R_386_GOT32類(lèi)型時(shí),已經(jīng)說(shuō)明過(guò)R_386_GOTPC,它與R_386_32類(lèi)似,只不過(guò)一個(gè)用于重定位變量位置,一個(gè)用于重定位.got表位置。
把對(duì)各種重定位類(lèi)型的理解放在同一張表格對(duì)比,它們之間的區(qū)別就暴露的赤裸裸,再也不撲朔迷離了:
(為了xx,需要在xx階段xx,前一階段提供準(zhǔn)備,后一階段完成計(jì)算,或變換為另一種計(jì)算方式)
REL_type.png (9.38 KB, 下載次數(shù): 637)
下載附件
2016-11-24 18:04 上傳
http://www.cnblogs.com/catch/p/3857964.html
http://blog.csdn.net/stonesharp/article/details/12943963
http://blog.csdn.net/wuhui_gdnt/article/details/51035557
http://blog.csdn.net/wuhui_gdnt/article/details/51094732
http://blog.csdn.net/wuhui_gdnt/article/details/51160465
http://jzhihui.iteye.com/blog/1447570
http://blog.csdn.net/yuyin86/article/details/10239479
|
評(píng)分
-
查看全部評(píng)分
|