0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

BL(B)和LDR跳轉(zhuǎn)范圍是如何規(guī)定的

FPGA之家 ? 來(lái)源:FPGA之家 ? 作者:FPGA之家 ? 2022-07-03 10:29 ? 次閱讀

1. BL LDR指令簡(jiǎn)介

2. 分析絕對(duì)跳轉(zhuǎn)過(guò)程

3. BL(B)和LDR跳轉(zhuǎn)范圍是如何規(guī)定的

4. BL執(zhí)行過(guò)程分析

5. LDR執(zhí)行過(guò)程分析

6. 總結(jié)

1. BL LDR指令簡(jiǎn)介

??LDR和BL在啟動(dòng)程序中,都是可以負(fù)責(zé)pc跳轉(zhuǎn)的指令。

??BL是地址無(wú)關(guān)指令,即和當(dāng)前的運(yùn)行地址無(wú)關(guān)。鏈接器腳本中標(biāo)明了一個(gè)運(yùn)行地址,但是arm中的代碼實(shí)際是從地址0開(kāi)始運(yùn)行的。這個(gè)時(shí)候,實(shí)際的地址和運(yùn)行地址是不符的

??如果想讓程序正常的運(yùn)行,就得使用地址無(wú)關(guān)指令。比如在完成將程序復(fù)制到內(nèi)存之前想要跳轉(zhuǎn)到一個(gè)函數(shù)里,就得使用BL。因?yàn)锽L跳轉(zhuǎn)依靠的是相對(duì)地址,和運(yùn)行地址無(wú)關(guān),所以能完成跳轉(zhuǎn)。

??LDR是地址有關(guān)指令。如果這個(gè)時(shí)候使用“l(fā)dr pc,=函數(shù)名”來(lái)跳轉(zhuǎn),實(shí)際上是跳轉(zhuǎn)到這個(gè)函數(shù)在鏈接器腳本中標(biāo)明的地址上了。所以使用地址相關(guān)指令之前,要把代碼復(fù)制到鏈接器腳本中指明的那個(gè)地址上,否則的話程序就跑飛了。復(fù)制完成之后再使用LDR跳轉(zhuǎn)到內(nèi)存中,使程序繼續(xù)運(yùn)行。

2. 分析絕對(duì)跳轉(zhuǎn)過(guò)程

??我們以一個(gè)例子具體分析下絕對(duì)跳轉(zhuǎn)過(guò)程。

指令編號(hào) 指令功能
指令1 順序執(zhí)行
指令2 順序執(zhí)行
指令3 相對(duì)跳轉(zhuǎn)到指令5
指令4 順序執(zhí)行
指令5 順序執(zhí)行
指令6 絕對(duì)跳轉(zhuǎn)到指令8
指令7 順序執(zhí)行
指令8 順序執(zhí)行

??假設(shè)程序被放在0x00000000位置開(kāi)始執(zhí)行,編譯鏈接后的結(jié)果為:

指令地址 指令編號(hào) 指令功能 下條指令地址
0x00000000 順序執(zhí)行 順序執(zhí)行 當(dāng)前地址+4
0x00000004 順序執(zhí)行 順序執(zhí)行 當(dāng)前地址+4
0x00000008 跳轉(zhuǎn)到指令5 跳轉(zhuǎn)到指令5 當(dāng)前地址+8
0x0000000C 順序執(zhí)行 順序執(zhí)行 當(dāng)前地址+4
0x00000010 順序執(zhí)行 順序執(zhí)行 當(dāng)前地址+4
0x00000014 跳轉(zhuǎn)到指令8 跳轉(zhuǎn)到指令8 0xC000001C
0x00000018 順序執(zhí)行 順序執(zhí)行 當(dāng)前地址+4
0x0000001C 順序執(zhí)行 順序執(zhí)行 當(dāng)前地址+4

9af2867a-f99d-11ec-ba43-dac502259ad0.png絕對(duì)跳轉(zhuǎn)分析

??當(dāng)這段程序被放在0xC000000空間(如右圖)時(shí),開(kāi)始執(zhí)行指令1,然后采用相對(duì)尋址的方法就可以運(yùn)行到指令6,在指令6執(zhí)行時(shí)也可以使用絕對(duì)尋址的方法從0xC0000014正確跳轉(zhuǎn)到指令8所在的0xC00001C位置,這段代碼運(yùn)行正常。

??當(dāng)這段代碼被放在0x00000000空間(如左圖)時(shí),開(kāi)始執(zhí)行指令1,然后采用相對(duì)尋址的方法就可以運(yùn)行到指令6,但在指令6執(zhí)行時(shí)使用絕對(duì)尋址的方法從0x0000014跳轉(zhuǎn)到了0xC000001C,但0xC000001C空間沒(méi)有代碼,這樣程序就跑飛了。

