<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > uboot的relocation原理詳細(xì)分析

          uboot的relocation原理詳細(xì)分析

          作者: 時(shí)間:2016-11-21 來(lái)源:網(wǎng)絡(luò) 收藏
          所謂的relocation,就是重定位,uboot運(yùn)行后會(huì)將自身代碼拷貝到sdram的另一個(gè)位置繼續(xù)運(yùn)行,這個(gè)在uboot啟動(dòng)流程分析中說(shuō)過(guò)。

          但基于以前的理解,一個(gè)完整可運(yùn)行的bin文件,link時(shí)指定的鏈接地址,load時(shí)的加載地址,運(yùn)行時(shí)的運(yùn)行地址,這3個(gè)地址應(yīng)該是一致的

          本文引用地址:http://www.ex-cimer.com/article/201611/319403.htm

          relocation后運(yùn)行地址不同于加載地址特別是鏈接地址,ARM的尋址會(huì)不會(huì)出現(xiàn)問(wèn)題?

          新版uboot跟老版uboot不太一樣的地方在于新版uboot不管uboot的load addr(entry pointer)在哪里,啟動(dòng)后會(huì)計(jì)算出一個(gè)靠近sdram頂端的地址,將自身代碼拷貝到該地址,繼續(xù)運(yùn)行。

          個(gè)人感覺uboot這樣改進(jìn)用意有二,一是為kernel騰出低端空間,防止kernel解壓覆蓋uboot,二是對(duì)于由靜態(tài)存儲(chǔ)器(spiflash nandflash)啟動(dòng),這個(gè)relocation是必須的。

          但是這樣會(huì)有一個(gè)問(wèn)題,relocation后uboot的運(yùn)行地址跟其鏈接地址不一致,compiler會(huì)在link時(shí)確定了其中變量以及函數(shù)的絕對(duì)地址,鏈接地址加載地址 運(yùn)行地址應(yīng)該一致,

          這樣看來(lái),arm在尋址這些變量函數(shù)時(shí)找到的應(yīng)該是relocation之前的地址,這樣relocation就沒有意義了!

          當(dāng)然uboot不會(huì)這樣,我們來(lái)分析一下uboot下relocation之后是如何尋址的,開始學(xué)習(xí)之前我是有3個(gè)疑問(wèn),如下

          (1)如何對(duì)函數(shù)進(jìn)行尋址調(diào)用

          (2)如何對(duì)全局變量進(jìn)行尋址操作(讀寫)

          (3)對(duì)于全局指針變量中存儲(chǔ)的其他變量或函數(shù)地址在relocation之后如何操作

          搞清楚這3個(gè)問(wèn)題,對(duì)于我來(lái)說(shuō)relocation的原理就算是搞明白了。

          為了搞清楚這些,在uboot的某一個(gè)文件中加入如下代碼

          [cpp] view plaincopyprint?
          1. voidtest_func(void)
          2. {
          3. printf("testfuncn");
          4. }
          5. staticvoid*test_func_val=test_func;
          6. staticinttest_val=10;
          7. voidrel_dyn_test()
          8. {
          9. test_val=20;
          10. printf("test=0x%xn",test_func);
          11. printf("test_func=0x%xn",test_func_val);
          12. test_func();
          13. }
          void test_func(void) { printf("test funcn"); } static void * test_func_val = test_func; static int test_val = 10; void rel_dyn_test() { test_val = 20; printf("test = 0x%xn", test_func); printf("test_func = 0x%xn", test_func_val); test_func(); }
          rel_dyn_test函數(shù)中就包含了函數(shù)指針 變量賦值函數(shù)調(diào)用這3種情況,尋址肯定要匯編級(jí)的追蹤才可以,編譯完成后反匯編,得到u-boot.dump(objdump用-D選項(xiàng),將所有section都disassemble出來(lái))

          找到rel_dyn_test函數(shù),如下:

          [cpp] view plaincopyprint?
          1. 80e9d3cc:
          2. 80e9d3cc:e59f0000ldrr0,[pc,#0];80e9d3d4
          3. 80e9d3d0:eaffc2fbb80e8dfc4
          4. 80e9d3d4:80eb1c39.word0x80eb1c39
          5. 80e9d3d8:
          6. 80e9d3d8:e59f202cldrr2,[pc,#44];80e9d40c
          7. 80e9d3dc:e3a03014movr3,#20;0x14
          8. 80e9d3e0:e92d4010push{r4,lr}
          9. 80e9d3e4:e59f1024ldrr1,[pc,#36];80e9d410
          10. 80e9d3e8:e5823000strr3,[r2]
          11. 80e9d3ec:e59f0020ldrr0,[pc,#32];80e9d414
          12. 80e9d3f0:ebffc2f3bl80e8dfc4
          13. 80e9d3f4:e59f301cldrr3,[pc,#28];80e9d418
          14. 80e9d3f8:e59f001cldrr0,[pc,#28];80e9d41c
          15. 80e9d3fc:e5931000ldrr1,[r3]
          16. 80e9d400:ebffc2efbl80e8dfc4
          17. 80e9d404:e8bd4010pop{r4,lr}
          18. 80e9d408:eaffffefb80e9d3cc
          19. 80e9d40c:80eb75c0.word0x80eb75c0
          20. 80e9d410:80e9d3cc.word0x80e9d3cc
          21. 80e9d414:80eb1c44.word0x80eb1c44
          22. 80e9d418:80eaa54c.word0x80eaa54c
          23. 80e9d41c:80eb1c51.word0x80eb1c51
          80e9d3cc : 80e9d3cc: e59f0000 ldr r0, [pc, #0] ; 80e9d3d4 80e9d3d0: eaffc2fb b 80e8dfc4 80e9d3d4: 80eb1c39 .word 0x80eb1c39 80e9d3d8 : 80e9d3d8: e59f202c ldr r2, [pc, #44] ; 80e9d40c 80e9d3dc: e3a03014 mov r3, #20 ; 0x14 80e9d3e0: e92d4010 push {r4, lr} 80e9d3e4: e59f1024 ldr r1, [pc, #36] ; 80e9d410 80e9d3e8: e5823000 str r3, [r2] 80e9d3ec: e59f0020 ldr r0, [pc, #32] ; 80e9d414 80e9d3f0: ebffc2f3 bl 80e8dfc4 80e9d3f4: e59f301c ldr r3, [pc, #28] ; 80e9d418 80e9d3f8: e59f001c ldr r0, [pc, #28] ; 80e9d41c 80e9d3fc: e5931000 ldr r1, [r3] 80e9d400: ebffc2ef bl 80e8dfc4 80e9d404: e8bd4010 pop {r4, lr} 80e9d408: eaffffef b 80e9d3cc 80e9d40c: 80eb75c0 .word 0x80eb75c0 80e9d410: 80e9d3cc .word 0x80e9d3cc 80e9d414: 80eb1c44 .word 0x80eb1c44 80e9d418: 80eaa54c .word 0x80eaa54c 80e9d41c: 80eb1c51 .word 0x80eb1c51
          。。。

          data段中

          [cpp] view plaincopyprint?
          1. 80eb75c0:
          2. 80eb75c0:0000000a.word0x0000000a
          80eb75c0 : 80eb75c0: 0000000a .word 0x0000000a
          。。。
          [cpp] view plaincopyprint?
          1. 80eaa54c:
          2. 80eaa54c:80e9d3cc.word0x80e9d3cc
          80eaa54c : 80eaa54c: 80e9d3cc .word 0x80e9d3cc

          rel_dyn_test反匯編后,最后多了一部分從0x80e9d40c開始的內(nèi)存空間,對(duì)比發(fā)現(xiàn)這部分內(nèi)存空間地址上的值竟然是函數(shù)需要的變量test_val test_func_val的地址。

          網(wǎng)上資料稱這些函數(shù)末尾存儲(chǔ)變量地址的內(nèi)存空間為L(zhǎng)abel,(編譯器自動(dòng)分配)

          一條條指令來(lái)分析。

          ldr r2, [pc, #44] ========> r2 = [pc + 0x2c]=======>r2 = [0x80e9d3e0 + 0x2c]=======>r2 =[0x80e9d40c]

          需要注意,由于ARM的流水線機(jī)制,當(dāng)前PC值為當(dāng)前地址加8個(gè)字節(jié)

          這樣r2獲取的是0x80e9d40c地址的值0x80eb75c0,這就是test_val的值嘛

          mov r3, #20======> r3 = 20

          對(duì)應(yīng)C函數(shù)這應(yīng)該是為test_val = 20做準(zhǔn)備,先跳過(guò)后面2條指令,發(fā)現(xiàn)

          str r3, [r2]

          很明顯了,將立即數(shù)20存入0x80eb75c0中也就是test_val中。

          這3條指令說(shuō)明,ARM對(duì)于變量test_val的尋址如下:

          (1)將變量test_val的地址存儲(chǔ)在函數(shù)尾端的Label中(這段內(nèi)存空間是由編譯器自動(dòng)分配的,而非人為)

          (2)基于PC相對(duì)尋址獲取函數(shù)尾端Label上的變量地址

          (3)對(duì)test_val變量地址進(jìn)行讀寫操作

          再來(lái)看其中的幾條指令

          ldr r3, [pc, #28] =====> r3 = [0x80e9d3fc + 0x1c] =====> r3 = [0x80e9d418] ====> r3 = 0x80eaa54c

          ldr r1, [r3] =====> r1 = [0x80eaa54c] ======> r1 = 0x80e9d3cc

          0x80e9d3cc這個(gè)地址可以看出是test_func的入口地址,這里是printf打印test_func_val的值
          可以看出對(duì)于函數(shù)指針變量的尋址跟普通變量一樣。

          接下來(lái)來(lái)看函數(shù)的調(diào)用,可以看到對(duì)于printf以及test_func,使用的是指令bl以及b進(jìn)行跳轉(zhuǎn),這2條指令都是相對(duì)尋址(pc + offset)

          說(shuō)明ARM調(diào)用函數(shù)使用的是相對(duì)尋址指令bl或b,與函數(shù)的絕對(duì)地址無(wú)關(guān)

          對(duì)于這3種情況的尋址方法已經(jīng)知道了,那就需要思考一下relocation之后會(huì)有什么變化。

          將rel_dyn_test relocation之后可以想象,函數(shù)的調(diào)用還是沒有問(wèn)題的,因?yàn)槭褂昧薭l或b相對(duì)跳轉(zhuǎn)指令。

          但是對(duì)于變量的尋址就有問(wèn)題了,尋址的前2步?jīng)]有問(wèn)題,相對(duì)尋址獲取尾部Label中的變量地址,但獲取的變量地址是在 link時(shí)就確定下來(lái)的絕對(duì)地址啊!

          而對(duì)于指針變量的尋址呢,問(wèn)題更多了,

          首先跟普通變量尋址一樣,尾部?jī)?nèi)存空間的變量地址是link時(shí)的絕對(duì)地址,再者,指針變量存儲(chǔ)的變量指針或者函數(shù)指針也是在link時(shí)確定的絕對(duì)地址,relocation之后這個(gè)值也變了!

          那uboot是如何來(lái)處理這些情況的呢?更準(zhǔn)確的說(shuō)應(yīng)該是compiler和uboot如何一起來(lái)處理這些情況的呢?

          這里利用了PIC位置無(wú)關(guān)代碼,通過(guò)為編譯器指定編譯選項(xiàng)-fpic或-fpie產(chǎn)生,
          這樣編譯產(chǎn)生的目標(biāo)文件包含了PIC所需要的信息,-fpic,-fpie是gcc的PIC編譯選項(xiàng)。ld也有PIC連接選項(xiàng)-pie,要獲得一個(gè)完整的PIC可運(yùn)行文件,連接目標(biāo)文件時(shí)必須為ld指定-pie選項(xiàng),

          察看uboot的編譯選項(xiàng)發(fā)現(xiàn),在arch/arm/config.mk,如下:

          [cpp] view plaincopyprint?
          1. #neededforrelocation
          2. LDFLAGS_u-boot+=-pie
          # needed for relocation LDFLAGS_u-boot += -pie
          uboot只指定了-pie給ld,而沒有指定-fPIC或-fPIE給gcc。

          指定-pie后編譯生成的uboot中就會(huì)有一個(gè)rel.dyn段,uboot就是靠rel.dyn段實(shí)現(xiàn)了完美的relocation!

          察看u-boot.dump中的rel.dyn段,如下:

          [cpp] view plaincopyprint?
          1. Disassemblyofsection.rel.dyn:
          2. 80eb7d54<__rel_dyn_end-0x5c10>:
          3. 80eb7d54:80e80020rschir0,r8,r0,lsr#32
          4. 80eb7d58:00000017andeqr0,r0,r7,lslr0
          5. 80eb7d5c:80e80024rschir0,r8,r4,lsr#32
          6. 80eb7d60:00000017andeqr0,r0,r7,lslr0
          7. 80eb7d64:80e80028rschir0,r8,r8,lsr#32
          8. 80eb7d68:00000017andeqr0,r0,r7,lslr0
          9. 。。。
          10. "color:#FF0000;">80eba944:80e9d40crschisp,r9,ip,lsl#8
          11. 80eba948:00000017andeqr0,r0,r7,lslr0
          12. 80eba94c:80e9d410rschisp,r9,r0,lslr4
          13. 80eba950:00000017andeqr0,r0,r7,lslr0
          14. 80eba954:80e9d414rschisp,r9,r4,lslr4
          15. 80eba958:00000017andeqr0,r0,r7,lslr0
          16. 80eba95c:80e9d418rschisp,r9,r8,lslr4
          17. 80eba960:00000017andeqr0,r0,r7,lslr0
          18. 80eba964:80e9d41crschisp,r9,ip,lslr4
          19. 80eba968:00000017andeqr0,r0,r7,lslr0
          20. 。。。。
          Disassembly of section .rel.dyn: 80eb7d54 <__rel_dyn_end-0x5c10>: 80eb7d54: 80e80020 rschi r0, r8, r0, lsr #32 80eb7d58: 00000017 andeq r0, r0, r7, lsl r0 80eb7d5c: 80e80024 rschi r0, r8, r4, lsr #32 80eb7d60: 00000017 andeq r0, r0, r7, lsl r0 80eb7d64: 80e80028 rschi r0, r8, r8, lsr #32 80eb7d68: 00000017 andeq r0, r0, r7, lsl r0 。。。 80eba944: 80e9d40c rschi sp, r9, ip, lsl #8 80eba948: 00000017 andeq r0, r0, r7, lsl r0 80eba94c: 80e9d410 rschi sp, r9, r0, lsl r4 80eba950: 00000017 andeq r0, r0, r7, lsl r0 80eba954: 80e9d414 rschi sp, r9, r4, lsl r4 80eba958: 00000017 andeq r0, r0, r7, lsl r0 80eba95c: 80e9d418 rschi sp, r9, r8, lsl r4 80eba960: 00000017 andeq r0, r0, r7, lsl r0 80eba964: 80e9d41c rschi sp, r9, ip, lsl r4 80eba968: 00000017 andeq r0, r0, r7, lsl r0 。。。。

          有沒有注意到,rel_dyn_test末尾存儲(chǔ)全局變量地址的Label地址也存儲(chǔ)在這里,那有什么用呢,那就來(lái)看一下uboot的核心函數(shù)relocate_code是如何實(shí)現(xiàn)自身的relocation的,

          在arch/arm/lib/relocate.S中

          [cpp] view plaincopyprint?
          1. ENTRY(relocate_code)
          2. ldrr1,=__image_copy_start
          3. subsr4,r0,r1
          4. beqrelocate_done
          5. ldrr2,=__image_copy_end
          6. copy_loop:
          7. ldmiar1!,{r10-r11}
          8. stmiar0!,{r10-r11}
          9. cmpr1,r2
          10. blocopy_loop
          11. ldrr2,=__rel_dyn_start
          12. ldrr3,=__rel_dyn_end
          13. fixloop:
          14. ldmiar2!,{r0-r1}
          15. andr1,r1,#0xff
          16. cmpr1,#23
          17. bnefixnext
          18. addr0,r0,r4
          19. ldrr1,[r0]
          20. addr1,r1,r4
          21. strr1,[r0]
          22. fixnext:
          23. cmpr2,r3
          24. blofixloop
          25. relocate_done:
          ENTRY(relocate_code) ldr r1, =__image_copy_start subs r4, r0, r1 beq relocate_done ldr r2, =__image_copy_end copy_loop: ldmia r1!, {r10-r11} stmia r0!, {r10-r11} cmp r1, r2 blo copy_loop ldr r2, =__rel_dyn_start ldr r3, =__rel_dyn_end fixloop: ldmia r2!, {r0-r1} and r1, r1, #0xff cmp r1, #23 bne fixnext add r0, r0, r4 ldr r1, [r0] add r1, r1, r4 str r1, [r0] fixnext: cmp r2, r3 blo fixloop relocate_done:
          前半部分在uboot啟動(dòng)流程中講過(guò),將__image_copy_start到__image_copy_end之間的數(shù)據(jù)進(jìn)行拷貝

          來(lái)看一下arm的link script,在arch/arm/cpu/u-boot.lds,如下:

          [cpp] view plaincopyprint?
          1. OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
          2. OUTPUT_ARCH(arm)
          3. ENTRY(_start)
          4. SECTIONS
          5. {
          6. .=0x00000000;
          7. .=ALIGN(4);
          8. .text:
          9. {
          10. *(.__image_copy_start)
          11. CPUDIR/start.o(.text*)
          12. *(.text*)
          13. }
          14. .=ALIGN(4);
          15. .rodata:{*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))}
          16. .=ALIGN(4);
          17. .data:{
          18. *(.data*)
          19. }
          20. .=ALIGN(4);
          21. .=.;
          22. .=ALIGN(4);
          23. .u_boot_list:{
          24. "code"class="cpp">KEEP(*(SORT(.u_boot_list*)));
          25. }
          26. .=ALIGN(4);
          27. .image_copy_end:
          28. {
          29. *(.__image_copy_end)
          30. }
          31. .rel_dyn_start:
          32. {
          33. *(.__rel_dyn_start)
          34. }
          35. .rel.dyn:{
          36. *(.rel*)
          37. }
          38. .rel_dyn_end:
          39. {
          40. *(.__rel_dyn_end)
          41. }
          42. .end:
          43. {
          44. *(.__end)
          45. }
          46. _image_binary_end=.;
          OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { *(.__image_copy_start) CPUDIR/start.o (.text*) *(.text*) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data*) } . = ALIGN(4); . = .; . = ALIGN(4); .u_boot_list : {
          KEEP(*(SORT(.u_boot_list*))); } . = ALIGN(4); .image_copy_end : { *(.__image_copy_end) } .rel_dyn_start : { *(.__rel_dyn_start) } .rel.dyn : { *(.rel*) } .rel_dyn_end : { *(.__rel_dyn_end) } .end : { *(.__end) } _image_binary_end = .;
          可以看出__image_copy_start---end之間包括了text data rodata段,但是沒有包括rel_dyn。 繼續(xù)看relocate_code函數(shù),拷貝__image_copy_start----end之間的數(shù)據(jù),但沒有拷貝rel.dyn段。 首先獲取__rel_dyn_start地址到r2,將start地址上連續(xù)2個(gè)4字節(jié)地址的值存在r0 r1中 判斷r1中的值低8位,如果為0x17,則將r0中的值加relocation offset。 獲取以此r0中值為地址上的值,存到r1中 將r1中值加relocation offset,再存回以r0中值為地址上。 以此循環(huán),直到__rel_dyn_end。 這樣讀有些拗口。來(lái)以咱們的rel_dyn_test舉例子。 上面rel.dyn段中有一段如下: 
          [cpp] view plaincopyprint?
          1. 80eba944:80e9d40crschisp,r9,ip,lsl#8
          2. 80eba948:00000017andeqr0,r0,r7,lslr0
          80eba944: 80e9d40c rschi sp, r9, ip, lsl #8 80eba948: 00000017 andeq r0, r0, r7, lsl r0
          按照上面的分析,判斷第二個(gè)四字節(jié)為0x17,r0中存儲(chǔ)為0x80e9d40c。這個(gè)是rel_dyn_test末尾Label的地址啊, 將r0加上relocation offset,則到了relocation之后rel_dyn_test的末尾Label。 獲取r0為地址上的值到r1中,0x80eb75c0,可以看到,這個(gè)值就是變量test_val的首地址啊。 最后將r1加上relocation offset,寫回以r0為地址上。意思是將變量test_val地址加offset后寫回到relocation之后rel_dyn_test的末尾Label中。 這樣relocate_code完成后,再來(lái)看對(duì)test_val的尋址。尋址第三步獲取到的是修改之后的relocation addr啊,這樣就可以獲取到relocation之后的test_val值! 對(duì)于普通變量尋址是這樣,那對(duì)于指針變量呢,如test_func_val呢? 獲取test_func_val relocation后地址的步驟跟上面一樣,但是我們?cè)讷@取test_func_val的值時(shí)要注意,這個(gè)變量存儲(chǔ)的是函數(shù)test_func指針,之前是0x80e9d3cc,relocation之后就變化了,所以test_func_val的值也應(yīng)該變化,這個(gè)該怎么辦? 方法是一樣的,可以在rel.dyn段中找到如下一段: 
          [cpp] view plaincopyprint?
          1. 80ebc18c:80eaa54crschisl,sl,ip,asr#10
          2. 80ebc190:00000017andeqr0,r0,r7,lslr0
          80ebc18c: 80eaa54c rschi sl, sl, ip, asr #10 80ebc190: 00000017 andeq r0, r0, r7, lsl r0
          這上面存儲(chǔ)的是test_func_val的地址,按照relocate_code的操作,完成后80eaa54c + offset上的值也應(yīng)該+offset了。 這就解決了,test_func_val的值也就是test_func的地址也被修改為relocation之后的地址了。 網(wǎng)上查閱資料,這里對(duì)于rel.dyn段中每一個(gè)rel section(8個(gè)字節(jié))第二個(gè)4字節(jié),0x17,是一種label的類型R_ARM_RELATIVE, 經(jīng)過(guò)上面uboot的relocate_code后,我們提出的3個(gè)問(wèn)題的尋址都可以正常工作。 還有一個(gè)疑問(wèn),是誰(shuí)來(lái)決定哪些label放到rel.dyn中,特別是對(duì)于存儲(chǔ)指針的變量,如何分辨,這樣看來(lái),是compiler的ld來(lái)完成的這個(gè)工作,將所有需要relocate的label放到rel.dyn段中,真是牛逼的compiler?。】偨Y(jié)一下,可以看出, 使用-pie選項(xiàng)的compiler,將需要relocate的值(全局變量地址 函數(shù)入口地址)的地址存儲(chǔ)在rel.dyn段中,uboot運(yùn)行中relocate_code遍歷rel.dyn段,根據(jù)rel.dyn中存儲(chǔ)的值,對(duì)以(這些值+offset)為地址上的值進(jìn)行了relocate,完成對(duì)所有需要relocate的變量的修改!。。。。還是有些拗口。。。 需要注意的是,在uboot的整個(gè)relocate_code中rel.dyn不僅沒有拷貝,也沒有修改,修改只是針對(duì)rel.dyn中值+offset為地址上的值! 查閱網(wǎng)上資料,compiler在cc時(shí)加入-fPIC或-fPIE選項(xiàng),會(huì)在目標(biāo)文件中生成GOT(global offset table),將本文件中需要relocate的值存放在GOT中,函數(shù)尾部的Label來(lái)存儲(chǔ)GOT的offset以及其中變量的offset,變量尋址首先根據(jù)尾部Label相對(duì)尋址找到GOT地址,以及變量地址在GOT中的位置,從而確定變量地址,這樣對(duì)于目標(biāo)文件統(tǒng)一修改GOT中的值,就修改了變量地址的offset,完成了relocation。 ld時(shí)加入-pie選項(xiàng),就會(huì)將GOT并入到rel.dyn段中,uboot在relocate_code中統(tǒng)一根據(jù)rel.dyn段修改需要relocation的數(shù)值。 uboot中l(wèi)d使用-pie而cc沒有使用-fPIC或-fPIE,目標(biāo)文件中就不會(huì)生成GOT,函數(shù)中尋址還是在尾部Label中直接存儲(chǔ)變量的絕對(duì)地址,但這個(gè)Label同樣存在rel.dyn中,uboot根據(jù)rel.dyn段修改Label上的值,就完成了relocation。 這樣不僅節(jié)省了每個(gè)目標(biāo)文件的GOT段,而且不需要去相對(duì)尋址GOT,直接修改函數(shù)尾部Label所存儲(chǔ)的變量地址就可以啦! uboot的relocation就是如此!


          關(guān)鍵詞: ubootrelocatio

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();