ARM指令重难点小记
一、LDR伪指令与ADR伪指令详解
a) ADR的定义为:小范围的地址读取伪指令(地址无关代码),ADR指令将基于PC相对偏移的地址值读取到寄存器中,在编译源程序时ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现(当偏移量不能满足立即数规则时),则产生错误。
b) LDR的定义为:大范围的地址读取伪指令(地址相关代码),LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或者MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。(优先使用MOV或MVN指令代替该指令。)
c) 与加载指令LDR相比,伪指令LDR的参数有”=”号
COUNT EQU 0x30008000
LDR R1, =COUNT ;伪指令,将COUNT(0x30008000)作为地址赋给R1
LDR R2, =0x30000000 ;伪指令,将立即数(0x30000000)作为地址赋给R2
LDR R0, [R1] ;加载指令,将[R1]加载到R0中
LDR R0,COUNT ;加载指令,将COUNT中的值(0x30008000单元中的值)加载到R0中
d) 当不能用MOV指令传送立即数时(不满足立即数规则),这个时候LDR伪指令就派上用场了,它可以处理任何32位的常量。
二、关于包含于ARM指令中的立即数规则
a) 对ARM指令中的立即数有这样的规定:“该常数必须对应8位位图,即常数是由一个8位的常数循环移位偶数位得到的”。
b) 32位指令中用了其中的12bit(0-11位)来表示立即数,其中4bit表示移位的位数(循环右移,且数值x2),8bit用来表示要移位的一个基数。
c) 立即数满足的条件:首先基数必须少于等于8位,然后是循环位移数必须是偶数。
d) 为什么这么做:一方面是无奈之举(只有12位);另一方面是可以表示的数更广泛,实际可用性比直接用12位好。
三、C与汇编的混合编程:
a) 在C程序中嵌入汇编指令(使用关键字__asm来标识一段汇编指令程序)
__asm
{
……汇编语言程序……
}
注意事项:(内嵌汇编一般是为了提高程序执行效率)
(1)内嵌汇编中不能直接向PC寄存器赋值
(2)通常,内嵌汇编中不要指定物理寄存器
(3)内嵌汇编中,常量前面的”#”可以省略
(4)C程序中的标号可以被内嵌汇编指令使用,但是BL不能使用C的标号
(指令B则可以)
b) 在C程序中调用汇编函数
i.首先在汇编中用EXPORT导出函数名(Lable),在末尾用mov pc, lr返回;
ii.然后在C中声明函数原型,并加extern关键字;
参数传递应该注意3点:
(1)小于4个参数,用R0~R3
(2)大于4个参数,用压栈的方式传递
(3)函数的返回值用R0寄存器
c) 在汇编程序中访问C定义的全局变量
IMPORT global
ldr r0, =global
ldr r1, [r0]
d) 在汇编程序中调用C函数
导入:IMPORT cFun
传参:给R0~R3赋值
调用:bl cFun