日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

重定位的介绍

發(fā)布時(shí)間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重定位的介绍 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

以下內(nèi)容源于朱有鵬嵌入式課程的學(xué)習(xí),如有侵權(quán),請(qǐng)告知?jiǎng)h除。

1、鏈接地址和運(yùn)行地址

(1)鏈接地址,是程序員通過(guò)Makefile中-Ttext ?xxx,或者在鏈接腳本中指定的地址。

  • 程序員預(yù)知自己的程序的執(zhí)行要求,并且有一個(gè)期望的執(zhí)行地址,并且會(huì)用這個(gè)地址來(lái)做鏈接地址。
  • 換言之,鏈接地址由程序員指定,程序員知道該程序應(yīng)該放在哪里才能順利運(yùn)行,否則此段代碼運(yùn)行不起來(lái)(假設(shè)里面有位置相關(guān)碼。?

(2)運(yùn)行地址,代碼實(shí)際運(yùn)行的地址,編譯鏈接時(shí),無(wú)法絕對(duì)確定運(yùn)行時(shí)地址。

  • 鏈接地址和運(yùn)行地址能不同。比如我們指定鏈接地址為0xd0024000,但實(shí)際DNW下載到0xd002 0010。此時(shí)運(yùn)行地址是0xd002 0010,如果代碼里面有位置相關(guān)碼,那么位置相關(guān)碼就運(yùn)行不起來(lái),因?yàn)槲恢冒l(fā)生改變了。
  • 在位置相關(guān)碼運(yùn)行前,需要把代碼拷貝到以鏈接地址為起始地址的空間里,然后通過(guò)跳轉(zhuǎn)語(yǔ)句,跳轉(zhuǎn)到以鏈接地址為起始地址的代碼的相應(yīng)的位置繼續(xù)運(yùn)行。

(3)舉例

  • linux中的應(yīng)用程序。比如gcc hello.c -o hello,使用默認(rèn)的鏈接地址就是0x0,所以應(yīng)用程序都是鏈接在0地址。因?yàn)閼?yīng)用程序運(yùn)行在操作系統(tǒng)的一個(gè)進(jìn)程中,在這個(gè)進(jìn)程中這個(gè)應(yīng)用程序獨(dú)享4G的虛擬地址空間。所以應(yīng)用程序都可以鏈接到0地址,因?yàn)槊總€(gè)進(jìn)程都是從0地址開(kāi)始的。(編譯時(shí)可以不給定鏈接地址而都使用0)。
  • 210中的裸機(jī)程序。運(yùn)行地址由我們下載時(shí)確定,下載時(shí)下載到0xd0020010,所以就從這里開(kāi)始運(yùn)行。這個(gè)下載地址不是隨意定的,是iROM中的BL0加載BL1時(shí)事先指定好的地址,這是由CPU的設(shè)計(jì)決定的。所以理論上我們編譯鏈接時(shí)應(yīng)該將地址指定到0xd0020010。


2、重定位

(1)在運(yùn)行地址處執(zhí)行一段位置無(wú)關(guān)碼,把整個(gè)程序鏡像拷貝一份到鏈接地址處,然后使用長(zhǎng)跳轉(zhuǎn)指令從運(yùn)行地址處直接跳轉(zhuǎn)到鏈接地址處去執(zhí)行同一個(gè)函數(shù)。

  • 實(shí)質(zhì)的區(qū)別是操作使用的是絕對(duì)地址,還是PC + offset的相對(duì)地址,主要集中在取址、跳轉(zhuǎn)這兩個(gè)操作上;
  • b、BL都是用的相對(duì)地址,所以是位置無(wú)關(guān)碼;
  • ldr pc,=main;因?yàn)閙ain標(biāo)志在編譯的時(shí)候,會(huì)受到鏈接腳本的鏈接位置的影響,因此main是鏈接后的絕對(duì)地址,所以是位置有關(guān)碼。
  • ldr r0, =bss_start,這句代碼的作用是把bss_start(在鏈接腳本中)的地址放入r0中,因?yàn)閎ss_start的值會(huì)受到鏈接腳本中鏈接位置的影響,所以是位置有關(guān)碼。
  • ldr r0, 0xe0002700;這個(gè)操作取0xe0002700內(nèi)存地址中的值賦值給r0,因?yàn)檫@個(gè)內(nèi)存地址不會(huì)受到鏈接腳本中鏈接位置的影響,所以是位置無(wú)關(guān)碼。
  • 下面這幾句代碼不會(huì)受到鏈接腳本中鏈接位置的影響(在宏定義中),所以也是位置無(wú)關(guān)碼:
