这里所介绍的指令集架构均属于 RISC,相比 CISC 更简单。但是 ARM 比较特殊,因为它作为一个 RISC 架构竟然有 push/pop 指令……
ARMv7
ARM 指令集从旧到新有 ARMv6、ARMv7、ARMv7s、ARMv8,使用新指令集的芯片也能支持旧的指令集,但是无法发挥出较好的性能。同时要注意,指令集版本不同的静态库是不能一起使用的。
ARM 有两种工作状态,ARM 状态的指令长度是 32 位的,Thumb 状态的指令长度是 16 位的(从 ARMv6-T2 开始引入的 Thumb-2 指令集也支持 32 位的指令,具有 .w 后缀)
使用 Thumb 指令集可以得到较小的二进制文件,但是可以访问的寄存器更少,产生的指令数量更多,性能会有损失。
寄存器
Register...
r0函数返回值或函数参数
r1~r3函数参数,更多参数使用栈传递
r4~r10临时变量
r11函数栈帧 FP(类似于 EBP 寄存器)
r12内部过程调用寄存器 IP
r13栈指针 SP
r14链接寄存器 LR,用于存储将要跳转到的地址
r15程序计数器 PC
Cortex-M 含有两个栈指针寄存器(SP),分别为 PSP(Process SP)和 MSP(Main SP)。
ARM 指令
指令结构为 MNEMONIC{S}{cond} {Rd}, Operand1, Operand2
如果指令后加了 S,将依据计算结果更新当前程序状态寄存器 CPSR 中相应的标志。
cond 表示执行条件,见下表。
扩展助记符意义(整形)意义(浮点)条件
EQ相等相等Z==1
NE不相等不相等或无序(即至少有一个 NaN)Z==0
CS/HS进位置位/无符号高于等于大于等于或无序C==1
CC/LO进位复位/无符号低于小于C==0
MI减法、负数小于N==1
PL加法、非负数大于等于,或无序N==0
VS溢出置位无序V==1
VC溢出复位不无序V==0
HI无符号高于大于或无序C==1 且 Z==0
LS无符号不高于小于或相等C==0 或 Z==1
GE有符号大于等于大于等于N==V
LT有符号小于小于或无序N!=V
GT有符号大于大于Z==0 且 N==V
LE有符号小于等于小于等于或无序Z==1 或 N!=V
AL(default)无条件无条件
第三个操作数可以是寄存器,也可以是要进行的移位操作。可能的操作有 LSL/LSR/ASR/ROR/RRX,其中 RRX 表示右移一位,最高位由 APSR 寄存器的状态位 C 填充,移出的位给状态位 C。
Mnemonic...
mov复制寄存器。例如 MOV R0,R2,LSL #3 表示把 R2 左移 3 位后传给 R0。
lsl/lsr/asr/ror逻辑左移,逻辑右移,算数右移,循环右移
push把立即数、单个寄存器,多个寄存器压栈。多个寄存器按从右到左压栈
pop出栈到单个寄存器或多个寄存器(从左到右的顺序)
ldr/strldr 从内存中读 32 位数据,str 写 32 位数据到内存。如 ldr r1, [r2, #0x10] 即 r1 = *(r2+0x10);str r1, [r2, #0x01] 即 *(r2+1)=r1。相应地,读写 16 位时 ldrh/strh;8 位时 ldrb/strb。例如 ldrneh 即不相等时读半字。
swp交换值,可用于实现信号量
b/blb 跳转,bl 跳转并把下一条指令地址存储到 lr
bx/blx Rm跳转并切换状态。由于指令是 2 或 4 字节对齐的,地址的最低位一定是 0,故若 Rm & 0x01==1 则令 CPSR.T=1,把目标地址解释为 Thumb 代码;否则令 CPSR.T=0,目标地址解释为 ARM 代码
add/sub加减法,更新标志位
sbc带借位减法,Rd = ~Ra + Rb + CPSR.C
cmp比较两个寄存器或一个立即数(使用减法)并更新标志位
tst/teq测试相等
mul/mla/umullmul 乘法,mla 乘加,即 Ra*Rb+Rc,umull 64 位乘法
svc/swi系统调用
and/orr/eor按位与,按位或,按位异或
几个 SIMD 指令:
Mnemonic...
ldmib/stmib/ldmdb/stmdbb 表示存储器指针在保存/读取第一个值之前更新;i 表示更新方式为增加,d 表示更新方式为减少
ldmfa/stmfa/ldmfd/stmfd存储器指针为 SP 时,就等价于该指令。f 表示堆栈指针指向内含有效数据项的最高地址;a 表示堆栈往高地址增长,d 表示堆栈往低地址增长
ldmea/stmea/ldmed/stmede 表示堆栈指针指向堆栈的第一个空位置 ;a 表示堆栈往高地址增长,d 表示堆栈往低地址增长。
协处理器指令格式:
MRC/MCR {cond} coproc,opcode1,Rd,CRn,CRm{,opcode2}
MCR:从寄存器到协处理器
MRC:从协处理器到寄存器
coproc:协处理器名称,p0~p15
MSR:从寄存器到状态寄存器,如 MSR CPSR,R0
MRS:从状态寄存器到寄存器,如 MRS R2,SPSR
中断
Cortex-A 处理器发生中断时,先跳转进 IRQ 入口,再通过软件判断是由哪个中断源触发,获得相对应的中断服务程序(ISR)的地址。而 Cortex-M 处理器发生中断时,CPU 自动从中断向量表中寻找相应的中断服务程序并跳转。
链接寄存器(LR)的数值会被更新为 EXC_RETURN 值(详细含义可自行搜索)。然后硬件自动将 r0, r1, r2, r3, r12, lr, pc, psr 寄存器依次入栈,同时更新 psp 寄存器。中断处理函数结束时,通过 bx lr 指令触发中断返回,处理器将自动保存的寄存器值从栈上弹出并恢复给相应的寄存器。
svc 指令用于系统调用,如 svc #0x900004 调用 sys_write
另一种方法是把编号传给 r7(如 4 为 sys_write),再使用 swi 0 进行调用。
MIPS32
寄存器
Register NumberName...
0zero它总是返回零,对其写入也没有效果
1at汇编器临时寄存器,用于加载 16 位以上的大常数使用
2-3v0,v1函数返回值,对于 64 位的返回值,两个寄存器都要用到
4-7a0-a3函数调用参数,更多参数使用栈传递
8-15t0-t7无需保存的临时变量
16-23s0-s7需要在当前函数返回之前,恢复其本来值的临时变量
24,25t8-t9无需保存的临时变量
26k0发生中断时,在中断处理过程中用作临时变量
27k1用于中断嵌套的深度计数器。也可作为临时变量
28gp一个全局指针,可以用于访问一些全局变量。没有特