汇编语言学习笔记(一)ARM指令集
前言
杂事太多,浪费我10多天的时间。ARM指令集,我感觉还是“复杂”了;功能虽全,但记忆量也多。其实,编写OS所用到的只是100多条ARM指令集中的约30多条吧。以下是对ARM指令集的第一次简单整理,有错难免、仅供参考。
有多种指令集架构(Instruction Set Architecture),如RISC类(RISC-V、OpenRISC、ARM( Advanced RISC Machines) 、MIPS、等等精简指令集架构)、Intel x86 体系(可变指令长度的CISC(复杂指令集计架构,Complex Instruction Set Architecture))。一个机器内也可以支持多种指令集架构,如ARM的A(Application profile)系列CPU(基于MMU(内存管理单元)支持VMSA(虚拟内存系统架构))内就可以支持A64/A32/T32三种指令集架构。AArch64 state(状态)支持A64指令集,这是一个固定长度32位指令编码的指令集;AArch32 state支持:A32、一个固定长度的32位指令编码的指令集,与ARMv7 ARM指令集兼容;T32、是一个可变长度使用16位和32位指令编码的指令集,与ARMv7 Thumb®指令集兼容。16位指令编码空间有64K条机器指令码,32位指令编码空间可以有4G条机器指令码。汇编语言是为了方便人们记忆和使用各种指令集的语言,一条汇编语言指令语句通常是表述一束指令码(包含多条类同功能的机器指令码),如MOVT Rd, #imm16; 16位立即数送到目标32位寄存器Rd的高16位、就代表了一束指令(14*64K条机器指令码)。将汇编语句翻译成机器可以认知的机器指令码的软件就是汇编语言编译器。通常有五类指令:控制指令,转移指令,数据处理指令,存储器访问指令,向量操作类指令(可伸缩向量SVE指令集,SIMD向量(Single-Instruction、Multiple-Data)和标量floating-point(浮点),基本的数字信号处理DSP(digital signal processing)指令)(另文讨论)。
ARM汇编指令的基本格式:
<Opcode>{<Cond>}{<q>}{<S>}{<Rd>},<Rn>{,<Operand2>};
• 其中尖括号是必须的,花括号是可选的。
• A32: Rd => {R0–R14} ,注:也有许多指令的Rd可以是R15 = PC。
• A64: Rd =>Xt => {X0–X30}
注意:如比较、测试等指令是没有目标寄存器的。通常的实际写法有3种:
Opcode {Cond}{S} Rd, Operand2;
Opcode {Cond}{S} Rn, Operand2;
Opcode {Cond}{S} Rd, Rn, Operand2;
Opcode:操作码助记符,说明指令需要执行的操作类型,如ADD等。
Cond:指令执行条件码,通常是条件跳转和少数数据处理这类指令才有条件执行;A32有更多的条件指令,但实现复杂,并没有明显好处。Cortex‐M3中,只有转移指令(B 指令)才可随意使用条件后缀。而对于其它指令,CM3 引入了 IF‐THEN 指令块,在这个块中才可以加后缀,且必须加以后缀。另外,S 后缀可以和条件后缀在一起使用。共有 15 种不同的条件后缀。
q:“.W(Wide)”后缀指定 32 位指令。如果没有给出后缀,汇编器会先试着用 16 位指令以缩小代码体积,如果不行再使用 32 位指令。因此,使用“.N”(N=Narrow)其实是多此一举,或说{
}项后缀多余。
S:条件码设置项,决定本次指令执行是否影响PSTATE寄存器相应状态位值,如ADDS R0,R1 ; 根据加法的结果更新 APSR 中的标志。
Rd/Xt:目标寄存器,A32指令可以选择R0-R14;T32的16位指令大部分只能选择RO-R7,32 位指令则无限制,A64指令可以选择X0-X30。
Rn/Xn:第一个操作数的寄存器,和Rd一样,不同指令有不同要求。
Operand2:灵活的第二个操作数,可以是立即数(常量constant),寄存器Rm和寄存器移位方式(Rm, shift)。(shift应用于Rm的可选移位ASR #sh(允许移动1–32位)、LSR #sh(允许移动1–32位)、LSL #sh(允许移动0–31位)、ROR #sh(允许移动1–32位)、RRX(向右循环移动一位,带扩展);type Rs仅在ARM中使用,type:是ASR、LSR、LSL或ROR,Rs提供移位量的ARM寄存器、只使用最低有效字节。)
Operand2 = <Rm> | <#immediate> | <Rm, ASR|LSR|LSL|ROR Rs|#sh> | <Rm, RRX>,为四项中的一项。
ARM汇编指令格式:
**Opcode{
Cond}{
S} {
Rd,} Rn{
, Operand2};**
一、数据处理指令类型
算术逻辑单元ALU(Arithmetic Logical Unit),应用程序状态寄存器APSR(Application Program Status Register),当前程序状态寄存器CPSR(Current PSR),保存的程序状态寄存器SPSR。
1)、加减算术运算指令:(C进位,!为取反)
Opcode {S}{Cond} Rd, Rn, Operand2; Rd = Rn Opcode Operand2。
ADD{
S}{
Cond} Rd, Rn, Operand2; 加法,Rd = Rn + Operand2。
ADC{
S}{
Cond} Rd, Rn, Operand2; 带进位加法,Rd = Rn + Operand2 + C。
SUB{
S}{
Cond} Rd, Rn, Operand2; 减法(substract),Rd = Rn - Operand2。
SBC{
S}{
Cond} Rd, Rn, Operand2; 带进位减法(substract with carry ),Rd = Rn - Operand2 - !C。
RSB{
S}{
Cond} Rd, Rn, Operand2; 逆向减法(Reverse subtract)。Rd = Operand2 - Rn
RSC{
S}{
Cond} Rd, Rn, Operand2; 带进位逆向减法(Reverse subtract with carry),Rd = Operand2 - Rn - !C。
2)、饱和SAT(saturate)加减运算指令:有符号限幅最大正值或最小负值,无符号限幅2^n - 1或0(负值)。
Opcode{
Cond} Rd, Rn, Rm; Rd = SAT( Rn Opcode Rm )
QADD{
Cond} Rd, Rn, Rm; 饱和加法,Rd = SAT( Rn + Rm )。
QDADD{
Cond} Rd, Rn, Rm; 饱和加倍加法,Rd = SAT( Rn + SAT( 2*Rm ) )。
QSUB{
Cond} Rd, Rn, Rm; 饱和减法,Rd = SAT( Rn - Rm )。
QDSUB{
Cond} Rd, Rn, Rm; 饱和加倍减法,Rd = SAT( Rn - SAT( 2*Rm ) )。
有符号或无符号饱和到任何位的位置,可选择在饱和前进行移位。
Opcode{
Cond} Rd, #SAT, Rm, shift}; Opcode = SSAT、USAT。#SAT指定要饱和到的位位置,SSAT范围:1--32,USAT范围:0--31。Rm、Rd不能为PC(R15)。shift是一个可选的移位,ASR #n; (ARM n = 1--32,T32 n = 1--31),LSR #n; (n = 0--31)。
SSAT{
Cond} Rd, #SAT, Rm, shift}; 有符号(Signed Sat)饱和字、移位,Rd = SignedSat((Rm, ASR|LSR #sh), #sat)。
USAT{
Cond} Rd, #SAT, Rm, shift}; 无符号(Unsigned Sat)饱和字、移位,Rd = UnsignedSat((Rm, ASR|LSR #sh), #sat)。
并行半字饱和指令(同时高低2个半字):
Opcode {
Cond} Rd, #SAT, Rm; Opcode= SSAT16(Signed Sat16)有符号饱和、USAT16(Unsigned Sat16)无符号饱和。#SAT指定要饱和到的位位置,SSAT16范围:1--16,USAT16范围:0--15。Rm、Rd不能为PC(R15)。
SSAT16{
Cond} Rd, #SAT, Rm; 有符号饱和两个半字,Rd[31:16] = SignedSat(Rm[31:16], #sat),Rd[15:0] = SignedSat(Rm[15:0], #sat)。
USAT16{
Cond} Rd, #SAT, Rm; 无符号饱和两个半字,Rd[31:16] = UnsignedSat(Rm[31:16], #sat),Rd[15:0] = UnsignedSat(Rm[15:0], #sat)。
3)、并行加减算术运算指令:<prefix>
Opcode {Cond} Rd, Rn, Rm;
并行指令前缀(<prefix>):
S: 对2^8 or 2^16有符号求模,设置CPSR的GE[0:3]标志(Signed arithmetic modulo 2^8 or 2^16 ,sets CPSR GE bit)。
Q:有符号饱和运算(Signed saturating arithmetic)。
SH:有符号运算,结果减半(Signed arithmetic, halving results)。
U:对2^8 or 2^16无符号求模,设置CPSR的GE[0:3]标志(Unsigned arithmetic modulo 28 or 216 ,sets CPSR GE bit)。
UQ:无符号饱和运算(Unsigned saturating arithmetic)。
UH:无符号运算,结果减半(Unsigned arithmetic ,halving results)。
GE位:GE[0]用于结果的[7:0]位,GE[1]用于结果的[15:8]位,GE[2]用于结果的[23:16]位,GE[3]用于结果的[31:24]位。
<prefix>ADD8{
Cond} Rd, Rn, Rm; 以字节为单位的4个字节并行加法。Rd[31:24] = Rn[31:24] + Rm[31:24],Rd[23:16] = Rn[23:16] + Rm[23:16],Rd[15:8] = Rn[15:8] + Rm[15:8],Rd[7:0] = Rn[7:0] + Rm[7:0]。
<prefix>ADD16{
Cond} Rd, Rn, Rm; 以半字为单位的2个半字并行加法。Rd[31:16] = Rn[31:16] + Rm[31:16],Rd[15:0] = Rn[15:0] + Rm[15:0]。
<prefix>SUB8{
Cond} Rd, Rn, Rm; 以字节为单位的4个字节并行减法。Rd[31:24] = Rn[31:24] - Rm[31:24],Rd[23:16] = Rn[23:16] - Rm[23:16],Rd[15:8] = Rn[15:8] - Rm[15:8],Rd[7:0] = Rn[7:0] - Rm[7:0]。
<prefix>SUB16{
Cond} Rd, Rn, Rm; 以半字为单位的2个半字并行减法。Rd[31:16] = Rn[31:16] - Rm[31:16],Rd[15:0] = Rn[15:0] - Rm[15:0]
<prefix>ASX{
Cond} Rd, Rn, Rm; 先交换Rm的半字,然后高半字相加、低半字相减。Rd[31:16] = Rn[31:16] + Rm[15:0],Rd[15:0] = Rn[15:0] - Rm[31:16]
<prefix>SAX{
Cond} Rd, Rn, Rm; 先交换Rm的半字,然后高半字相减、低半字相加。Rd[31:16] = Rn[31:16] - Rm[15:0],Rd[15:0] = Rn[15:0] + Rm[31:16]
<prefix>USAD8 {
Cond} Rd, Rn, Rm; 差值的绝对值无符号求和。Rd = Abs( Rn[31:24] - Rm[31:24] ) + Abs( Rn[23:16] - Rm[23:16] ) + Abs( Rn[15:8] - Rm[15:8] ) + Abs( Rn[7:0] - Rm[7:0] )
<prefix>USADA8 {
Cond} Rd, Rn, Rm, Ra; 差值的绝对值无符号求和,再累加。Rd = Ra + Abs( Rn[31:24] - Rm[31:24] ) + Abs( Rn[23:16] - Rm[23:16] ) + Abs( Rn[15:8] - Rm[15:8] ) + Abs( Rn[7:0] - Rm[7:0] )
4)、乘法算术运算指令:
MUL {
S}{
Cond} Rd, Rn, Rm; 乘法(Multiply), Rd = ( Rn * Rm )[31:0](如果 Rn 为 Rd,则 S 可用于 Thumb-2 中。取结果低32位)
MLA {
S}{
Cond} Rd, Rn, Rm, Ra; 乘加(Multiply and accumulate),Rd = ( Ra + ( Rn * Rm ) )[31:0]
MLS {
S}{
Cond} Rd, Rn, Rm, Ra; 乘减,Rd = ( Ra - ( Rn * Rm ) )[31:0]
UMULL{
S}{
Cond} RdLo, RdHi, Rn, Rm; 无符号长整数乘法(Unsigned multiply long),RdHiRdLo(64位结果) = unsigned( Rn * Rm )
UMLAL{
S}{
Cond} RdLo, RdHi, Rn, Rm; 无符号长整数乘加(Unsigned mul&accumulate long),RdHiRdLo = unsigned( RdHiRdLo + Rn * Rm )
UMAAL{
Cond} RdLo, RdHi, Rn, Rm; 无符号长整数乘法,两次加法,RdHiRdLo = unsigned( RdHi + RdLo + Rn * Rm )
SMULL{
S}{
Cond} RdLo, RdHi, Rn, Rm; 有符号长整数乘法(signed multiply long),RdHiRdLo(64位结果) = signed( Rn * Rm )
SMLAL{
S}{
Cond} RdLo, RdHi, Rn, Rm; 有符号长整数乘加(signed mul&accumulate long),RdHiRdLo = signed( RdHiRdLo + Rn * Rm )
SMULxy{
Cond} Rd, Rn, Rm; 有符号16 * 16 位乘法,Rd = signed( Rn[x] * Rm[y] ),x、y可为B(低16位)或T(高16位)。
SMLAxy{
Cond} Rd, Rn, Rm, Ra; 有符号16 * 16