寄存器和指令基本格式
寄存器
寄存器名称 | 寄存器描述 |
---|---|
R0 | 函数的第1个参数, 以及保存函数返回的结果 |
R1 - R3 | 保存函数的第2~4个参数 |
R4 – R8 | 通用寄存器,其中R7在系统调用时存储调用号 |
R9 | 平台相关 |
R10 | 通用寄存器, 可用于保存局部变量 |
R11/FP | 栈帧指针, 用于记录栈帧 |
R12 | 过程间调用, 保存函数及其调用的子函数之间的立即数 |
R13/SP | 栈指针, 指向栈顶 |
R14/LR | 链接寄存器, 用于保存子函数调用的返回地址 |
R15/PC | 程序计数器, 保存当前执行指令地址+8 |
CSPR | 当前程序状态寄存器 |
常用指令
指令 | 描述 | 指令 | 描述 |
---|---|---|---|
MOV | 移动数据 | EOR | 按位异或 |
MVN | 移动并取反 | LDR | 加载 |
ADD | 加 | STR | 存储 |
SUB | 减 | LDM | 加载多个 |
MUL | 乘 | STM | 存储多个 |
LSL | 逻辑左移 | PUSH | 入栈 |
LSR | 逻辑右移 | POP | 出栈 |
ASR | 算术右移 | B | 跳转 |
ROR | 循环右移 | BL | 跳转并将返回地址保存到LR寄存器 |
CMP | 比较 | BX | 跳转并切换Arm/Thumb模式 |
AND | 按位与 | BLX | 跳转,保存返回地址,并切换ARM/Thubmb模式 |
ORR | 按位或 | SWI/WVC | 系统调用 |
总体设计和指令规格
- 没有隐式内存操作指令
- 0-3个操作数,内存操作数和立即数不能同时存在,内存操作数至多出现1次,寄存器操作数总在最前
特殊情况:
- C标志位使用
- 读PC寄存器
断点
在 IDA 调试中,无论是断点还是单步调试都是依靠 #UND 0x10
触发断点实现,且 IDA 调试器 无法分辨出改指令是否是自己设置的,在读取数据时会按实际情况返回数据。
该指令在 Arm 模式和 Thumb 模式的硬编码不同:
- Arm 模式断点:
F0 01 F0 E7
- Thumb 模式断点:
10 DE
PC寄存器相关指令
MOV PC, R0
:相当于PC = R0
MOV R0, PC
- 在 Arm 模式中相当于
R0 = PC + 8
- 在 Thumb 模式中相当于
R0 = PC +4
- 在 Arm 模式中相当于
LDR R0, [PC,#x]
可以看做 3 步:- 读 PC 寄存器的值,规则与
MOV R0, PC
相同,即根据处于 Arm 或 Thumb 模式加上相应的偏移 - 将读出的值再加上偏移 x 作为地址,然后将地址向下取整做 4 字节对齐
- 从计算出的地址的值读入到 R0 寄存器中
- 读 PC 寄存器的值,规则与
条件和标志位响应
CPSR 寄存器
CPSR 寄存器结构如下图所示:
各标志位含义:
N,bit[31]
若运算结果为 0 或正数则该该标志位置 0,若运算结果为负数则该标志位置 1 。Z,bit[30]
运算结果为 0 则置 1,否则置 0 。C,bit[29]
无符号数溢出,加法溢出置 1,减法溢出置 0。V,bit[28]
有符号数溢出T
T = 0
表示 Arm 模式T = 1
表示 Thumb 模式。
注意:指令是否影响标志位取决于是否是否加 S 后缀(大多数情况,具体看指令硬编码第 20 位是否置 1),比如 MOV
不影响标志位但 MOVS
影响标志位。
执行条件
cond 标志的值及其对应含义如下表所示:
cond 标志位位于指令硬编码的高 4 比特,在执行时根据标志寄存器决定该指令是否执行。
MOV 指令
MOV 不访问内存,因此操作数只能是寄存器或立即数。
MOV 立即数
由于 ARM 汇编指令长度的影响,对立即数范围有严格的限制。允许 MOV 的立即数有如下几类:
- 立即数不超过 16 位
该指令在给寄存器低 16 比特赋值的同时会将寄存器高 16 比特清零。 - 立即数可以用 不超过8 比特的数循环右移不超过 32 的偶数得到
其中 imm12 中的低 8 比特是需要循环右移的数,高 4 比特乘 2 是需要循环右移的次数。 - (MOVT)立即数不超过 16 位且需要移动到寄存器高 16 位(通常与 MOV 配合使且应当先 MOV 后 MOVT)
该指令在给寄存器高 16 比特赋值的同时不会将寄存器低 16 比特清零。
MOV 寄存器, 寄存器
- 寄存器 + 立即数移位
例如MOV R0, R1,LSL#4
,该指令等同于LSL R0, R1,#4
。
移位类型由 stype 决定,移位的值为 imm5 。 - 寄存器 + 寄存器移位
例如MOV R0, R1,LSR R2
,该指令等同于LSR R0, R1,R2
。
基本整型运算
相关指令
ADD
:加ADR
:PC 与操作数相加结果放入结果寄存器中ADRL
:伪指令,与ADR
相似,不过通过类似MOV + MOVT
的方式使得寻址范围更大CMN
:加,只影响标志寄存器
SUB
:减CMP
:减,只影响标志寄存器
RSB
:反减AND
:与TST
:与,只影响标志寄存器
BIC
:第二个操作数与第三个操作数的反码逻辑与结果放在第一个寄存器中ORR
:或EOR
:异或TEQ
:异或,只影响标志寄存器
LSL
:逻辑左移LSR
:逻辑右移ASR
:算术右移
ADD 指令(举例)
- ADD 立即数
这里 12 比特长的立即数与前面 MOV 的机制一样,采用移位的方式将其扩展为 32 位范围。 - ADD 寄存器,立即数移位
与 MOV 机制相同,例如ADD R0, R1, R2,LSL #4
。 - ADD 寄存器,寄存器移位
- ADR
本质还是 ADD,不过被加数为 PC 寄存器。由于设计到读 PC 寄存器,因此根据当前所处的模式,读出来的 PC 寄存器的值会加上相应的偏移。
访存指令
数据流向
- LDR:
内存 -> 寄存器
- STR:
寄存器 -> 内存
操作的寄存器和内存地址
- 寄存器:
LDR R0, [R1]
- 寄存器 + 偏移(立即数):
LDR R0, [R1,#4]
- 12 位立即数即偏移,不存在移位扩展。
- U 为立即数的正负号。
- P = 0 则外偏移,W = 1 则内偏移,内外偏移不能同时存在。
- 寄存器 + 移位偏移(寄存器):
-
LDR R0, [R1,R2,LSL #4]
-
LDR R0, [R1,R2,LSL R3]
-
后续的附加行为
- 内偏移:
LDR R0, [R1,#4]!
该指令表示将[R1+4]
赋值给 R0 ,然后将 R1 的值设为R1 + 4
。 - 外偏移:
LDR R0, [R1],#4
该指令表示将[R1]
赋值给 R0 ,然后将 R1 的值设为R1 + 4
。
注意:外偏移和内偏移不能同时存在。
根据附加附加行为性质可知:
PUSH R0
相当于STR R0, [SP,#-4]!
POP R0
相当于LDR R0, [SP],#4
块访存指令
指令结构
LDM\STM+后缀 寄存器(!), {寄存器组}
- LDM 表示将寄存器指向的地址的数据依次存放在寄存器组中。
- STM 表示将寄存器组中的数据依次存放在寄存器指向的地址。
- 寄存器组可以写作范围,比如
{R0-R4}
;也可指定具体寄存器,比如{R0,R2,R3}
。但是读写操作是按照寄存器下标的顺序依次操作寄存器组中的寄存器(编号小的在低地址),因为指令对应硬编码无法体现出寄存器组的顺序。
以 LDM 为例:
后缀类型
- I 表示地址加;D 表示地址减。
- A 表示先读写内存,再改变指向;B 表示先改变指向,再读写内存。
- 带 ! 表示修改的指向写入寄存器;不带 ! 表示修改的指向不写入寄存器。
- 如果操作地址寄存器为 SP 时LDMFD 相当于 LDMIA ;STMFD 相当于 STMDB 。
根据不同后缀类型的性质可以确定如下用法:
- STMFD 相当于 PUSH
- LDMFD 相当于 POP
- STM\LDMIA 可以快速复制内存
分支和模式切换
B + imm
- 跳转目标:立即数
- 模式切换:不带模式切换
- 写入 LR 的值:不影响 LR 寄存器
指令编码的立即数为目标地址与 PC 寄存器的差值除 4 。由于涉及读 PC 寄存器,因此根据当前模式要加上相应的偏移。跳转范围为 PC 值加上正负 32M 的偏移。
BL + imm
- 跳转目标:立即数
- 模式切换:不带模式切换
- 写入 LR 的值:
下一条指令的地址 | T 标志位
BX + reg
- 跳转目标:寄存器中的值去掉最低一位
- 模式切换:跳转时将寄存器中存储的地址的最低一位写入 T 标志位
- 写入 LR 的值:不影响 LR 寄存器。
BLX + imm
- 跳转目标:立即数
- 模式切换:一定切换模式
- 写入 LR 的值:
下一条指令的地址 | T 标志位
BLX + reg
- 跳转目标:寄存器中的值去掉最低一位
- 模式切换:跳转时将寄存器中存储的地址的最低一位写入 T 标志位
- 写入 LR 的值:
下一条指令的地址 | T 标志位
拓展
BX reg
和MOV PC, reg
的区别:BX 可以切换模式,MOV 不能切换模式。LDR PC, [R0]
:可以做模式切换,常用于 PLT 表中调用 GOT 表中对应的函数地址(最低位表示模式)。LDMFD SP!, {R11,PC}
:同样可以做模式切换,常与STMFD SP!, {R11,PC}
一起用于函数调用时保存栈帧和返回地址。
Thumb 模式
特点
- 段指令一般不使用 R8-R12
- 一般没有条件码和标志响应位,指令默认影响标志位
- 运算指令优先对第一,第二操作数相同情况有短指令编码。对于 STMFD 和 LDMFD,如果以 SP 寄存器的值作为地址则简写为 PUSH 和 POP 。
IT 块
结构如下图:
IT 指令的 mask 编码为从高到低,T 为 0,E 为 1 ,最后填一个 1 表示结束。比如 ITTEE EQ
的 mask 的二进制形式为 0111
。
调用约定
- 前 4 个参数:R0-R3,其它参数栈传递
- 非异变寄存器:R4-R11,使用此类寄存器的函数负责恢复寄存器原来的值。
- R11:栈帧指针,类似 EBP。
- R12:导入表寻址