#define WTCON         0xE2700000 #define PS_HOLD_CONTROL  0xE010E81C #define SVC_STACK      0xD0037D80 ldr r0, =WTCON ldr r0, =PS_HOLD_CONTROL
  • 見(jiàn)博客http://www.cnblogs.com/biaohc/p/6344562.html

(2)當(dāng)執(zhí)行完代碼重定位后,在SRAM中有2份代碼的鏡像。

  • 一份是下載到0xd0020010處開(kāi)頭的,另一份是重定位代碼復(fù)制到0xd0024000處開(kāi)頭的。
  • 重定位后使用ldr pc, =led_blink這句長(zhǎng)跳轉(zhuǎn),直接從0xd0020010開(kāi)頭的代碼跳轉(zhuǎn)到0xd0024000開(kāi)頭的那一份代碼的led_blink函數(shù)處去執(zhí)行。
  • 如果短跳轉(zhuǎn)bl led_blink,則執(zhí)行的是運(yùn)行地址0xd0020010開(kāi)頭的這一份;
  • 如果長(zhǎng)跳轉(zhuǎn)ldr pc, =led_blink,則執(zhí)行的是連接地址0xd0024000開(kāi)頭處的這一份;
  • 當(dāng)鏈接地址和運(yùn)行地址相同時(shí),短跳轉(zhuǎn)和長(zhǎng)跳轉(zhuǎn)效果一樣。

3、例子說(shuō)明

(1)在SRAM內(nèi)部重定位,不涉及內(nèi)存的初始化

/** 文件名: led.s * 描述: 演示重定位(在SRAM內(nèi)部重定位)*/#define WTCON 0xE2700000 #define SVC_STACK 0xd0037d80.global _start // 把_start鏈接屬性改為外部,這樣其他文件就可以看見(jiàn)_start了 _start:// 第1步:關(guān)看門(mén)狗(向WTCON的bit5寫(xiě)入0即可)ldr r0, =WTCONldr r1, =0x0str r1, [r0]// 第2步:設(shè)置SVC棧ldr sp, =SVC_STACK// 第3步:開(kāi)/關(guān)icachemrc p15,0,r0,c1,c0,0; // 讀出cp15的c1到r0中//bic r0, r0, #(1<<12) // bit12 置0 關(guān)icacheorr r0, r0, #(1<<12) // bit12 置1 開(kāi)icachemcr p15,0,r0,c1,c0,0;// 第4步:重定位// adr指令用于加載_start當(dāng)前運(yùn)行地址adr r0, _start // adr加載時(shí)就叫短加載 // ldr指令用于加載_start的鏈接地址:0xd0024000ldr r1, =_start // ldr加載時(shí)如果目標(biāo)寄存器是pc就叫長(zhǎng)跳轉(zhuǎn),如果目標(biāo)寄存器是r1等就叫長(zhǎng)加載 // bss段的起始地址ldr r2, =bss_start // 就是我們重定位代碼的結(jié)束地址,重定位只需重定位代碼段和數(shù)據(jù)段即可cmp r0, r1 // 比較_start的運(yùn)行時(shí)地址和鏈接地址是否相等beq clean_bss // 如果相等說(shuō)明不需要重定位,所以跳過(guò)copy_loop,直接到clean_bss// 如果不相等說(shuō)明需要重定位,那么直接執(zhí)行下面的copy_loop進(jìn)行重定位// 重定位完成后繼續(xù)執(zhí)行clean_bss。// 用匯編來(lái)實(shí)現(xiàn)的一個(gè)while循環(huán) copy_loop:ldr r3, [r0], #4 // 源str r3, [r1], #4 // 目的 這兩句代碼就完成了4個(gè)字節(jié)內(nèi)容的拷貝cmp r1, r2 // r1和r2都是用ldr加載的,都是鏈接地址,所以r1不斷+4總能等于r2bne copy_loop// 清bss段,其實(shí)就是在鏈接地址處把bss段全部清零 clean_bss:ldr r0, =bss_start ldr r1, =bss_endcmp r0, r1 // 如果r0等于r1,說(shuō)明bss段為空,直接下去beq run_on_dram // 清除bss完之后的地址mov r2, #0 clear_loop:str r2, [r0], #4 // 先將r2中的值放入r0所指向的內(nèi)存地址(r0中的值作為內(nèi)存地址),cmp r0, r1 // 然后r0 = r0 + 4bne clear_looprun_on_dram: // 長(zhǎng)跳轉(zhuǎn)到led_blink開(kāi)始第二階段ldr pc, =led_blink // ldr指令實(shí)現(xiàn)長(zhǎng)跳轉(zhuǎn)// 從這里之后就可以開(kāi)始調(diào)用C程序了//bl led_blink // bl指令實(shí)現(xiàn)短跳轉(zhuǎn)// 匯編最后的這個(gè)死循環(huán)不能丟b .

