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

          新聞中心

          arm匯編指令整理

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

          .align的作用在于對指令或者數(shù)據(jù)的存放地址進(jìn)行對齊,有些CPU架構(gòu)要求固定的指令長度并且存放地址相對于2的冪指數(shù)圓整,否則程序無法正常運行,比如ARM;有些系統(tǒng)卻不需要,如果不遵循地址的圓整規(guī)則,程序依然可以正確執(zhí)行,只是降低了一些執(zhí)行效率,比如i386。.align的作用范圍只限于緊跟它的那條指令或者數(shù)據(jù),而接下來的指令或者數(shù)據(jù)的地址由上一條指令的地址和其長度決定。

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

          ARM匯編器并不直接使用.align提供的參數(shù)作為對齊目標(biāo),而是使用2^n的值,比如這里的參數(shù)為4,那么圓整對象為2^4 = 16。這也就是為什么在ARM平臺的Uboot或者Linux內(nèi)核匯編中會出現(xiàn).align 5的根本原因。.align此時的取值范圍為0-15,當(dāng)取值為0,2或者不提供參數(shù)時均圓整于4。如果嘗試使用大于15的值,將會得到編譯器的err。

          在指令出現(xiàn)非對齊情況下,插入.align偽指令,對于32bit的ARM會進(jìn)行4byte的指令對齊。

          2..rept

          .rept和.endr之間的語句count次。

          3..text

          幾個常用的段代號,基本上與編譯器/處理器都沒有無關(guān)系(FLAT模式):
          .text- 代碼段
          .const - 只讀數(shù)據(jù)段(有些編譯器不使用此段,將只讀數(shù)據(jù)并入.data段)
          .data- 讀寫數(shù)據(jù)段
          .bss - 堆

          4..extern

          ".extern"定義一個外部符號(可以是變量也可以是函數(shù)。

          5..global

          ".global"將本文件中的某個程序標(biāo)號定義為全局的。

          6..word

          .word expression就是在當(dāng)前位置放一個word型的值,這個值就是expression。

          相當(dāng)于用.word定義了一個16bit的數(shù)據(jù)。
          舉例來說,
          _rWTCON:
          .word 0x15300000
          就是在當(dāng)前地址,即_rWTCON處放一個值0x15300000

          7.更多偽指令

          http://www.byywee.com/page/M0/S774/774183.html

          8.條件碼表

          條件碼助記符

          標(biāo)志

          含義

          EQ

          Z=1

          相等

          NE

          Z=0

          不相等

          CS/HS

          C=1

          無符號數(shù)大于或等于

          CC/LO

          C=0

          無符號數(shù)小于

          MI

          N=1

          負(fù)數(shù)

          PL

          N=0

          正數(shù)

          VS

          V=1

          溢出

          VC

          V=0

          沒有溢出

          HI

          C=1,Z=0

          無符號數(shù)大于

          LS

          C=0,Z=1

          無符號數(shù)小于或等于

          GE

          N=V

          帶符號數(shù)大于或等于

          LT

          N!=V

          帶符號數(shù)小于

          GT

          Z=0,N=V

          帶符號數(shù)大于

          LE

          Z=1,N!=V

          帶符號數(shù)小于或等于

          AL

          任何無條件執(zhí)行(指令默認(rèn)條件)

          9.ldr

          偽指令LDR

          大范圍的地址讀取偽指令.LDR偽指令用于加載32位的立即數(shù)或一個地址值到指定寄存器.在匯編編譯源程序時,LDR偽指令被編譯器替換成一條合適的指令.若加載的常數(shù)未超出MOV或MVN的范圍,則使用MOV或MVN指令代替該LDR偽指令,否則匯編器將常量放入字池,并使用一條程序相對偏移的LDR指令從文字池讀出常量.LDR偽指令格式如下:
          LDR{cond} register,=expr/label_expr
          其中register加載的目標(biāo)寄存器
          expr 32位立即數(shù).
          label_expr基于PC的地址表達(dá)式或外部表達(dá)式.

          LDR/STR指令用于對內(nèi)存變量的訪問,內(nèi)存緩沖區(qū)數(shù)據(jù)的訪問、查表、外圍部件的控制操作等等,若使用LDR指令加載數(shù)據(jù)到PC寄存器,則實現(xiàn)程序跳轉(zhuǎn)功能,這樣也就實現(xiàn)了程序散轉(zhuǎn)。

          ldr r1, [r2, #4] /*將地址為r2+4的內(nèi)存單元數(shù)據(jù)讀取到r1中*/
          ldr r1,[r2] /*將地址為r2的內(nèi)存單元數(shù)據(jù)讀取到r1中*/
          ldr r1,[r2], #4/*將地址為r2的內(nèi)存單元數(shù)據(jù)讀取到r1中,然后r2=r2+4*/
          str r1 ,[r2, #4]/*將r1的數(shù)據(jù)保存到地址為r2+4的內(nèi)存單元中*/
          str r1, [r2]/*將r1的數(shù)據(jù)保存到地址為r2的內(nèi)存單元中。*/
          str r1, [r2],#4/*將r1的數(shù)據(jù)保存到地址為r2的內(nèi)存單元,然后r2= r2+4*/

          ldrb:8bit=>1byte

          ldrh:16bit=>2byte

          LDR R0,LED_TAB
          LDR R1, =LED_TAB
          LED_TAB: .work 0x12345678
          R0的值是0x12345678,R1的值是LED_TAB標(biāo)號值,就是0x12345678在內(nèi)存中存放的地址

          10.adr

          轉(zhuǎn)自:http://coon.blogbus.com/logs/2738861.html

          ldr r0, _start

          adr r0, _start

          ldr r0, =_start

          nop

          mov pc, lr

          _start:

          nop

          編譯的時候設(shè)置 R0 為 0x0c008000

          ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

          0c008000 <_start-0x14>:

          c008000: e59f000c ldr r0, [pc, #12] ; c008014 <_start>

          c008004: e28f0008 add r0, pc, #8 ; 0x8

          c008008: e59f0008 ldr r0, [pc, #8] ; c008018 <_start+0x4>

          c00800c: e1a00000 nop (mov r0,r0)

          c008010: e1a0f00e mov pc, lr

          0c008014 <_start>:

          c008014: e1a00000 nop (mov r0,r0)

          c008018: 0c008014 stceq 0, cr8, [r0], -#80

          分析:

          ldr r0, _start

          從內(nèi)存地址 _start 的地方把值讀入。執(zhí)行這個后,r0 = 0xe1a00000

          adr r0, _start

          取得 _start 的地址到 r0,但是請看反編譯的結(jié)果,它是與位置無關(guān)的。其實取得的時相對的位置。例如這段代碼在 0x0c008000 運行,那么 adr r0, _start 得到 r0 = 0x0c008014;如果在地址 0 運行,就是 0x00000014 了。

          ldr r0, =_start

          這個取得標(biāo)號 _start 的絕對地址。這個絕對地址是在 link 的時候確定的。看上去這只是一個指令,但是它要占用 2 個 32bit 的空間,一條是指令,另一條是 _start 的數(shù)據(jù)(因為在編譯的時候不能確定 _start 的值,而且也不能用 mov 指令來給 r0 賦一個 32bit 的常量,所以需要多出一個空間存放 _start 的真正數(shù)據(jù),在這里就是 0x0c008014)。

          因此可以看出,這個是絕對的尋址,不管這段代碼在什么地方運行,它的結(jié)果都是 r0 = 0x0c008014

          11.ldm

          ldm和stm屬于批量內(nèi)存訪問指令,只用一條指令就可以讀寫多個數(shù)據(jù)。它們的格式如下:

          ldm{cond} {!} {^}

          stm{cond} {!} {^}

          其中,

          {cond}表示指令的執(zhí)行條件,參見下面的指令條件碼。

          表示地址變化模式,有以下幾種方式:

          1)ia(increment after): 傳送后遞增方式;

          2)ib(increment before): 傳送前遞增方式;

          3)da(decrement after): 傳送后遞減方式;

          4)db(decrement before):傳送前遞減方式;

          5)fd(full descending): 滿遞減堆棧;

          6)ed(empty descending):空遞減堆棧;

          7)fa(full ascending): 滿遞增堆棧;

          8)ea(empty ascending): 空遞增堆棧;

          中保存內(nèi)存的地址,如果后面加上了感嘆號,指令執(zhí)行后,rm的值會更新,等于下一個內(nèi)存單元的地址。

          表示寄存器列表,對于ldm指令,從所對應(yīng)的內(nèi)存塊中取出數(shù)據(jù),寫入這些寄存器;對于stm指令,把這些寄存器的值寫入所對應(yīng)的內(nèi)存塊中。

          {^}有兩種含義:如果中有PC寄存器,它表示指令執(zhí)行后,spsr寄存器的值將自動到cpsr寄存器中——這常用于從中斷處理函數(shù)中返回;如果中沒有PC寄存器,{^}表示操作的是用戶模式下的寄存器,而不是當(dāng)前特權(quán)模式的寄存器。

          指令中寄存器列表和內(nèi)存單元的對應(yīng)關(guān)系為:編號低的寄存器對應(yīng)于內(nèi)存中的低地址單元,編號高的寄存器對應(yīng)于內(nèi)存中高地址的單元。

          ldmia r0!, {r3-r10} /*將基址寄存器r0開始的連續(xù)8個地址單元的值分別賦給r3,r4,r5,r6,r7,r8,r9,r10,注意的是r0指定的地址每次賦一次r0會加1,指向下一個地址單元*/

          stmia r1!, {r3-r10} /*跟上面指令功能相反,將寄存器r3到r10的值依次賦值給r1指定的地址單元,每次賦值一次r1就加1*/

          堆棧尋址:堆棧是特定順序進(jìn)行存取的存儲區(qū),堆棧尋址時隱含的使用一個專門的寄存器(堆棧指針),指向一塊存儲區(qū)域(堆棧),存儲器堆??煞譃閮煞N:

          向上生長:向高地址方向生長,稱為遞增堆棧。
          向下生長:向低地址方向生長,稱為遞減堆棧。


          如此可結(jié)合出四種情況:
          1、滿遞增:堆棧通過增大存儲器的地址向上增長,堆棧指針指向內(nèi)含有效數(shù)據(jù)項的最高地址,棧指針總是指向最后一個元素(最后入棧的數(shù)據(jù)),指令如 LDMFA,STMFA。
          2、空遞增:堆棧通過增大存儲器的地址向上增長,堆棧指針指向堆棧上的第一個空位置,棧指針總是指向下一個將要放入數(shù)據(jù)的空位置,指令如 LDMEA,STMEA。
          3、滿遞減:堆棧通過減小存儲器的地址向下增長,堆棧指針指向內(nèi)含有效數(shù)據(jù)項的最低地址,棧指針總是指向最后一個元素(最后入棧的數(shù)據(jù)),指令如 LDMFD,STMFD。
          4、空遞減:堆棧通過減小存儲器的地址向下增長,堆棧指針指向堆棧下的第一個空位置,棧指針總是指向下一個將要放入數(shù)據(jù)的空位置,指令如 LDMED,STMED。

          滿:棧指針總是指向最后一個元素(最后入棧的數(shù)據(jù))。

          空:棧指針總是指向下一個將要放入數(shù)據(jù)的空位置。

          增:棧首部是低地址,棧向高地址增長。

          減:棧首部是高地址,棧向低地址增長。

          STMFD SP!,{R1-R7,LR} ;將R1-R7,LR入棧,滿遞減堆棧
          LDMFD SP!,{R1-R7,LR} ;數(shù)據(jù)出棧,放入R1-R7,LR寄存器,滿遞減堆棧

          ARM-Thumb過程調(diào)用標(biāo)準(zhǔn)和ARM、Thumb C/C++ 編譯器總是使用Full descending 類型堆棧。

          以前困惑的就是STMFD 命令 對于操作數(shù) 是按照什么順序壓棧的

          比如:STMFD sp!{R0-R5,LR} 進(jìn)棧順序是:

          高地址(1方式) LR R5 R4 ``````` R0 <-sp 低地址

          高地址(2方式) R0 R1 ``` R5 LR <-sp 低地址

          尋址方式

          說明

          pop

          =LDM

          push

          =STM

          FA

          遞增滿

          LDMFA

          LDMDA

          STMFA

          STMIB

          FD

          遞減滿

          LDMFD

          LDMIA

          STMFD

          STMDB

          EA

          遞增空

          LDMEA

          LDMDB

          STMEA

          STMIA

          ED

          遞減空

          LDMED

          LDMIB

          STMED

          STMDA

          按照圖表,可知 STMFD對應(yīng)的是STMDB,根據(jù)arm指令手冊,可知STMDB入棧順序是1方式,而LDMFD對應(yīng)的是LDMIA,這樣這兩個操作就可以成功配對。

          在寄存器傳輸中,基地址可以在傳輸前或者傳輸后遞增或者遞減:STMIA r10,{r1,r3-r5,r8}

          后綴IA還可以是IB,DA或者DB。這里I表示遞增(increment),D表示遞減(decrement),A表示后(after),B表示前(before)。

          無論是哪種情況,編號最小的寄存器與最低存儲器地址間進(jìn)行傳輸,編號最大的寄存器與最高存儲器地址間進(jìn)行傳輸。寄存器出現(xiàn)在列表中的次序是無關(guān)緊要的。而且,ARM總是以遞增存儲器地址的方式進(jìn)行順序存儲器訪問。所以,遞減傳輸實際上是先進(jìn)行一個減操作,然后在數(shù)據(jù)傳輸中進(jìn)行地址遞增操作。

          除非是特別指定,傳輸完成后基地址寄存器的值是不變的。如果要更新基地址寄存器,必須用!(感嘆號)特別指明: LDMDB r11!,{r9,r4-r7},指令執(zhí)行后r11=原來r11中的值-12。

          http://blog.csdn.net/xiaomt_rush/article/details/6501711

          12.ldrex

          在 include/asm-arm/spinlock.h 下有這麼一段

          #if __LINUX_ARM_ARCH__ <6
          #errorSMP not supported on pre-ARMv6 CPUs
          #endif

          好啦,前提就是:只有ARM core版本>=6才可以繼續(xù):

          all spin lock primitives 到最後都是使用下面這個基本型:

          static inline void__raw_spin_lock(raw_spinlock_t *lock)
          {
          unsigned longtmp;

          1 __asm____volatile__(
          2"1: ldrex %0, [%1]n"
          3" teq %0, #0n"
          4" strexeq %0, %2, [%1]n"
          5" teqeq %0, #0n"
          6" bne 1b"
          7 : "=&r" (tmp)
          8 : "r" (&lock->lock), "r" (1)
          9: "cc");

          smp_mb();
          }

          [指令重點]:

          ldrex 指令是 core 6 以後才有的,跟 strex 配成一對指令,可以請 bus 監(jiān)控從 ldrex 到 strex 之間有無其他的 CPU 或 DMA 來存取這個位址 ,若有的話,strex 會在第一個 register 裡設(shè)定值為 1(non-exclusive by this CPU) 並且令 store 動作失敗,若沒有,strex 會在第一個 register 裡設(shè)定值為 0(exclusive access by this CPU) 並且令 store 動作成功。

          Code Trace Discussion:

          Line 1: __volatile__ 告訴 compiler ,不要對這塊 assembly template 做最佳化動作,因為我們裡面有 loop 讀取 memory 動作,最佳化的結(jié)果可能導(dǎo)致 compiler 用一個 register 來 cache 它的值,不會老老實實的去讀 memory... ,這不是我們想要的動作喔!

          Line 2: 把 lock 讀到 tmp,並請 bus monitor 這個 memory。

          Line 3: 測試 lock 是否為 0,若非 0,表示 lock 已經(jīng)被別人取得了,則 Line 4,5 都不做了,然後 Line 6 一定 branch,做 spin 的動作。若為 0,表示有機(jī)會取得 lock,繼續(xù)做 Line 4.5.。

          Line 4:重點來了!,核對 bus monitor 的結(jié)果,若是exclusive access 則 tmp 設(shè)為 0 並且把 1 儲存到 lock,若是 non-exclusive access(有其他 CPU 來動過)則 tmp設(shè)為 1並且不做儲存 lock 的動作。

          Line 5: 測試 tmp。

          Line 6: 若 tmp 為 0 表示剛剛對 lock 動作是 exclusive,可以離開迴圈,若 tmp 為 1,則做 spin 動作。

          Line 7: tmp 用 register 來操作,同時是 input 及 output 令它為 %0。

          Line 8: &lock->lock 用 register 來操作 ,令它為 %1,值 1 用 register 來操作 ,令它為 %2。

          Line 9: 此 template 會改到 condition code,加入 clobber list 以告訴 compiler 有這回事。

          好了,終於看完了,真的很佩服那些 coding 的 kernel hackers ....

          思考問題: ARM v6 以前有個 SWP 指令可以 lock bus and swap memory ,一樣可以用來完成 exclusive access ,但是比起 ldrex,strex 這對指令有什麼缺點呢?

          SWP lock bus,其他 CPU 所有動作都不能做,但是 ldrex,strex就不會有這種現(xiàn)象,使用 ldrex,strex 時若其他 CPU不來 access 這個特定的 memory 就可以平行的做動作,增加平行執(zhí)行的 performance。

          13.swi

          SWI,即software interrupt軟件中斷。該指令產(chǎn)生一個SWI異常。意思就是處理器模式改變?yōu)槌売脩裟J剑珻PSR寄存器保存到超級用戶模式下的SPSR寄存器,并且跳轉(zhuǎn)到SWI向量。其ARM指令格式如下:

          SWI{cond} immed_24

          Cond域:是可選的條件碼 (參見 ARM匯編指令條件執(zhí)行詳解).

          immed_24域:范圍從 0 到 224-1 的表達(dá)式, (即0-16777215)。用戶程序可以使用該常數(shù)來進(jìn)入不同的處理流程。

          一、方法1:獲取immed_24操作數(shù)。

          為了能實現(xiàn)根據(jù)指令中immed_24操作數(shù)的不同,跳轉(zhuǎn)到不同的處理程序,所以我們往往需要在SWI異常處理子程序中去獲得immed_24操作數(shù)的實際內(nèi)容。獲得該操作數(shù)內(nèi)容的方法是在異常處理函數(shù)中使用下面指令:

          LDR R0,[LR,#-4]

          該指令將鏈接寄存器LR的內(nèi)容減去4后所獲得的值作為一個地址,然后把該地址的內(nèi)容裝載進(jìn)R0。此時再使用下面指令,immed_24操作數(shù)的內(nèi)容就保存到了R0:

          BIC R0,R0,#0xFF000000

          該指令將R0的高8位清零,并把結(jié)果保存到R0,意思就是取R0的低24位。

          可能還是有人會問:為什么在SWI異常處理子程序中執(zhí)行這兩條指令后,immed_24操作數(shù)的內(nèi)容就保存到了R0寄存器呢?之所以會有這樣的疑問,基本都是因為對LR寄存器的作用沒了解清楚。下面介紹一下鏈接寄存器LR(R14)的作用。

          寄存器R14(LR寄存器)有兩種特殊功能:

          ·在任何一種處理器模式下,該模式對應(yīng)的R14寄存器用來保存子程序的返回地址。當(dāng)執(zhí)行BL或BLX指令進(jìn)行子程序調(diào)用時,子程序的返回地址被放置在R14中。這樣,只要把R14內(nèi)容拷貝到PC中,就實現(xiàn)了子程序的返回(具體的子程序返回操作,這里不作詳細(xì)介紹)。

          ·當(dāng)某異常發(fā)生時,相應(yīng)異常模式下的R14被設(shè)置成異常返回的地址(對于某些異常,可能是一個偏移量,一個較小的常量)。異常返回類似于子程序返回,但有小小的不同(這里不作詳細(xì)介紹)。

          所謂的子程序的返回地址,實際就是調(diào)用指令的下一條指令的地址,也就是BL或BLX指令的下一條指令的地址。所謂的異常的返回的地址,就是異常發(fā)生前,CPU執(zhí)行的最后一條指令的下一條指令的地址。

          例如:(子程序返回地址示例)

          指令 指令所在地址

          ADD R2,R1,R3 ;0x300000

          BL subC ;0x300004

          MOV R1,#2 ;0x300008

          BL指令執(zhí)行后,R14中保存的子程序subC的返回地址是0x300008。

          再例如:(異常返回地址示例)

          指令 指令所在地址

          ADD R2,R1,R3 ;0x300000

          SWI 0x98 ;0x300004

          MOV R1,#2 ;0x300008

          SWI指令執(zhí)行后,進(jìn)入SWI異常處理程序,此時R14中保存的返回地址為0x300008。

          所以,在SWI異常處理子程序中執(zhí)行LDR R0,[LR,#-4]語句,實際就是把產(chǎn)生本次SWI異常的SWI指令的內(nèi)容(如:SWI 0x98)裝進(jìn)R0寄存器。又因為SWI指令的低24位保存了指令的操作數(shù)(如:0x98),所以再執(zhí)行BIC R0,R0,#0xFF000000語句,就可以獲得immed_24操作數(shù)的實際內(nèi)容。

          二、方法2:使用參數(shù)寄存器。

          實際上,在SWI異常處理子程序的實現(xiàn)時,還可以繞開immed_24操作數(shù)的獲取操作,這就是說,我們可以不去獲取immed_24操作數(shù)的實際內(nèi)容,也能實現(xiàn)SWI異常的分支處理。這就需要使用R0-R4寄存器,其中R0-R4可任意選擇其中一個,一般選擇R0,遵從ATPCS原則。

          具體方法就是,在執(zhí)行SWI指令之前,給R0賦予某個數(shù)值,然后在SWI異常處理子程序中根據(jù)R0值實現(xiàn)不同的分支處理。例如:

          指令 指令所在地址

          MOV R0,#1 ; #1給R0

          SWI 0x98 ; 產(chǎn)生SWI中斷,執(zhí)行異常處理程序SoftwareInterrupt

          ADD R2,R1,R3 ;

          ;SWI異常處理子程序如下

          SoftwareInterrupt

          CMP R0, #6 ; if R0 < 6

          LDRLO PC, [PC, R0, LSL #2] ; if R0 < 6,PC = PC + R0*4,else next //PC-8處的指令

          MOVS PC, LR //PC-4處的指令

          SwiFunction

          DCD function0 ;0//PC處的指令

          DCD function1 ;1

          DCD function2 ;2

          DCD function3 ;3

          DCD function4 ;4

          DCD function5 ;5

          Function0

          異常處理分支0代碼

          Function1

          異常處理分支1代碼

          function2

          異常處理分支2代碼

          function3

          異常處理分支3代碼

          function4

          異常處理分支4代碼

          function5

          異常處理分支5代碼

          在ARM體系結(jié)構(gòu)中,當(dāng)正確讀取了PC的值時,該值為當(dāng)前指令地址值加8字節(jié),也就是說,對于ARM指令集來說,讀出的PC值指向當(dāng)前指令的下兩條指令的地址,本例中就是指向SwiFunction 表頭DCD function0這個地址,在該地址中保存了異常處理子分支function0的入口地址。所以,當(dāng)進(jìn)入SWI異常處理子程序SoftwareInterrupt時,如果R0=0,執(zhí)行LDRLO PC, [PC, R0, LSL #2]語句后,PC的內(nèi)容即為function0的入口地址,即程序跳轉(zhuǎn)到了function0執(zhí)行。在本例中,因為R0=1,所以,實際程序是跳轉(zhuǎn)到了function1執(zhí)行。R0左移2位(LDRLO PC, [PC,R0, LSL #2]),即R0*4,是因為ARM指令是字(4個字節(jié))對齊的DCD function0等偽指令也是按4字節(jié)對齊的。

          在本方法的實現(xiàn)中,實際指令中的24位立即數(shù)(immed_24域)被忽略了, 就是說immed_24域可以為任意合法的值。如在本例中,不一定使用SWI 0x98,還可以為SWI 0x00或者SWI 0x01等等,程序還是會進(jìn)入SWI異常處理子程序SoftwareInterrupt,然后根據(jù)R0的內(nèi)容跳轉(zhuǎn)到相應(yīng)的子分支。

          ARM處理器使用流水線來增加處理器指令流的速度,這樣可使幾個操作同時進(jìn)行,并使處理與存儲器系統(tǒng)之間的操作更加流暢,連續(xù),能提供0.9MIPS/MHZ的指令執(zhí)行速度。 PC代表程序計數(shù)器,流水線使用三個階段,因此指令分為三個階段執(zhí)行:

          1.取指(從存儲器裝載一條指令);

          2.譯碼(識別將要被執(zhí)行的指令);

          3.執(zhí)行(處理指令并將結(jié)果寫回寄存器)。

          而R15(PC)總是指向“正在取指”的指令,而不是指向“正在執(zhí)行”的指令或正在“譯碼”的指令。一般來說,人們習(xí)慣性約定將“正在執(zhí)行的指令作為參考點”,稱之為當(dāng)前第一條指令,因此PC總是指向第三條指令。當(dāng)ARM狀態(tài)時,每條指令為4字節(jié)長,所以PC始終指向該指令地址加8字節(jié)的地址,即:PC值=當(dāng)前程序執(zhí)行位置+8;

          周期1 周期2 周期3 周期4 周期5 周期6

          PC-8取指 譯碼 執(zhí)行

          PC-4 取指 譯碼 執(zhí)行

          PC 取指 譯碼執(zhí)行

          14.cmp

          CMP比較指令,用于把一個寄存器的內(nèi)容和另一個寄存器的內(nèi)容或一個立即數(shù)進(jìn)行比較,同時更新CPSR中條件標(biāo)志位的值。指令將第一操作數(shù)減去第二操作數(shù),但不存儲結(jié)果,只更改條件標(biāo)志位。

          CMP R1, R0 ;做R1-R0的操作。

          CMP R1,#10 ;做R1-10的操作。

          15.txt

          TST位測試指令,用于把一個寄存器的內(nèi)容和另一個寄存器的內(nèi)容或立即數(shù)進(jìn)行按位的與運算,并根據(jù)運算結(jié)果更新CPSR中條件標(biāo)志位的值。操作數(shù)1是要測試的數(shù),而操作數(shù)2 是一個位掩碼,該指令一般用來檢測是否設(shè)置了特定的位。

          TST {條件} 操作數(shù)1, 操作數(shù)2

          例:TST R0, #0X0000 0040 ; 指令用來測試R0的位3是否為1。

          TST指令通常和EQ、NE條件碼配合使用,當(dāng)所有測試位為0時,EQ有效,而只要有一個測試位不為0,則NE有效。

          16.teq

          TEQ相等測試指令,用于把一個寄存器的內(nèi)容和另一個寄存器的內(nèi)容或立即數(shù)進(jìn)行按位的異或運算,并根據(jù)運算結(jié)果更新CPSR中的條件標(biāo)志位。指令用于比較兩個操作數(shù)是否相等。如果相等,則 Z = 1,否則Z = 0。指令通常和EQ、NE條件碼配合使用

          例:TEQ R1, R2

          TST R1,#%1;測試R1中是否設(shè)置了最低位(%表示二進(jìn)制數(shù)

          17.cmn

          CMN -- 比較取負(fù)的值

          CMN{條件}{P} ,

          status = op1 - (-op2)

          CMN R0, #1 @把R0與-1進(jìn)行比較

          18.bic

          BIC指令用于清除操作數(shù)1的某些位,并把結(jié)果放置到目的寄存器中,如果在掩碼中設(shè)置了某一位,則清除這一位。未設(shè)置的掩碼位保持不變。

          例:BIC R1, R1, #0X0F ;將R1的低四位清零,其他位不變。



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

          評論


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