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

          新聞中心

          ARM匯編 MOV PC,LR

          作者: 時(shí)間:2016-11-09 來源:網(wǎng)絡(luò) 收藏

          終于明白這個(gè)LR寄存器了

          看下面這個(gè)ARM匯編

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

          BL NEXT ;跳轉(zhuǎn)到子程序

          ......... ;NEXT處執(zhí)行

          NEXT

          ..........

          MOV PC,LR ;從子程序返回

          這里的BL是跳轉(zhuǎn)的意思,LR(R14)保存了返回地址

          PC(R15)是當(dāng)前地址,把LR給PC就是從子程序返回

          這里有一下總結(jié)

          首先

          1.SP(R13) LR(R14)PC(R15)

          2.lr(r14)的作用問題,這個(gè)lr一般來說有兩個(gè)作用:
          1》.當(dāng)使用bl或者blx跳轉(zhuǎn)到子過程的時(shí)候,r14保存了返回地址,可以在調(diào)用過程結(jié)尾恢復(fù)。
          2》.異常中斷發(fā)生時(shí),這個(gè)異常模式特定的物理R14被設(shè)置成該異常模式將要返回的地址。

          另外注意pc,在調(diào)試的時(shí)候顯示的是當(dāng)前指令地址,而用mov lr,pc的時(shí)候lr保存的是此指令向后數(shù)兩條指令的地址,大家可以試一下用mov pc,pc,結(jié)果得到的是跳轉(zhuǎn)兩條指令,這個(gè)原因是由于arm的流水線造成的,預(yù)取兩條指令的結(jié)果.

          3.》我以前看書不懂的地方

          子程序返回的三種方法

          現(xiàn)在總結(jié)如下

          1.MOV PC,LR

          2.BL LR

          3.在子程序入口處使用以下指令將R14存入堆棧

          STMFD SP!,{,LR}

          對(duì)應(yīng)的,使用以下指令可以完成子程序的返回

          LDMFD SP!, {,LR}

          轉(zhuǎn)載自:http://blog.csdn.net/xgx198831/article/details/8333446

          匯編學(xué)習(xí)總結(jié)記錄

          1.1. 匯編學(xué)習(xí)總結(jié)記錄
          對(duì)于我們之前分析的start.S中,涉及到很多的匯編的語句,其中,可以看出,很多包含了很多種不同的語法,使用慣例等,下面,就對(duì)此進(jìn)行一些總結(jié),借 以實(shí)現(xiàn)一定的舉一反三或者說觸類旁通,這樣,可以起到一定的借鑒功能,方便以后看其他類似匯編代碼, 容易看懂匯編代碼所要表達(dá)的含義。
          1.1.1. 匯編中的標(biāo)號(hào)=C中的標(biāo)號(hào)
          像前面匯編代碼中,有很多的,以點(diǎn)開頭,加上一個(gè)名字的形式的標(biāo)號(hào),比如:

          1. reset:
          2. /*
          3. * set the cpu to SVC32 mode
          4. */
          5. mrs r0,cpsr
          中的reset,就是匯編中的標(biāo)號(hào),相對(duì)來說,比較容易理解,就相當(dāng)于C語言的標(biāo)號(hào)。
          比如,C語言中定義一個(gè)標(biāo)號(hào)ERR_NODEV:
          1. ERR_NODEV: /* no device error */
          2. ... /* c code here */
          然后對(duì)應(yīng)在別處,使用goto去跳轉(zhuǎn)到這個(gè)標(biāo)號(hào)ERR_NODEV:
          1. if (something)
          2. goto ERR_NODEV ;

          匯編中的標(biāo)號(hào) = C語言中的標(biāo)號(hào)Label
          1.1.2. 匯編中的跳轉(zhuǎn)指令=C中的goto
          對(duì)應(yīng)地,和上面的例子中的C語言中的編號(hào)和掉轉(zhuǎn)到標(biāo)號(hào)的goto類似,匯編中,對(duì)于定義了標(biāo)號(hào),那么也會(huì)有對(duì)應(yīng)的指令,去跳轉(zhuǎn)到對(duì)應(yīng)的匯編中的標(biāo)號(hào)。
          這些跳轉(zhuǎn)的指令,就是b指令,b是branch的縮寫。
          b指令的格式是:
          b{cond} label
          簡(jiǎn)單說就是跳轉(zhuǎn)到label處。
          用和上面的例子相關(guān)的代碼來舉例:
          1. .globl _start
          2. _start: b reset
          就是用b指令跳轉(zhuǎn)到上面那個(gè)reset的標(biāo)號(hào)。

          匯編中的b跳轉(zhuǎn)指令 = C語言中的goto
          1.1.3. 匯編中的.globl=C語言中的extern
          對(duì)于上面例子中:

          .globl _start
          中的.global,就是聲明_start為全局變量/標(biāo)號(hào),可以供其他源文件所訪問。
          即匯編器,在編譯此匯編代碼的時(shí)候,會(huì)將此變量記下來,知道其是個(gè)全局變量,遇到其他文件是用到此變量的的時(shí)候,知道是訪問這個(gè)全局變量的。
          因此,從功能上來說,就相當(dāng)于C語言用extern去生命一個(gè)變量,以實(shí)現(xiàn)本文件外部訪問此變量。

          匯編中的.globl或.global = C語言中的extern
          1.1.4. 匯編中用bl指令和mov pc,lr來實(shí)現(xiàn)子函數(shù)調(diào)用和返回
          和b指令類似的,另外還有一個(gè)bl指令,語法是:
          BL{cond} label
          其作用是,除了b指令跳轉(zhuǎn)到label之外,在跳轉(zhuǎn)之前,先把下一條指令地址存到lr寄存器中,以方便跳轉(zhuǎn)到那邊執(zhí)行完畢后,將lr再賦值給pc,以實(shí)現(xiàn)函數(shù)返回,繼續(xù)執(zhí)行下面的指令的效果。
          用下面這個(gè)start.S中的例子來說明:

          1. bl cpu_init_crit
          2. 。。。
          3. cpu_init_crit:
          4. 。。。
          5. mov pc, lr
          其中,就是先調(diào)用bl掉轉(zhuǎn)到對(duì)應(yīng)的標(biāo)號(hào)cpu_init_crit,其實(shí)就是相當(dāng)于一個(gè)函數(shù)了,
          然后在cpu_init_crit部分,執(zhí)行完畢后,最后調(diào)用 mov pc, lr,將lr中的值,賦給pc,即實(shí)現(xiàn)函數(shù)的返回原先 bl cpu_init_crit下面那條代碼,繼續(xù)執(zhí)行函數(shù)。
          上面的整個(gè)過程,用C語言表示的話,就相當(dāng)于
          1. 。。。
          2. cpu_init_crit();
          3. 。。。
          4. void cpu_init_crit(void)
          5. {
          6. 。。。
          7. }

          而關(guān)于C語言中,函數(shù)的跳轉(zhuǎn)前后所要做的事情,都是C語言編譯器幫我們實(shí)現(xiàn)好了,會(huì)將此C語言中的函數(shù)調(diào)用,轉(zhuǎn)化為對(duì)應(yīng)的匯編代碼的。
          其中,此處所說的,函數(shù)掉轉(zhuǎn)前后所要做的事情,就是:
          函數(shù)跳轉(zhuǎn)前:要將當(dāng)前指令的下一條指令的地址,保存到lr寄存器中。
          函數(shù)調(diào)用完畢后:將之前保存的lr的值給pc,實(shí)現(xiàn)函數(shù)跳轉(zhuǎn)回來。繼續(xù)執(zhí)行下一條指令。
          而如果你本身自己寫匯編語言的話,那么這些函數(shù)跳轉(zhuǎn)前后要做的事情,都是你程序員自己要關(guān)心,要實(shí)現(xiàn)的事情。

          匯編中bl + mov pc,lr = C語言中的子函數(shù)調(diào)用和返回
          1.1.5. 匯編中的對(duì)應(yīng)位置有存儲(chǔ)值的標(biāo)號(hào) = C語言中的指針變量
          像前文所解析的代碼中類似于這樣的:
          1. LABEL1:.word Value2
          比如:
          1. _TEXT_BASE:
          2. .word TEXT_BASE
          所對(duì)應(yīng)的含義是,有一個(gè)標(biāo)號(hào)_TEXT_BASE
          而該標(biāo)號(hào)中對(duì)應(yīng)的位置,所存放的是一個(gè)word的值,具體的數(shù)值是TEXT_BASE,此處的TEXT_BASE是在別處定義的一個(gè)宏,值是0x33D00000。
          所以,即為:
          有一個(gè)標(biāo)號(hào)_TEXT_BASE,其對(duì)應(yīng)的位置中,所存放的是一個(gè)word的值,值為TEXT_BASE=0x33D00000。
          總的來說,此種用法的含義,如果用C語言來表示,其實(shí)更加容易理解:
          int *_TEXT_BASE = TEXT_BASE = 0x33D00000
          即:
          int *_TEXT_BASE = 0x33D00000

          不過,對(duì)于這樣的類似于C語言中的指針的匯編中的標(biāo)號(hào),在C語言中調(diào)用到的話,卻是這樣引用的:
          1. /* for the following variables, see start.S */
          2. extern ulong _armboot_start; /* code start */
          3. extern ulong _bss_start; /* code + data end == BSS start */
          4. 。。。
          5. IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
          6. 。。。
          而不是我原以為的,直接當(dāng)做指針來引用該變量的方式:

          1. *IRQ_STACK_START = *_armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;

          其中,對(duì)應(yīng)的匯編中的代碼為:

          1. .globl _armboot_start
          2. _armboot_start:
          3. .word _start
          所以,針對(duì)這點(diǎn),還是需要注意一下的。至少以后如果自己寫代碼的時(shí)候,在C語言中引用匯編中的global的標(biāo)號(hào)的時(shí)候,知道是如何引用該變量的。

          匯編中類似這樣的代碼:
          label1: .word value2
          就相當(dāng)于C語言中的:
          int *label1 = value2
          但是在C語言中引用該標(biāo)號(hào)/變量的時(shí)候,卻是直接拿來用的,就像這樣:
          label1 = other_value
          其中l(wèi)abel1就是個(gè)int型的變量。
          1.1.6. 匯編中的ldr+標(biāo)號(hào),來實(shí)現(xiàn)C中的函數(shù)調(diào)用
          接著上面的內(nèi)容,繼續(xù)解釋,對(duì)于匯編中這樣的代碼:
          第一種:
          ldr pc, 標(biāo)號(hào)1
          。。。
          標(biāo)號(hào)1:.word 標(biāo)號(hào)2
          。。。
          標(biāo)號(hào)2:
          。。。(具體要執(zhí)行的代碼)
          或者是,
          第二種:
          ldr pc, 標(biāo)號(hào)1
          。。。
          標(biāo)號(hào)1:.word XXX(C語言中某個(gè)函數(shù)的函數(shù)名)
          的意思就是,將地址為標(biāo)號(hào)1中內(nèi)容載入到pc中。
          而地址為標(biāo)號(hào)1中的內(nèi)容,就是標(biāo)號(hào)2。
          所以上面第一種的意思:
          就很容易看出來,就是把標(biāo)號(hào)2這個(gè)地址值,給pc,即實(shí)現(xiàn)了跳轉(zhuǎn)到標(biāo)號(hào)2的位置執(zhí)行代碼,就相當(dāng)于調(diào)用一個(gè)函數(shù),該函數(shù)名為標(biāo)號(hào)2.
          第二種的意思,和上面類似,是將C語言中某個(gè)函數(shù)的函數(shù)名,即某個(gè)地址值,給pc,實(shí)現(xiàn)調(diào)用C中對(duì)應(yīng)的那個(gè)函數(shù)。
          兩種做法,其含義用C語言表達(dá),其實(shí)很簡(jiǎn)單:
          PC = *(標(biāo)號(hào)1) = 標(biāo)號(hào)2
          舉個(gè)例子就是:
          第一種:
          1. 。。。
          2. ldr pc, _software_interrupt
          3. 。。。
          4. _software_interrupt: .word software_interrupt
          5. 。。。
          6. software_interrupt:
          7. get_bad_stack
          8. bad_save_user_regs
          9. bldo_software_interrupt

          就是實(shí)現(xiàn)了將標(biāo)號(hào)1,_software_interrupt,對(duì)應(yīng)的位置中的值,標(biāo)號(hào)2,software_interrupt,給pc,即實(shí)現(xiàn)了將pc掉轉(zhuǎn)到software_interrupt的位置,即實(shí)現(xiàn)了調(diào)用函數(shù)software_interrupt的效果。
          第二種:

          1. ldr pc, _start_armboot
          2. _start_armboot: .word start_armboot
          含義就是,將標(biāo)號(hào)1,_start_armboot,所對(duì)應(yīng)的位置中的值,start_armboot給pc,即實(shí)現(xiàn)了調(diào)用函數(shù)start_armboot的目的。
          其中,start_armboot是C語言文件中某個(gè)C語言的函數(shù)。

          匯編中,實(shí)現(xiàn)函數(shù)調(diào)用的效果,有如下兩種方法:
          方法1:
          ldr pc, 標(biāo)號(hào)1
          。。。
          標(biāo)號(hào)1:.word 標(biāo)號(hào)2
          。。。
          標(biāo)號(hào)2:
          。。。(具體要執(zhí)行的代碼)
          方法2:
          ldr pc, 標(biāo)號(hào)1
          。。。
          標(biāo)號(hào)1:.word XXX(C語言中某個(gè)函數(shù)的函數(shù)名)
          1.1.7. 匯編中設(shè)置某個(gè)寄存器的值或給某個(gè)地址賦值
          在匯編代碼start.S中,看到不止一處, 類似于這樣的代碼:
          形式1:

          1. # define pWTCON0x53000000
          2. 。。。
          3. ldr r0, =pWTCON
          4. mov r1, #0x0
          5. str r1, [r0]
          或者:
          形式2:

          1. # define INTSUBMSK 0x4A00001C
          2. 。。。
          3. ldr r1, =0x7fff
          4. ldr r0, =INTSUBMSK
          5. str r1, [r0]
          其含義,都是將某個(gè)值,賦給某個(gè)地址,此處的地址,是用宏定義來定義的,對(duì)應(yīng)著某個(gè)寄存器的地址。
          其中,形式1是直接通過mov指令來將0這個(gè)值賦給r1寄存器,和形式2中的通過ldr偽指令來將0x3ff賦給r1寄存器,兩者區(qū)別是,前者是因?yàn)橐呀?jīng)確定所要賦的值0x0是mov的有效操作數(shù),而后者對(duì)于0x3ff不確定是否是mov的有效操作數(shù)
          (如果不是,則該指令無效,編譯的時(shí)候,也無法通過編譯,會(huì)出現(xiàn)類似于這樣的錯(cuò)誤:
          1. start.S: Assembler messages:
          2. start.S:149: Error: invalid constant -- `mov r1,#0xFFEFDFFF
          3. make[1]: * [start.o] 錯(cuò)誤 1
          4. make: * [cpu/arm920t/start.o] 錯(cuò)誤 2

          所以才用ldr偽指令,讓編譯器來幫你自動(dòng)判斷:
          (1)如果該操作數(shù)是mov的有效操作數(shù),那么ldr偽指令就會(huì)被翻譯成對(duì)應(yīng)的mov指令。
          舉例說明:
          匯編代碼:

          1. # define pWTCON0x53000000
          2. 。。。
          3. ldr r0, =pWTCON
          被翻譯后的真正的匯編代碼:

          1. 33d00068: e3a00453mov r0, #1392508928 ; 0x53000000
          (2)如果該操作數(shù)不是mov的有效操作數(shù),那么ldr偽指令就會(huì)被翻譯成ldr指令。
          舉例說明:
          匯編代碼:
          1. ldr r1, =0x7fff
          被翻譯后的真正的匯編代碼:

          1. 33d00080: e59f13f8ldr r1, [pc, #1016] ; 33d00480
          2. 。。。
          3. 33d00480: 00007fff.word 0x00007fff
          即把ldr偽指令翻譯成真正的ldr指令,并且另外分配了一個(gè)word的地址空間用于存放該數(shù)值,然后用ldr指令將對(duì)應(yīng)地址中的值載入,賦值給r1寄存器。

          匯編中,一個(gè)常用的,用來給某個(gè)地址賦值的方法,類似如下形式:

          1. #define 宏的名字寄存器地址
          2. 。。。
          3. ldr r1, =要賦的值
          4. ldr r0, =宏的名字
          5. str r1, [r0]



          關(guān)鍵詞: ARM匯編MOVPCL

          評(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); })();