<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > ARM匯編 MOV PC,LR

ARM匯編 MOV PC,LR

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

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

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

本文引用地址:http://dyxdggzs.com/article/201611/317869.htm

BL NEXT ;跳轉到子程序

......... ;NEXT處執行

NEXT

..........

MOV PC,LR ;從子程序返回

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

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

這里有一下總結

首先

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

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

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

3.》我以前看書(shū)不懂的地方

子程序返回的三種方法

現在總結如下

1.MOV PC,LR

2.BL LR

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

STMFD SP!,{,LR}

對應的,使用以下指令可以完成子程序的返回

LDMFD SP!, {,LR}

轉載自:http://blog.csdn.net/xgx198831/article/details/8333446

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

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

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

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

匯編中的b跳轉指令 = C語(yǔ)言中的goto
1.1.3. 匯編中的.globl=C語(yǔ)言中的extern
對于上面例子中:

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

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

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

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

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

不過(guò),對于這樣的類(lèi)似于C語(yǔ)言中的指針的匯編中的標號,在C語(yǔ)言中調用到的話(huà),卻是這樣引用的:
  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. 。。。
而不是我原以為的,直接當做指針來(lái)引用該變量的方式:

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

其中,對應的匯編中的代碼為:

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

匯編中類(lèi)似這樣的代碼:
label1: .word value2
就相當于C語(yǔ)言中的:
int *label1 = value2
但是在C語(yǔ)言中引用該標號/變量的時(shí)候,卻是直接拿來(lái)用的,就像這樣:
label1 = other_value
其中label1就是個(gè)int型的變量。
1.1.6. 匯編中的ldr+標號,來(lái)實(shí)現C中的函數調用
接著(zhù)上面的內容,繼續解釋?zhuān)瑢τ趨R編中這樣的代碼:
第一種:
ldr pc, 標號1
。。。
標號1:.word 標號2
。。。
標號2:
。。。(具體要執行的代碼)
或者是,
第二種:
ldr pc, 標號1
。。。
標號1:.word XXX(C語(yǔ)言中某個(gè)函數的函數名)
的意思就是,將地址為標號1中內容載入到pc中。
而地址為標號1中的內容,就是標號2。
所以上面第一種的意思:
就很容易看出來(lái),就是把標號2這個(gè)地址值,給pc,即實(shí)現了跳轉到標號2的位置執行代碼,就相當于調用一個(gè)函數,該函數名為標號2.
第二種的意思,和上面類(lèi)似,是將C語(yǔ)言中某個(gè)函數的函數名,即某個(gè)地址值,給pc,實(shí)現調用C中對應的那個(gè)函數。
兩種做法,其含義用C語(yǔ)言表達,其實(shí)很簡(jiǎn)單:
PC = *(標號1) = 標號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í)現了將標號1,_software_interrupt,對應的位置中的值,標號2,software_interrupt,給pc,即實(shí)現了將pc掉轉到software_interrupt的位置,即實(shí)現了調用函數software_interrupt的效果。
第二種:

  1. ldr pc, _start_armboot
  2. _start_armboot: .word start_armboot
含義就是,將標號1,_start_armboot,所對應的位置中的值,start_armboot給pc,即實(shí)現了調用函數start_armboot的目的。
其中,start_armboot是C語(yǔ)言文件中某個(gè)C語(yǔ)言的函數。

匯編中,實(shí)現函數調用的效果,有如下兩種方法:
方法1:
ldr pc, 標號1
。。。
標號1:.word 標號2
。。。
標號2:
。。。(具體要執行的代碼)
方法2:
ldr pc, 標號1
。。。
標號1:.word XXX(C語(yǔ)言中某個(gè)函數的函數名)
1.1.7. 匯編中設置某個(gè)寄存器的值或給某個(gè)地址賦值
在匯編代碼start.S中,看到不止一處, 類(lèi)似于這樣的代碼:
形式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è)地址,此處的地址,是用宏定義來(lái)定義的,對應著(zhù)某個(gè)寄存器的地址。
其中,形式1是直接通過(guò)mov指令來(lái)將0這個(gè)值賦給r1寄存器,和形式2中的通過(guò)ldr偽指令來(lái)將0x3ff賦給r1寄存器,兩者區別是,前者是因為已經(jīng)確定所要賦的值0x0是mov的有效操作數,而后者對于0x3ff不確定是否是mov的有效操作數
(如果不是,則該指令無(wú)效,編譯的時(shí)候,也無(wú)法通過(guò)編譯,會(huì )出現類(lèi)似于這樣的錯誤:
  1. start.S: Assembler messages:
  2. start.S:149: Error: invalid constant -- `mov r1,#0xFFEFDFFF
  3. make[1]: * [start.o] 錯誤 1
  4. make: * [cpu/arm920t/start.o] 錯誤 2

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

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

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

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

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

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



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

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>