ARM寻址方式
2.1 立即数寻址
MOV R0, #0X3F ;R0 <-- R0 + 1
书写规则:
- 以
#
为前缀。 - 十六进制数,
#
后加0X
或&
,如#0X3f
,#&3f
。 - 二进制数,
#
后加0B
, 如#0B1011
。 - 十进制数,
#
后加0D
或缺省,如#0D678
,#789
。
Question1:32位长度指令中最多包含几位立即数?最大为多少?
由前面的知识可以知道立即数在32位ARM指令的编码格式为0~11!立即数的范围为 [0,212−1]。
Question2:如何构造32位的立即数?
对于一条汇编指令
MOV R0, #0X0000F200
其机器代码为:E3A00CF2
E
:无条件
3A
:MOV
00
:目的寄存器,代表R0寄存器
CF2
:第二操作数,其中C
为4位循环右移值,F2
为8位常数。
即将0X3F循环右移12×2+8=32位。
2.2 寄存器寻址
ADD R0, R0, #1 ;R0 <-- R0 + 1
寄存器移位操作
- LSL(Logical Shift Left):逻辑左移操作,空出的最低有效位用0填充。
Ex:000001逻辑左移4位→010000即将1×16=16。
- LSR(Logical Shift Right):逻辑右移操作,空出的最低有效位用0填充。
Ex:010000逻辑右移4位→000001即将16/16=1。
- ASL(Arithmetic Shift Left):算术左移操作,同逻辑左移。
- ASR(Arithmetic Shift Right):算术右移操作,算术移位的对象是带符号数,移位过程中必须保持操作数的符号不变。如果源操作数是正数,空出的最高有效位用0填充,如果是负数用1填充。
Ex:1000010算术右移4位→1000000
- ROR(Rotate Right):循环右移,移出的字的最低有效位依次填入空出的最高有效位。
Ex:10100110循环右移4位→01101010
- RRX(Rotate Right Extended):带扩展的循环右移,将寄存器的内容循环右移1位,空位用原来C标志位填充。
Ex:10100110带扩展循环右移,设CPSR中C标志位为0,则→11001010
2.3 寄存器间接寻址(比较像c++中的指针)
ADD R0, R1, [R2] ;R0 <-- R1 + [R2]
以寄存器R2的值作为操作数的地址,在存储器中取的一个操作数后与R1相加,结果存入R0中
写成c++代码的指针模式如下所示:
#include <iostream>
using namespace std;
int main()
{
int a = 10; /*MOV R1, 10*/
int b = 20; /*MOV R2, 20*/
int c = a + *(&b); /*ADD R0, R1, [R2]*/
cout << c << endl;
return 0;
}
输出结果:30!
2.4 基址加变址寻址
2.4.1 前变址
LDR R0, [R1, #8] ;R0 <-- [R1 + 8]
2.4.2 自动变址
LDR R0, [R1, #8]! ;R1 <-- [R1 + 8], R1 <-- R1 + 8
2.4.3 后变址
LDR R0, [R1], #8 ;R0 <-- [R1], R1 <-- R1 + 8
2.4.4 寄存器偏移地址
LDR R0, [R1 + R2] ;R0 <-- [R1 + R2]
写成c++代码的指针模式如下所示:
#include <iostream>
using namespace std;
int main()
{
int a = 10; /*MOV R1, 10*/
int b = 20; /*MOV R2, 20*/
int c;
c = *(&a); /*LDR R0, [R1]*/
cout << c << endl;
c = *(&a + 8); /*LDR R0,[R1, #8]*/
cout << c << endl;
return 0;
}
输出结果:
10
0
2.5 多寄存器寻址
含义:一条指令完成多字段数据或数据块的传送
基本指令:LDM/STM
基址寄存器变化方式:
- IA(Increment After Operating):操作完再增加地址值。
- IB(Increment Before Operating):先增加地址后操作。
- DA(Decrement After Operating):先操作再减地址值。
- DB(Decrement Before Operating):先减地址值后操作。
语法表示:
多寄存器用”{}”包含,连续寄存器用”-“间隔,否则用”,”分隔。
Ex:
LDMIA R0, {R1-R4, R6} ;R1 = [R0], R2 = [R0 + 4], ... , R4 = [R0 + 12], R6 = [R0 + 16]
LDMIA R0, {R1-R4, R6}! ;R1 = [R0], R2 = [R0 + 4], ... , R4 = [R0 + 12], R6 = [R0 + 16], R1 <-- R1 + 16
2.6 堆栈寻址
含义:按先进后出FILO的方式工作,使用一个专门的寄存器(堆栈指针SP)指向一块存储区域(堆栈)来指示当前的操作位置,堆栈总是指向栈顶的。
基本指令:LDM/STM
堆栈的生长方式:
- FD(Full Descending):满递减堆栈,堆栈指针指向最后压入堆栈的有效数据项,堆栈由高地址向低地址生成。
-
ED(Empty Descending):空递减堆栈,堆栈指针指向下一个待压入数据的空位置,称为空堆栈。堆栈由高地址向低地址生成。
-
FA(Full Ascending):满递增堆栈,堆栈指针指向最后压入堆栈的有效数据项,堆栈由低地址向高地址生成。
- EA(Empty Ascending):空递增堆栈,堆栈指针指向下一个待压入数据的空位置,堆栈由低地址向高地址生成。
ARM指令集的出栈和入栈操作:
STMFD SP!, {R0, R1, R3-R5} ;R0, R1, R3-R5入栈
LDMFD SP!, {R0, R1, R3-R5} ;R0, R1, R3-R5出栈