本文记录学习ARM汇编时遇到的问题及其解释,如有错误,乞望指正!
汇编语句LDR r0, =(0xF << 20)中的“=”是什么意思?
先说结论:源操作数前有“=”说明本条汇编语句中的汇编指令是伪指令
LDR:大范围的地址读取伪指令。
LDR伪指令将一个32位的常数或者一个地址读取到寄存器中。
语法格式:
LDR {cond} register, =[expr | label-expr]
cond:可选的指令执行的条件;
register:目标寄存器;
expr:为32位的常量。编译器将根据expr的取值情况,处理LDR伪指令。
当expr表示的地址值没有超过MOV或MVN指令中地址的取值范围时,编译器用合适的MOV或者MVN指令替代该LDR伪指令。
例如:LDR R1, =0XFF0,将0xff0读取到R1中
汇编后得到MOV R1, 0XFF0
当expr表示的地址值超过了MOV或MVN指令中地址的取值范围时,编译器将该常数凡在数据缓冲区中,同时用一条基于PC的LDR指令读取该常数。
例如:LDR R1, =0xFFF,将0xfff读取到R1中。
汇编后得到:
LDR R1, [PC,OFFSET_TO_LPOOL]
...
LPOOL DCD 0XFFF
label-expr:为基于PC的地址表达式或者是外部表达式。当label-expr为基于PC的地址表达式时,编译器将label-expr表示的数值放在数据缓冲区中,同时用一条基于PC的LDR指令读取该数值。当label-expr为外部表达式,或者非当前段的表达式时,汇编编译器将在目标文件中插入连接重定位伪操作,这样链接器将在连接时生成该地址。
例如:LDR R1, =ADDR1,将外部地址ADDR1读取到R1中。
汇编后将得到:
LDR R1, [PC, OFFSET_TO_LPOOL]
...
LPOOL DCD ADDR1
LDR伪指令主要有一下两种用途:
①当需要读取到寄存器中的数据超过了MOV及MVN指令可以操作的范围时,可以使用LDR伪指令将改数据读取到寄存器中。
②将一个基于PC的地址值或者外部的地址值读取到寄存器中。由于这种地址值是在连接时确定的,所以这种代码不是位置无关的。同时,LDR伪指令处的PC值到数据缓冲区中的目标数据所在的地址的偏移量要小于4KB。
ARM中伪指令不是真正的ARM指令或者Thumb指令,这些伪指令在汇编编译器对源程序进行汇编处理时被替换成对应的ARM或者Thumb指令(序列)。
ARM NEON 是适用于ARM Cortex-A和Cortex-R52系列处理器的一种128位SIMD(single instruction multiple data, 单指令多数据)扩展结构。
关于满堆栈和空堆栈
满堆栈(full stack,“F”)是指堆栈指针指向堆栈的最后一个已使用的地址或者满位置(也就是sp指向堆栈最后一个数据项位置)。
空堆栈(empty stack,“E”)是指sp指向堆栈的第一个没有使用的地址或者空位置(也就是说sp指向堆栈最后一个数据项的下一个位置)。
如下图:
指令上加上后缀FA、FD、EA、ED(F-满位置,E-空位置,A-递增,D-递减)来表示sp指针的寻址方式。
CPSID(关) CPSIE(开) 用于快速的开关中断。
ARM汇编中的^:
'^'是一个后缀标志,不能在User模式和Sys系统模式下使用该标志.该标志有两个存在目的:
①对于LDM操作,同时恢复的寄存器中含有pc(r15)寄存器,那么指令执行的同时cpu自动将spsr拷贝到cpsr中。
②数据的送入、送出发生在User用户模式下的寄存器,而非当前模式寄存器。
内嵌汇编的通用形式:
asm (
代码
: 输出操作数列表
: 输入操作数列表
: 破坏列表
);
破坏列表:
一般就是一个“memory",或者寄存器列表。如果在汇编代码中修改了内存中的值,我们就需要在破坏列表中加上"memory"字段,告诉编译器,我们修改了内存中的值。如果在汇编代码中修改了某些寄存器,那么我们就需要把在代码中所修改过的寄存器列在破坏列表中。
例:
STATIC INLINE INT32 LOS_AtomicAdd(Atomic *v, INT32 addVal)
{
INT32 val;
UINT32 status;
do {
__asm__ __volatile__("ldrex %1, [%2]\n"
"add %1, %1, %3\n"
"strex %0, %1, [%2]"
: "=&r"(status), "=&r"(val)
: "r"(v), "r"(addVal)
: "cc");
} while (__builtin_expect(status != 0, 0));
return val;
}
status和val是输出操作数,Atomic *v和INT32 addVal是输入操作数。
其中%0、%1、%2、%3分别代表status、val、v、addVal。
“cc”:表示内嵌汇编代码影响状态寄存器相关的标志位;
LDM指令的"!“和”^"
LDMFD SP, {R13, R14}^
LDMFD SP!, {R0-R3, R12, LR}
“^”后缀不允许在用户模式呈系统模式下使用,若在 LDM 指令用寄存器列表中包含有 PC 时使用,那么除了正
常的多寄存器传送外,将 SPSR 拷贝到 CPSR 中,这可用于异常处理返回;使用“^”后缀进行数据传送且寄存器列表不包含 PC 时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存器。
后缀“!”表示最后的地址写回到Rn中。