linux内核全局变量重定位,关于可重定位文件中全局变量的一个重定位疑惑,借各位牛刀一用^...
///
不需要牛刀,不需要閱讀源碼,如果只是為解決109的含義。樓主執(zhí)行的查詢命令readelf?-S??test2.o
[?8]?.symtab???????????SYMTAB??????????00000000?0002a8?0000c0?10?????????9???7??4
.symtab起始于2a8,保存了符號(hào)信息,根據(jù)樓主提供的test2.o,從2a8開始,讀到367:
00002a8:???????????? 0000?0000?0000?0000
00002b0:?0000?0000?0000?0000?0100?0000?0000?0000??................
00002c0:?0000?0000?0400?f1ff?0000?0000?0000?0000??................
00002d0:?0000?0000?0300?0100?0000?0000?0000?0000??................
00002e0:?0000?0000?0300?0300?0000?0000?0000?0000??................
00002f0:?0000?0000?0300?0400?0000?0000?0000?0000??................
0000300:?0000?0000?0300?0500?0000?0000?0000?0000??................
0000310:?0000?0000?0300?0600?0900?0000?0000?0000??................
0000320:?0400?0000?1100?0300?0b00?0000?0400?0000??................
0000330:?0400?0000?1100?0300?0d00?0000?0800?0000??................
0000340:?0400?0000?1100?0300?0f00?0000?0000?0000??................
0000350:?0e00?0000?1200?0100?1300?0000?0e00?0000??................
0000360:?5200?0000?1200?0100
我們按照8字節(jié)為一個(gè)整體,數(shù)7個(gè)(前6個(gè)是symtab頭不信息?),到了318:
0900?0000?0000?0000?0400?0000?1100?0300
其中0900就是符號(hào)的具體位置偏移,我們?cè)購(gòu)?68開始看.strtab:
0074?6573?7432?2e63?0061?0062?0063?0066?756e?006d?6169?6e00
自己數(shù)數(shù)09位置是什么?沒錯(cuò)就是61,它是“a”的asic的16進(jìn)制值。
以此類推,0b是“b”,0d是“c”。
講到這里,0109、0108、0107的秘密應(yīng)該大白天下了吧?二樓已經(jīng)講了01是object,你在1100中的第二個(gè)`1`指的就是這個(gè)。而09、08、07,指的就是.symtab按八字節(jié)為一整塊算時(shí)的塊號(hào)罷了!每個(gè)塊代表一個(gè)符號(hào),并給出了strtab中相應(yīng)字符串的位置偏移和屬性解釋!
以上結(jié)論純屬觀察,本人完全不懂編譯原理,哈哈^_^
//
不是搞編譯的,只是記得以前看過一些介紹的文章,嘗試解答一下。
.text+2a:
2a:???ff?35?00?00?00?00???????pushl??0x0
很明顯,這是在push一個(gè)參數(shù),只是在編譯的時(shí)候,由于不知道最后的地址,操作數(shù)暫時(shí)為0。
經(jīng)過了鏈接階段,所有變量的地址都確定了,就可以替換這些臨時(shí)的操作數(shù)了。
如樓主所言,這些信息是保留在elf文件的relcoation?section里的。
代碼中一共有8處引用全局變量
#fun(a,?b,?c)
[2a]:???ff?35?00?00?00?00???????pushl??0x0
[30]:???ff?35?00?00?00?00???????pushl??0x0
[36]:???ff?35?00?00?00?00???????pushl??0x0
[3c]:???e8?fc?ff?ff?ff??????????call???3d?
#func(c,?b,?a)
[44]:???ff?35?00?00?00?00???????pushl??0x0
[4a]:???ff?35?00?00?00?00???????pushl??0x0
[50]:???ff?35?00?00?00?00???????pushl??0x0
[56]:???e8?fc?ff?ff?ff??????????call???57?
.rel.text:
0000380:?[2c00]?0000?<0109>?0000?[3200]?0000?<0108>?0000??,.......2.......
0000390:?[3800]?0000?<0107>?0000?[3d00]?0000?<020a>?0000??8.......=.......
00003a0:?[4600]?0000?<0108>?0000?[4c00]?0000?<0107>?0000??F.......L.......
00003b0:?[5200]?0000?<0109>?0000?[5700]?0000?<020a>?0000??R.......W.......
00003c0:?0a
顯然,.rel.text需要描述這8個(gè)對(duì)全局變量的引用,并觀察到[]里的地址的相似性,
因此可以推測(cè),每個(gè)引用占8個(gè)字節(jié)。
并且,<>里面的部分可以分為兩類:6個(gè)傳參的屬于一類01**,函數(shù)調(diào)用屬于一類02**。
猜測(cè)**是變量/函數(shù)名在符號(hào)表中的id。
觀察其中一組01類型的:
.text:
[2a]:???ff?35?[00?00?00?00]???????pushl??0x0
.rel.text:
0000380:?[2c00]?0000?<0109>?0000
2c正好是2a(push指令的地址)+2(push操作碼ff35的長(zhǎng)度),這就告訴ld,
在連接的時(shí)候,需要把2c的內(nèi)容(就是push指令的參數(shù))替換掉(當(dāng)前為0)。
替換成什么內(nèi)容,由<0109>決定。01是一種類型,09應(yīng)該是變量在symbol表中的id。
由于樓主沒有貼出test.o經(jīng)過linker鏈接后的結(jié)果,手頭也沒有32bit的機(jī)器,所以就不太好猜了……
最簡(jiǎn)單的可能性是,linker直接替換為變量的絕對(duì)地址。
至于02類型的:
3c:???e8?fc?ff?ff?ff??????????call???3d?
0000398:?[3d00]?0000?<020a>?0000
分析同上,3d=3c(call指定的地址)+1(call操作碼的長(zhǎng)度),就是call的參數(shù)的地址。
我手頭有64bit的機(jī)器,傳參和函數(shù)調(diào)用都被編譯為02類型的,通過readelf可以看到,02屬于R_X86_64_PC32類型。
實(shí)際上,這個(gè)call是個(gè)相對(duì)jmp,參數(shù)是相對(duì)于當(dāng)前ip/pc的偏移,在.o文件里,目的地址是-4(0xfffffffc),就是這條指令本身。
可以想象,在ld階段,-4會(huì)被替換為func函數(shù)跟call指令之間的地址差值。
(實(shí)際上,由于func是編譯單元內(nèi)部的函數(shù)調(diào)用,這個(gè)差值在編譯階段也可以確定的。)
由于<02>是相對(duì)偏移,因此[3c]和[56]雖然都是call?$func,它們的偏移值是不一樣的,所以兩條指令并不相同。
作為對(duì)比,30和4a都是push?$b,如果<01>類型是絕對(duì)地址的話,那么兩條指令就完全一樣。
以上,啰啰嗦嗦的,不知道有沒有說清楚。
1,調(diào)用fun前,將a,b,c作為參數(shù)壓棧,我們只看到連續(xù)push三個(gè)0,因?yàn)榫幾g階段,a,b,c的地址都不確定,暫時(shí)用0代替。
2,到了鏈接階段,linker會(huì)搜集所有.o文件中的符號(hào),并放到一張全局符號(hào)表里。像a,b,c,它們就有名字“a","b","c",并算出了對(duì)應(yīng)的地址,就這樣存到全局符號(hào)表里。
3,之前說到的,那三條push?0的指令,它們對(duì)應(yīng)的機(jī)器碼,是存儲(chǔ)在test2.o的.text段的,這時(shí)候當(dāng)然要把那三個(gè)零換成a,b,c的地址。
4,linker是根據(jù)test.o的.rel.text段來完成這個(gè)重定位的。.rel.text段是一個(gè)表,每個(gè)entry(表項(xiàng))8個(gè)字節(jié),數(shù)據(jù)結(jié)構(gòu)是這樣:
struct{
unsigned??????r_offset;
usnigned??????r_info;
}
linker根據(jù)r_offset知道,要修正的位置相對(duì)于.text段的偏移。就這樣定位到那三個(gè)0的位置。
根據(jù)r_info知道要修正的是哪個(gè)符號(hào)。再說細(xì)點(diǎn):linker根據(jù)r_info的高24位在全局符號(hào)表里索引到這個(gè)符號(hào),這樣,符號(hào)的地址就
順藤摸瓜的出來了。把它寫入r_offset處。
這樣重定位就完成了。
----------------以上是就32位elf來說的,某些敘述有簡(jiǎn)化。你可以去看《程序員的自我修養(yǎng)》
總結(jié)
以上是生活随笔為你收集整理的linux内核全局变量重定位,关于可重定位文件中全局变量的一个重定位疑惑,借各位牛刀一用^...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分红股和原始股的区别
- 下一篇: 新乳业是什么时候上市?