??因此,當(dāng)編譯地址(加載地址)和運(yùn)行地址相同時(shí),絕對(duì)跳轉(zhuǎn)和相對(duì)跳轉(zhuǎn)都可以正確執(zhí)行。比如,程序在NORFLASH存儲(chǔ)時(shí)。

??但是,當(dāng)編譯地址(加載地址)和運(yùn)行地址不相同時(shí),相對(duì)跳轉(zhuǎn)就會(huì)出現(xiàn)問(wèn)題。比如,代碼存儲(chǔ)在NANDFLASH,由于NANDFLASH并不能運(yùn)行代碼,所以需要重定位代碼到內(nèi)部的SRAM。

3. BL(B)和LDR跳轉(zhuǎn)范圍是如何規(guī)定的

??下圖為B(BL)指令的格式

9b145336-f99d-11ec-ba43-dac502259ad0.pngBL指令編碼格式

??BL指令的[23,0]位存放的是要跳轉(zhuǎn)的相對(duì)地址,由于指令所在地址必須是4字節(jié)對(duì)齊的,因此跳轉(zhuǎn)的地址最低位必然是0

??BL指令[23,0]位保存的是省略這最低2位的地址,如果補(bǔ)全了這2位,BL指令就可以表示26位的跳轉(zhuǎn)地址。在這26位中需要使用1位表示向前跳還是向后跳,那么剩下的25位就可以表示32 MBts的范圍了,225=32M因此,B(BL)指令的跳轉(zhuǎn)范圍為-32MBytes~+32MBytes。

??下圖為L(zhǎng)DR指令的格式。

9b45f3be-f99d-11ec-ba43-dac502259ad0.pngLDR指令編碼格式 9b7853fe-f99d-11ec-ba43-dac502259ad0.pngLDR指令編碼格式