(2)重定位到內(nèi)存中,需要先初始化內(nèi)存

/** 文件名: led.s * 作者: 朱老師* 描述: 演示重定位*/#define WTCON 0xE2700000#define SVC_STACK 0xd0037d80.global _start // 把_start鏈接屬性改為外部,這樣其他文件就可以看見(jiàn)_start了 _start:// 第1步:關(guān)看門(mén)狗(向WTCON的bit5寫(xiě)入0即可)ldr r0, =WTCONldr r1, =0x0str r1, [r0]// 第2步:設(shè)置SVC棧ldr sp, =SVC_STACK// 第3步:開(kāi)/關(guān)icachemrc p15,0,r0,c1,c0,0; // 讀出cp15的c1到r0中//bic r0, r0, #(1<<12) // bit12 置0 關(guān)icacheorr r0, r0, #(1<<12) // bit12 置1 開(kāi)icachemcr p15,0,r0,c1,c0,0;// 第4步:初始化ddrbl sdram_asm_init// 第5步:重定位// adr指令用于加載_start當(dāng)前運(yùn)行地址adr r0, _start // adr加載時(shí)就叫短加載 // ldr指令用于加載_start的鏈接地址:0xd0024000ldr r1, =_start // ldr加載時(shí)如果目標(biāo)寄存器是pc就叫長(zhǎng)跳轉(zhuǎn),如果目標(biāo)寄存器是r1等就叫長(zhǎng)加載 // bss段的起始地址ldr r2, =bss_start // 就是我們重定位代碼的結(jié)束地址,重定位只需重定位代碼段和數(shù)據(jù)段即可cmp r0, r1 // 比較_start的運(yùn)行時(shí)地址和鏈接地址是否相等beq clean_bss // 如果相等說(shuō)明不需要重定位,所以跳過(guò)copy_loop,直接到clean_bss// 如果不相等說(shuō)明需要重定位,那么直接執(zhí)行下面的copy_loop進(jìn)行重定位// 重定位完成后繼續(xù)執(zhí)行clean_bss。// 用匯編來(lái)實(shí)現(xiàn)的一個(gè)while循環(huán) copy_loop:ldr r3, [r0], #4 // 源str r3, [r1], #4 // 目的 這兩句代碼就完成了4個(gè)字節(jié)內(nèi)容的拷貝cmp r1, r2 // r1和r2都是用ldr加載的,都是鏈接地址,所以r1不斷+4總能等于r2bne copy_loop// 清bss段,其實(shí)就是在鏈接地址處把bss段全部清零 clean_bss:ldr r0, =bss_start ldr r1, =bss_endcmp r0, r1 // 如果r0等于r1,說(shuō)明bss段為空,直接下去beq run_on_dram // 清除bss完之后的地址mov r2, #0 clear_loop:str r2, [r0], #4 // 先將r2中的值放入r0所指向的內(nèi)存地址(r0中的值作為內(nèi)存地址),cmp r0, r1 // 然后r0 = r0 + 4bne clear_looprun_on_dram: // 長(zhǎng)跳轉(zhuǎn)到led_blink開(kāi)始第二階段ldr pc, =led_blink // ldr指令實(shí)現(xiàn)長(zhǎng)跳轉(zhuǎn)// 從這里之后就可以開(kāi)始調(diào)用C程序了//bl led_blink // bl指令實(shí)現(xiàn)短跳轉(zhuǎn)// 匯編最后的這個(gè)死循環(huán)不能丟b .

總結(jié)

以上是生活随笔為你收集整理的重定位的介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。