ARM汇编和内嵌汇编
首先要判断我们用的是ldr arm指令还是伪指令。 当我们用的是arm指令时,它的作用不是向寄存器里加载立即数,而是将某个地址里 的内容加载到寄存器。而伪指令ldr的作用就是向寄存器里加载立即数。
(1) ldr伪指令
ldr伪指令的格式是 ldr Rn, =expr
其中,expr是要加载到Rn中的内容,一般可以是立即数或者label。
如果expr可以用8bit数据向右移偶数位得到,那么这条伪指令就被编译器翻译成mov指令。具体的移位情况可以去查阅资料。反之如果立即数很大,超过了12bit的表示范畴,那么就不能用一条mov指令了,毕竟arm指令最大只有32bit的空间可用(RISC的arm所有的指令长度是一致的,效率较高,当然我们并不关心16bit的thumb指令)。如果不能用一条32bit的指令乘下来,那么就只能另辟蹊径了,新开一段缓冲,将立即数expr放到里面,然后将其地址(暂时标记为addr)拿来使用:
ldr Rn, addr
xxx (xxx就是expr)
xxx
由于编译器一般来说新安排的存储这个立即数expr的缓冲的位置是在相应代码的附近(这个应该可以控制,好像是使用.ltorg伪指令)。我们从addr地址加载数据到Rn不就可以了。
(2)ldr arm 指令
就是将一个地址的内容加载到寄存器。不能用mov,因为arm里的mov只是在寄存器之间传输数据,不支持在寄出器和memory之间传递数据。因此就出现了ldr/str指令。如ldr Rn, addr,注意这里的addr的值也是有限制的。这个label应该距离当前指令的距离不超过4k。因为我们知道label在具体使用的时候应该是被翻译成了相对偏移,如果这个label长度不超过12bit,那么就不应超过4k,我们可以这样做:
ldr pc, _start_armboot
_start_armboot: .word arm_startboot
这样label _start_armboot就在指令下方,因此肯定是合法的。
ldr r0, [r1, #4] 的含义就是把r1+4 这个地址处的DOWRD 加载到r0,而寻址后,r1 的内容并不改变。
ldr r0, [r1, #4]! 这种变址方式有点类似于++i的含义,寻址前先对基地址寄存器进行运算,然后寻址. 其基本的语法是在寻址符[]后面加上一个"!" 来表示
二、.world
说说这个 .word 的作用。
word expression 就是在当前位置放一个 word 型的值,这个值就是expression
举例来说,
_rWTCON:
.word 0x15300000
就是在当前地址,即 _rWTCON 处放一个值0x15300000
不是把地址0x1530 0000 上的内容传递到r1,是把地址_rWTCON上的内容放到r1,而地址_rWTCON上的内容是0x15300000。实际上就是把r1设置为0x15300000
三 bic
BIC(位清除)指令对 Rn 中的值 和 Operand2 值的反码按位进行逻辑“与”运算。 (注意:ARM官方网站有误, 写的是补码)
BIC 是 逻辑”与非” 指令, 实现的 Bit Clear的功能
举例:
BIC R0, R0 , #0xF0000000
#将 R0 高4位清零
BIC R1, R1, #0x0F
#将R1 低4位清0
RSB 反向减法
Rn, Operand2
RSB(反向减法)指令可从 Operand2 中的值减去 Rn 中的值。
这是很有用的,因为有了该指令,Operand2 的选项范围就会更大。
例如:
RSB r4, r4, #1280
从1280中减去 R4
RSB R4, R0, #0×46
从0×46 中 减去 R0, 放入R4
四、ADR
ADR的定义为:小范围的地址读取伪指令,ADR指令将基于PC相对偏移的地址值读取到寄存器中,在编译源程序时ADR伪指令被编译器 替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,刚产生错误。
在如上的定义中,有两个关键信息:⑴将基于PC相对偏移的地址值读取到寄存器中;⑵被编译器替换成一条合适的指令。ADR指令只能将地址值读取到寄存器中,而不能是其它的立即数,并用只能用一条指令。
如果在汇编程序中使用ADR R1,ResetHandel语句,其中ResetHandel是汇编程序中的一个标签,此条伪指令的作用是把ResetHandel标签所在的指令地址 读取到寄存器R0中
根据上面的分析,可以看到,编译器在编译的时候把ADR伪指令编译成一个ADD R1,PC,Immediate指令,其中Immediate是一个立即数,数值是ResetHandel语句和此条伪指令之间的差值,由编译器自动算 出。由于立即数寻址的约束,这个Immediate存在一定的约束,所以会出现定义中所说的不能用一条指令实现。
五、ldmia 和 stmia
所有的示例指令执行前:
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}
执行后: 执行后:
r0 = 0x0010001C r0 = 0x0010001C
r1 = 0x01 r1 = 0x02
r2 = 0x02 r2 = 0x03
r3 = 0x03 r3 = 0x04
至于DA 和DB 的模式,和IA / IB 是类似的,不多说了。
最后要说的是,使用ldm 和stm指令对进行寄存器组的保护是很常见和有效的功能。配对方案:
stmia / ldmdb
stmib / ldmda
stmda / ldmib
stmdb / ldmia
继续来看两个例子:
执行前:
r0 = 0x00001000
r1 = 0x00000003
r2 = 0x00000002
r3 = 0x00000001
执行的指令:
stmib r0!, {r1-r3}
mov r1, #1 ; These regs have been modified
mov r2, #2
mov r3, #3
当前寄存器状态:
r0 = 0x0000100C
r1 = 0x00000001
r2 = 0x00000002
r3 = 0x00000003
ldmia r0!, {r1-r3}
最后的结果:
r0 = 0x00001000
r1 = 0x00000003
r2 = 0x00000002
r3 = 0x00000001
另外,我们还可以利用这个指令对完成内存块的高效copy:
loop
ldmia r9!, {r0-r7}
stmia r10!, {r0-r7}
cmp r9, r11
bne loop
ARM汇编内嵌汇 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)