目标:这是一篇Arm汇编学习笔记,也相当于一份guide,提供了快速了解Arm汇编的“接口”
一、寄存器
二、指令集
三、过程调用规范
通用寄存器(32-bit)
别名/过程调用规范中作用
R0-R3
参数传递/结果返回(调用者保存)
R4-R8
(被调用者保存)
R9
平台寄存器(可变用途)
R10
(被调用者保存)
R11
FP,栈帧指针寄存器,记录当前栈帧基址
(被调用者保存)
R12
IP,内部过程调用临时寄存器
R13
SP,栈指针,指向栈顶,任何函数的出入口处,需满足8字节对齐,即SP mod 8 = 0,即SP mod 0x08 = 0
R14
LR,链接寄存器,保存函数返回地址
R15
PC,程序计数器
其他寄存器
CPSR
当前程序状态寄存器,重点位:N(负数)、Z(零)、C(进位)、V(溢出)、T(处理器指令集,如thumb、arm)

总结:
1、15个通用32位寄存器
2、R4-R11,被调用者保存。即,子函数被调用时,需保存这些寄存器的值,在返回父函数时,恢复这些寄存器的值。R9比较特殊,保留平台相关的配置,有时候有用有时候不用,可直接按被调用者保存处理。
3、R11,FP栈帧指针。一般指向调用函数的FP,形成调用链,可用于栈回溯。实际使用中最常用是用来寻址栈中的数据,因为SP会频繁改变,但FP不会
4、R12,IP寄存器,常用来寻址外部导入函数。比如调用printf,会用来计算printf的地址。
5、LR,不是非易变寄存器,被调用者可以改变,而不恢复,只需要在返回调用者的时候,将LR POP到PC就行。所以可以把LR保存到堆栈,最后从堆栈 POP 到PC
6、CPSR,T标志位控制处理器指令集,如T32(thumb模式)或者A32(arm模式)。A32为定长4字节指令,T32为2字节或4字节指令。NZCV条件标志位
其他(不多BB了解不多):
系统寄存器
浮点寄存器(SX为32个单精度(32-bit)寄存器,DX为16个双精度(64-bit)寄存器),S0-S15参数传递/调用者保存,S16-S31被调用者保存。D0-D7双精度参数传递,D8-D15双精度,被调用者保存。
常用指令:
数据处理
基本运算
ADD(ADR、ADRL),SUB、RSB
逻辑运算
AND(TST)、BIC、ORR、EOR(TEQ)
位操作
LSL、LSR、ASR、ROR
标志位设置
CMN、CMP
内存操作
访存
LDR、STR
块访存
LDMFD、LDMIA、STMFD、STMIA、STMDB、PUSH、POP
分支与跳转
B、BL、BX、BLX;CBZ、CBNZ、TBB、TBH
系统与协处理器指令
系统调用
SVC(触发软中断)、HVC(虚拟化调用)
协处理器操作
MCR/MRC访问协处理器
条件码:

1、A32(arm模式)和T32(thumb模式),A32定长4字节指令,T32为2字节指令与4字节指令混合。
2、数据处理指令,同样的运算方式,一般会有三种指令变体。如下面三条指令,执行的都是加法运算:
ADD(只存放结果,不影响标志位)
ADDS(既存放结果,又影响标志位)
CMN(只影响标志位,不存放结果)
同理,还有SUB、SUBS、CMP;AND、TST;EOR(TEQ)
3、由于A32指令定长4字节,所以无法容纳32位立即数,一般会使用立即数扩展。
MOV指令立即数扩展:A32ExpandImm,imm12,将12位立即数扩展为32位,运算过程是后8位循环右移前4位的值*2
或者使用
可得到:R0 = 0x12345678
4、ADR、ADRL
ADR一般用于寻址计算,实现PC偏移寻址。
如下图main函数调用libc中printf函数。


(off_1654 - 0x1508)可看作printf存储地址与PC之间的偏移offset,ADR指令将PC加上,得到printf的地址。加载前后,offset是不变的,PC加载前0x508加载后变为实际运行时候的指令地址0xB6FF8508,使得通过PC寻址的printf的地址发生改变为0xB6FF9654,如此寻到的printf地址才是正确的地址。

R12之前说过,常用来寻址外部导入函数。如printf函数的调用,由于arm和thumb的BL指令无法寻址完整的32位地址空间,如无法BL 0x12345678,此处则通过ADR、LDR指令来计算地址并加载到PC实现跳转。这段代码通常称为veneer,特点是,一般不改变除r12寄存器和状态寄存器之外的寄存器。
5、其他
RSB R0,R1,#8 => R0=8-R1
BIC R0,R1,#8 => 清除R1的第3位,结果存入R0
6、访存:
将偏移量与从基址寄存器获取的地址相加,结果作为内存访问的地址,并回写到基址寄存器R1。
从基址寄存器获取的地址,不做任何修改,作为内存访问的地址。将偏移量与该地址相加,然后回写到基址寄存器R1。
注意:Arm是满减栈。如下图假如是一个栈帧结构。
“满”意味着SP指针总指向栈顶最后一个元素,图中是0x222,SP的值即位0x00000ff8。
“减“意味着栈的生长方向是向内存地址减小的方向。当放入一个元素,会往低地址放。如STR R0,[SP,#-4]!,则会将R0的值存入SP-4的位置即0x0000ff4处,然后将SP-4写回SP。

7、块访存:
LDMFD、STMFD、LDMIA、STMIA
IA
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!