??圖中的LDR的跳轉(zhuǎn)范圍計(jì)算方式和B指令的類(lèi)似,其中Rn和Address_mode共同構(gòu)成第二個(gè)操作數(shù)的內(nèi)存地址。由Address_mode的9種格式可以知道,Address_mode表示的就是偏移地址的范圍大小,為212=4K。(不理解的可以對(duì)比下ldrpc, [pc, #804]和Address_mode的九種格式,很明顯可以看出Address_mode就是當(dāng)前地址的偏移范圍)

4. BL執(zhí)行過(guò)程分析

??下圖為B(BL)指令的格式。

9b145336-f99d-11ec-ba43-dac502259ad0.pngBL指令編碼格式

??28~31位(cond)是條件碼,就是表明這條語(yǔ)句里是否有大于、等于、非零等的條件判斷,這4位共有16種狀態(tài),分別為:

9bca6ff4-f99d-11ec-ba43-dac502259ad0.png條件碼

??我們以Uboot啟動(dòng)過(guò)程中的這句跳轉(zhuǎn)代碼分析下BL指令具體的執(zhí)行過(guò)程。

#ifndefCONFIG_SKIP_LOWLEVEL_INIT
blcpu_init_crit
#endif

??上述代碼對(duì)應(yīng)的反匯編代碼如下:

33f000ac:eb000017bl33f00110
33f00110:
33f00110:e3a00000movr0,#0;0x0
33f00114:ee070f17mcr15,0,r0,cr7,cr7,{0}

??當(dāng)指令執(zhí)行到33f000ac時(shí),對(duì)應(yīng)的機(jī)器碼為eb000017(1110_1011_0000_0000_0000_0000_0001_0111?),其中[31,28]高四位為條件碼,1110表示無(wú)條件執(zhí)行。[25,27]位保留區(qū)域,24位表示是否帶有返回值,1表示帶有返回值,也就是BL指令。[23,0]為指令的操作數(shù),0000_0000_0000_0000_0001_0111。

??BL指令的跳轉(zhuǎn)地址是按照如下方式計(jì)算:

??1、將指令中24位帶符號(hào)的補(bǔ)碼立即數(shù)擴(kuò)展為32位(擴(kuò)展其符號(hào)位)原數(shù)變成 0000_0000_0000_0000_0000_0000_0001_0111。

??2、將此數(shù)左移兩位0000_0000_0000_0000_0000_0010_1000_0000 變成 0000_0000_0000_0000_0000_0000_0101_1100 = 0x0000005c

?? 3、將得到的值加到PC寄存器中得到目標(biāo)地址,由于ARM為3級(jí)流水線,此時(shí)的 pc = 33f000ac+8 = 33F000B4,pc = 33F000B4 + 0x0000005c = 33F00110?與圖中的cpu_init_crit的地址相等。

?? 在算的過(guò)程中我們使用的始終是PC的值,假設(shè)程序在 0 地址處執(zhí)行,那么計(jì)算方法一樣,pc 的值變了,計(jì)算出來(lái)的結(jié)果也隨之改變。所以 BL 的跳轉(zhuǎn)時(shí)是與位置無(wú)關(guān)的。

5. LDR執(zhí)行過(guò)程分析

??下圖為L(zhǎng)DR指令的格式。9bee8e34-f99d-11ec-ba43-dac502259ad0.png

9c0662fc-f99d-11ec-ba43-dac502259ad0.pngLDR指令編碼格式

??我們以下圖中的代碼作為例子分析下。

ldrpc,=call_board_init_f

??對(duì)應(yīng)的反匯編代碼如下:

33f000d0:e59ff324ldrpc,[pc,#804];33f003fc
33f003fc:33f000d4.word0x33f000d4
........
33f000d4:
33f000d4:e3a00000movr0,#0;0x0

?? ldrpc, [pc, #804]這條指令為偽指令,編譯的時(shí)候會(huì)將call_board_init_f的鏈接地址存入一個(gè)固定的地址(鏈接時(shí)確定的),對(duì)于本條指令,這個(gè)地址就是33f000d4 。

??上面的反匯編出來(lái)的 ldr pc,=call_board_init_f就變成了ldrpc, [pc, #804],由于ARM使用了流水線的原因,所以在執(zhí)行 ldr pc,[ pc, #4 ]的時(shí)候 pc 不在這句代碼這里了,而是跑到了 pc+8的地方,這句代碼相當(dāng)于 pc= *(pc+804+8)=33f000d0+32C=33f003fc ,所以會(huì)跳轉(zhuǎn)到33f003fc 地址取33f000d4 ,而 33f000d4 是存在代碼段中的一個(gè)常量,并不是計(jì)算出來(lái)的,不會(huì)隨程序的位置而改變,所以無(wú)論代碼和pc怎么變 *(pc+804) 的值時(shí)不會(huì)變的。

6. 總結(jié)

??這樣,絕對(duì)跳轉(zhuǎn)中的固定地址就很好理解了,要跳轉(zhuǎn)地址的值在鏈接時(shí)就已經(jīng)確定了,存在了一塊內(nèi)存中。

相對(duì)跳轉(zhuǎn)時(shí),反匯編bl33f00110中的33f00110是根據(jù)pc計(jì)算出來(lái)的,當(dāng)pc改變時(shí),結(jié)果也會(huì)改變。所以,稱(chēng)為相對(duì)跳轉(zhuǎn),與當(dāng)前位置無(wú)關(guān)。

原文標(biāo)題:分析下BL(B)/LDR指令

文章出處:【微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5294

    瀏覽量

    119814
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4277

    瀏覽量

    62323
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68229

原文標(biāo)題:分析下BL(B)/LDR指令

文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【NanoPi M2試用體驗(yàn)】+SD卡啟動(dòng)BL1拷貝BL2到DDR2中運(yùn)行

    */bl ddr_init/* DDR初始化 */bl main/* 跳轉(zhuǎn)到C函數(shù)去執(zhí)行 */ldr sp, =0x34000000/* 重新設(shè)在棧為DDR內(nèi)存的最高地址 */
    發(fā)表于 06-11 17:03

    ARM匯編指令(B/BL/BX)--轉(zhuǎn)載

    向后的 32MB 的地址空間的跳轉(zhuǎn),包括以下 4 條指令:(1) B 跳轉(zhuǎn)指令(2) BL 帶返回的跳轉(zhuǎn)指令(3) BLX 帶返回和狀態(tài)切換
    發(fā)表于 01-26 16:26

    ARM2440的啟動(dòng)模式

    程序。代碼Head.s.extern main.text.global _start_start: b resetreset: ldr sp,=4096 bl disable_watch_dog
    發(fā)表于 07-05 05:29

    使用bl指令設(shè)置系統(tǒng)時(shí)鐘不能正常運(yùn)行

    *1024 //設(shè)置時(shí)鐘 //bl Init_system_clock //執(zhí)行main bl mainhalt: b haltCLOSE_WATCHDOG_S: //關(guān)閉看門(mén)狗 ldr
    發(fā)表于 03-05 03:09

    請(qǐng)問(wèn)ldr pc, und_addr跳轉(zhuǎn)是絕對(duì)地址還是相對(duì)地址?

    位置\014_und_exception_014_004\002start.S輸出的錯(cuò)誤信息:ldr pc, und_addr這一句為什么不是ldr pc, =und_addr ,ldr pc, und_addr
    發(fā)表于 04-16 07:45

    單板匯編代碼報(bào)錯(cuò)

    to fit: R_ARM_PC24 main原因是b跳轉(zhuǎn)范圍不夠,但是在前一句 ldr pc, =on_sdram ,這個(gè)時(shí)候pc已經(jīng)跳轉(zhuǎn)
    發(fā)表于 04-24 05:48

    arm匯編跳轉(zhuǎn)指令總結(jié)

    目前所知道的跳轉(zhuǎn)指令有 b,bl,bep,bne.他們共同點(diǎn)是都是以b開(kāi)頭,首先從字面上分析:b:是Branch,表示分支。
    發(fā)表于 04-26 02:39

    ARM處理器中斷響應(yīng)為什么非要跳轉(zhuǎn)兩次?

    最近看uboot源碼中S3C2440的start.S,源碼的開(kāi)始部分就是如下的代碼:.globl _start_start: b reset ldr pc
    發(fā)表于 08-15 03:47

    請(qǐng)問(wèn)一下ARM跳轉(zhuǎn)指令的范圍是多少

    (帶連接的跳轉(zhuǎn)指令)能夠在跳轉(zhuǎn)時(shí)對(duì)當(dāng)前 PC 值自動(dòng)進(jìn)行保存。Thumb的B系列指令跳轉(zhuǎn)范圍只有256字節(jié),然而大多數(shù)情況下
    發(fā)表于 04-14 09:30

    請(qǐng)問(wèn)一下ARM匯編中的B跳轉(zhuǎn)指令和LDR跳轉(zhuǎn)的區(qū)別在哪

    請(qǐng)問(wèn)一下ARM匯編中的B跳轉(zhuǎn)指令和LDR跳轉(zhuǎn)的區(qū)別有哪些不同之處呢?
    發(fā)表于 07-21 15:57

    SPC58NG84E7引導(dǎo)加載程序,BL不會(huì)跳轉(zhuǎn)到APP并繼續(xù)運(yùn)行BL代碼是什么問(wèn)題?

    我正在研究 SPC58NG84E7 引導(dǎo)加載程序。我有 BL 代碼(在 0xFC0000),它在啟動(dòng)后等待 10 秒后跳轉(zhuǎn)到 APP 位置 0xFD0000 并在那里執(zhí)行代碼。兩個(gè)代碼都有優(yōu)化
    發(fā)表于 12-15 07:40

    跳轉(zhuǎn)指令B及帶連接的跳轉(zhuǎn)指令BLX上 

    跳轉(zhuǎn)B)和跳轉(zhuǎn)連接(BL)指令是改變指令執(zhí)行順序的標(biāo)準(zhǔn)方式。ARM一般按照字地址順序執(zhí)行指令,需要時(shí)使用條件執(zhí)行跳過(guò)某段指令。只要程序必須偏離順序執(zhí)行,就要使用控制流指令來(lái)修改程序計(jì)
    發(fā)表于 10-19 10:26 ?2次下載
    <b class='flag-5'>跳轉(zhuǎn)</b>指令<b class='flag-5'>B</b>及帶連接的<b class='flag-5'>跳轉(zhuǎn)</b>指令BLX上 

    ARM嵌入式系統(tǒng)的中斷服務(wù)例程跳轉(zhuǎn)

    在32位 ARM 系統(tǒng)中,一般都是在中斷向量表中放置一條分支指令或PC寄存器加載指令,實(shí)現(xiàn) 程序跳轉(zhuǎn) 到 中斷服務(wù) 例程的功能。例如: IRQEntry B HandleIRQ ;跳轉(zhuǎn)范圍
    發(fā)表于 04-10 10:11 ?2810次閱讀

    全面分析下BL(B)/LDR指令

    1. BL LDR指令簡(jiǎn)介 LDRBL在啟動(dòng)程序中,都是可以負(fù)責(zé)pc跳轉(zhuǎn)的指令。 BL是地址無(wú)
    的頭像 發(fā)表于 06-01 11:15 ?7236次閱讀
    全面分析下<b class='flag-5'>BL</b>(<b class='flag-5'>B</b>)/<b class='flag-5'>LDR</b>指令

    ATF中bl2到bl31的跳轉(zhuǎn)介紹

    bl2到bl31的跳轉(zhuǎn)bl2_main函數(shù)中最終會(huì)調(diào)用smc(BL1_SMC_RUN_IMAGE,(unsigned long)next
    的頭像 發(fā)表于 11-07 16:09 ?846次閱讀