ARM匯編和內(nèi)嵌匯編
首先要判斷我們用的是ldr arm指令還是偽指令。 當(dāng)我們用的是arm指令時(shí),它的作用不是向寄存器里加載立即數(shù),而是將某個(gè)地址里 的內(nèi)容加載到寄存器。而偽指令ldr的作用就是向寄存器里加載立即數(shù)。
(1) ldr偽指令
ldr偽指令的格式是 ldr Rn, =expr
其中,expr是要加載到Rn中的內(nèi)容,一般可以是立即數(shù)或者label。
如果expr可以用8bit數(shù)據(jù)向右移偶數(shù)位得到,那么這條偽指令就被編譯器翻譯成mov指令。具體的移位情況可以去查閱資料。反之如果立即數(shù)很大,超過(guò)了12bit的表示范疇,那么就不能用一條mov指令了,畢竟arm指令最大只有32bit的空間可用(RISC的arm所有的指令長(zhǎng)度是一致的,效率較高,當(dāng)然我們并不關(guān)心16bit的thumb指令)。如果不能用一條32bit的指令乘下來(lái),那么就只能另辟蹊徑了,新開(kāi)一段緩沖,將立即數(shù)expr放到里面,然后將其地址(暫時(shí)標(biāo)記為addr)拿來(lái)使用:
ldr Rn, addr
xxx (xxx就是expr)
xxx
由于編譯器一般來(lái)說(shuō)新安排的存儲(chǔ)這個(gè)立即數(shù)expr的緩沖的位置是在相應(yīng)代碼的附近(這個(gè)應(yīng)該可以控制,好像是使用.ltorg偽指令)。我們從addr地址加載數(shù)據(jù)到Rn不就可以了。
(2)ldr arm 指令
就是將一個(gè)地址的內(nèi)容加載到寄存器。不能用mov,因?yàn)閍rm里的mov只是在寄存器之間傳輸數(shù)據(jù),不支持在寄出器和memory之間傳遞數(shù)據(jù)。因此就出現(xiàn)了ldr/str指令。如ldr Rn, addr,注意這里的addr的值也是有限制的。這個(gè)label應(yīng)該距離當(dāng)前指令的距離不超過(guò)4k。因?yàn)槲覀冎纋abel在具體使用的時(shí)候應(yīng)該是被翻譯成了相對(duì)偏移,如果這個(gè)label長(zhǎng)度不超過(guò)12bit,那么就不應(yīng)超過(guò)4k,我們可以這樣做:
ldr pc, _start_armboot
_start_armboot: .word arm_startboot
這樣label _start_armboot就在指令下方,因此肯定是合法的。
ldr r0, [r1, #4] 的含義就是把r1+4 這個(gè)地址處的DOWRD 加載到r0,而尋址后,r1 的內(nèi)容并不改變。
ldr r0, [r1, #4]! 這種變址方式有點(diǎn)類似于++i的含義,尋址前先對(duì)基地址寄存器進(jìn)行運(yùn)算,然后尋址. 其基本的語(yǔ)法是在尋址符[]后面加上一個(gè)"!" 來(lái)表示
二、.world
說(shuō)說(shuō)這個(gè) .word 的作用。
word expression 就是在當(dāng)前位置放一個(gè) word 型的值,這個(gè)值就是expression
舉例來(lái)說(shuō),
_rWTCON:
.word 0x15300000
就是在當(dāng)前地址,即 _rWTCON 處放一個(gè)值0x15300000
不是把地址0x1530 0000 上的內(nèi)容傳遞到r1,是把地址_rWTCON上的內(nèi)容放到r1,而地址_rWTCON上的內(nèi)容是0x15300000。實(shí)際上就是把r1設(shè)置為0x15300000
三 bic
BIC(位清除)指令對(duì) Rn 中的值 和 Operand2 值的反碼按位進(jìn)行邏輯“與”運(yùn)算。 (注意:ARM官方網(wǎng)站有誤, 寫的是補(bǔ)碼)
BIC 是 邏輯”與非” 指令, 實(shí)現(xiàn)的 Bit Clear的功能
舉例:
BIC R0, R0 , #0xF0000000
#將 R0 高4位清零
BIC R1, R1, #0x0F
#將R1 低4位清0
RSB 反向減法
Rn, Operand2
RSB(反向減法)指令可從 Operand2 中的值減去 Rn 中的值。
這是很有用的,因?yàn)橛辛嗽撝噶?,Operand2 的選項(xiàng)范圍就會(huì)更大。
例如:
RSB r4, r4, #1280
從1280中減去 R4
RSB R4, R0, #0×46
從0×46 中 減去 R0, 放入R4
四、ADR
ADR的定義為:小范圍的地址讀取偽指令,ADR指令將基于PC相對(duì)偏移的地址值讀取到寄存器中,在編譯源程序時(shí)ADR偽指令被編譯器 替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來(lái)實(shí)現(xiàn)該ADR偽指令的功能,若不能用一條指令實(shí)現(xiàn),剛產(chǎn)生錯(cuò)誤。
在如上的定義中,有兩個(gè)關(guān)鍵信息:⑴將基于PC相對(duì)偏移的地址值讀取到寄存器中;⑵被編譯器替換成一條合適的指令。ADR指令只能將地址值讀取到寄存器中,而不能是其它的立即數(shù),并用只能用一條指令。
如果在匯編程序中使用ADR R1,ResetHandel語(yǔ)句,其中ResetHandel是匯編程序中的一個(gè)標(biāo)簽,此條偽指令的作用是把ResetHandel標(biāo)簽所在的指令地址 讀取到寄存器R0中
根據(jù)上面的分析,可以看到,編譯器在編譯的時(shí)候把ADR偽指令編譯成一個(gè)ADD R1,PC,Immediate指令,其中Immediate是一個(gè)立即數(shù),數(shù)值是ResetHandel語(yǔ)句和此條偽指令之間的差值,由編譯器自動(dòng)算 出。由于立即數(shù)尋址的約束,這個(gè)Immediate存在一定的約束,所以會(huì)出現(xiàn)定義中所說(shuō)的不能用一條指令實(shí)現(xiàn)。
五、ldmia 和 stmia
所有的示例指令執(zhí)行前:
mem32[0x1000C] = 0x04
mem32[0x10008] = 0x03
mem32[0x10004] = 0x02
mem32[0x10000] = 0x01
r0 = 0x00010010
r1 = 0x00000000
r3 = 0x00000000
r4 = 0x00000000
1) ldmia r0!, {r1-r3} 2) ldmib r0!, {r1-r3}
執(zhí)行后: 執(zhí)行后:
r0 = 0x0010001C r0 = 0x0010001C
r1 = 0x01 r1 = 0x02
r2 = 0x02 r2 = 0x03
r3 = 0x03 r3 = 0x04
至于DA 和DB 的模式,和IA / IB 是類似的,不多說(shuō)了。
最后要說(shuō)的是,使用ldm 和stm指令對(duì)進(jìn)行寄存器組的保護(hù)是很常見(jiàn)和有效的功能。配對(duì)方案:
stmia / ldmdb
stmib / ldmda
stmda / ldmib
stmdb / ldmia
繼續(xù)來(lái)看兩個(gè)例子:
執(zhí)行前:
r0 = 0x00001000
r1 = 0x00000003
r2 = 0x00000002
r3 = 0x00000001
執(zhí)行的指令:
stmib r0!, {r1-r3}
mov r1, #1 ; These regs have been modified
mov r2, #2
mov r3, #3
當(dāng)前寄存器狀態(tài):
r0 = 0x0000100C
r1 = 0x00000001
r2 = 0x00000002
r3 = 0x00000003
ldmia r0!, {r1-r3}
最后的結(jié)果:
r0 = 0x00001000
r1 = 0x00000003
r2 = 0x00000002
r3 = 0x00000001
另外,我們還可以利用這個(gè)指令對(duì)完成內(nèi)存塊的高效copy:
loop
ldmia r9!, {r0-r7}
stmia r10!, {r0-r7}
cmp r9, r11
bne loop
六、CMP
CMP指令的格式為:
CMP{條件} 操作數(shù)1,操作數(shù)2
CMP指令用于把一個(gè)寄存器的內(nèi)容和另一個(gè)寄存器的內(nèi)容或立即數(shù)進(jìn)行比較,同時(shí)更新CPSR中條件標(biāo)志位的值。該指令進(jìn)行一次減法運(yùn)算,但不存儲(chǔ)結(jié)果,只 更改條件標(biāo)志位。標(biāo)志位表示的是操作數(shù)1與操作數(shù)2的關(guān)系(大、小、相等),例如,當(dāng)操作數(shù)1大于操作操作數(shù)2,則此后的有GT 后綴的指令將可以執(zhí)行。
指令示例:
CMP R1,R0 ;將寄存器R1的值與寄存器R0的值相減,并根據(jù)結(jié)果設(shè)置CPSR的標(biāo)志位
CMP R1,#100 ;將寄存器R1的值與立即數(shù)100相減,并根據(jù)結(jié)果設(shè)置CPSR的標(biāo)志位
cmp r0, #0
beq 1f ; 如果r0==0那么向前跳轉(zhuǎn)到B處執(zhí)行
bne 1b ; 否則向后跳轉(zhuǎn)到A處執(zhí)行1: ;
1b,1f里的b和f表示backward和forward,1表示局部標(biāo)簽1
TST R0, #0X8
BNE SuspendUp ;BNE指令是“不相等(或不為0)跳轉(zhuǎn)指令”:
LDR R1,#0x00000000
先進(jìn)行and運(yùn)算,如果R0的第四位不為1,則結(jié)果為零,則設(shè)置zero=1(繼續(xù)下面的LDR指令);
否則,zero=0(跳到SuspendUp處執(zhí)行)
評(píng)論