-
ARM汇编基础概述
ARM与 x86相比较
■ 精简指令集
对于每一个复杂的操作,与x86汇编相比具有更多的指令。
■ 固定的指令长度
x86有可变长度的指令, ARM将指令长度固定为32位
■ 内存对齐
ARM/RISC要求内存对齐
对齐内存需要进行填充
■ 条件执行
每条指令的前四位包含一个条件码**
ARM指令的表示方式
以ADDEQS R0,R1,#8为例,其二进制代码形式为:
31—28 |
27—25 |
24—21 |
20 |
19—16 |
15—12 |
11—0 |
0000 |
001 |
0100 |
1 |
0001 |
0000 |
000000001000 |
cond |
Opcode |
Rn |
Rd |
Op2 |
从上面可知,ARM指令一般包括5个域:
条件码域 |
cond |
4位 |
指令代码域 |
Opcode |
8位 |
地址基址 |
Rn |
4位 |
目标或源寄存器 |
Rd |
4位 |
地址偏移或操作寄存器 |
Op2 |
12位 |
汇编指令格式
<opcode>{<cond>}{S}{.W|.N}<Rd>,<Rn>{,<operand2>} <>表示该内容必不可少,{}表示可省略。 <opcode>表示操作码,如ADD表示算术加法。 {<cond>} 表示指令执行的条件域,如EQ,NE等。缺省则表示默认条件(无条件执行)。 {S} 决定指令的执行结果是否影响CPSR的值,使用该后缀则指令执行的结果影响CPSR的值,否则不影响。 {.W|.N} 使用.W 宽度说明符。 即使 16 位编码可用,该指令宽度说明符也会强制汇编器生成 32 位编码。无论代码将会被汇编为 ARM 代码还是 Thumb(ARMv6T2 或更高版本)代码,您都可在其中使用 .W 说明符。 .W 说明符不会对代码的 ARM 编译产生任何影响。 如果要将指令汇编为 16 位编码,则您可使用 .N 宽度说明符。 在这种情况下,如果指令无法编码为 16 位,或者要将代码汇编为 ARM 代码,则汇编器会生成错误。 使用指令宽度说明符时,必须将说明符紧随在指令助记符和条件代码(如果有)之后,例如: BCS.W label ; forces 32-bit instruction even for a short branch B.N label : faults if label out of range for 16-bit instruction <Rd> 表示目的寄存器。 <Rn> 表示第一个操作数,为寄存器。 <Op2> 表示第二个操作数,可以使立即数,寄存器或寄存器偏移操作数。
上述指令ADDEQS R0,R1,#8;其中操作码为ADD,条件域为EQ,S表示该指令的执行影响CPSR寄存器的值,R0为目的寄存器,R1为第一个操作数寄存器,立即数#8为第二个操作数。
条件码助记符 |
标志位 |
含有 |
EQ |
Z=1 |
相等 |
NE |
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 |
忽略 |
无条件执行 |
ARM指令
ADC指令:带进位加法指令,将操作数2的数据与Rn的值相加,再加上CPSR中C条件标志位,结果保存到Rd中
使用ADC指令实现64位加法
ADDS R0,R0,R2 ; R0+R2 => R0,影响CPSR中的值 ADC R1,R1,R3 ;(R1、R0) = (R1、R0)+(R3、R2)
SBC指令:带借位减法指令,用寄存器Rn减去操作数2,再减去CPSR中的C条件标志位的非(即若C标志清零,则结果减去1),结果保存在Rd中。
使用SBC实现64位减法:
SUBS R0,R0,R2 SBC R1,R1,R3 ;使用SBC实现64位减法,(R1,R0) - (R3,R2)
AND指令:按位与操作
ANDS R0,R0,#0x01 ;取出最低位数据
ORR指令:按位或操作
ORR R0,R0,#0x0F ;将R0的低4位置1
EOR指令是进行异或操作,BIC指令是位清除指令(遇1清0)。
TST:位测试指令
TST R0,#0x01 ; 判断R0的最低位是否是为0
TEQ:相等测试指令
TEQ R0,R1 ; 比较R0与R1是否相等,也可看作相减,相等则为0,Z=1
MUL指令:乘法指令
MUL R1,R2,R3 ; R1=R2*R3 MULS R0,R3,R7 ; R0=R3*R7,同时设置CPSR中的N位和Z位
MLA是乘加指令,将操作数1和操作数2相乘再加上第3个操作数,结果的低32位存入到Rd中。
UMULL是64位无符号乘法指令:
UMULL R0,R1,R5,R8 ; (R1、R0) = R5 * R8
BL指令:带链接的跳转指令,指令将下一条指令拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行 BL指令用于子程序调用,例如:BL DELAY 。
BX指令:带状态切换的跳转指令,例如 BX R0 ;跳转到R0指定的地址,并根据R0的最低位来切换处理器的状态。
详细的指令介绍: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/CIHDDCIF.html
Thumb指令
Thumb指令可以看作是ARM指令压缩形式的子集,是针对代码密度问题而提出的,具有16位的代码密度。在ARM状态下,绝大多数的指令都是有条件执行的。
而在Thumb状态下,仅有分支指令是有条件执行的。
在Thumb状态下,不能直接访问所有的寄存器,只有寄存器R0—R7是可以被任意访问的。寄存器R8—R12只能通过MOV,ADD或CMP指令来访问。CMP指令和所有操作R0—R7的数据处理指令都会影响CPSR中的条件标志。
寄存器使用规则
寄存器的使用必须满足以下规则:
子程序间通过寄存器R0-R3来传递参数,使用R4-R11来保存局部变量。在Thumb程序中,通常只使用R4-R7来保存局部变量。R12用作子程序间scratch寄存器。
R13用作数据栈指针,记为SP,在子程序中不能用作其它用途。SP在进入子程序时的值与退出子程序时的值必须相等。
R14为连接寄存器,用于保存子程序的返回地址,记作LR。如果子程序保存了返回地址,则可以用于其它用途。
R15为程序计数器,记作PC,不能用作其它用途。
寄存器 |
别名 |
特殊名称 |
使用规则 |
R0 |
A1 |
参数/返回值/ Scratch寄存器1 |
|
R1 |
A2 |
参数/第二个32位的返回值/ Scratch寄存器2 |
|
R2/R3 |
A3/A4 |
参数/ Scratch寄存器3/4 |
|
R4 |
V1 |
ARM状态局部变量寄存器1 |
|
R5 |
V2 |
ARM状态局部变量寄存器2 |
|
R6 |
V3 |
ARM状态局部变量寄存器3 |
|
R7 |
V4 |
ARM状态局部变量寄存器4 |
|
R8 |
V5 |
ARM状态局部变量寄存器5 |
|
R9 |
V6 |
SB |
ARM状态局部变量寄存器6/基址寄存器 |
R10 |
V7 |
SL |
ARM状态局部变量寄存器7/数据栈限制指针 |
R11 |
V8 |
FP |
ARM状态局部变量寄存器8/ARM帧指针 |
R12 |
IP |
子程序内部调用的Scratch寄存器 |
|
R13 |
SP |
堆栈指针 |
|
R14 |
LR |
连接寄存器(保存子程序返回地址) |
|
R15 |
PC |
程序计数器 |
CPU总是按照PC的指向对指令序列进行取指、译码和执行,也就是说,最终是PC决定了程序运行流向。故而,程序计数器(PC)属于特别功能寄存器范畴,不能自由地用于存储其他运算数据。
在程序开始执行前,将程序指令序列的起始地址,即程序的第一条指令所在的内存单元地址送入PC,CPU按照PC的指示从内存读取第一条指令(取指)。当执行指令时,CPU自动地修改PC的内容,即每执行一条指令PC增加一个量,这个量等于指令所含的字节数(指令字节数),使PC总是指向下一条将要取指的指令地址。由于大多数指令都是按顺序来执行的,所以修改PC的过程通常只是简单的对PC加“指令节数”。
当程序转移时,转移指令执行的最终结果就是要改变PC的值,此PC值就是转去的目标地址。处理器总是按照PC指向取指、译码、执行,以此实现了程序转移。
ARM将指令长度固定为32位,故指令字节数总是为4字节。
CPSR( Current Program Status Register当前程序状态寄存器)
■ 高四位包含条件标志: Negative, Zero, Carry, oVerflow
■ 低8位为控制位。
■ SPSR( Saved Program Status Register备份的程序状态寄存器) (异常模式)
CPSR
说明:
条件标识位[31 : 28]:它们的内容可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。在ARM状态下,绝大多数指令都是有条件的执行的,在Thumb状态下,只有分支指令被有条件的执行。
标志位 |
含义 |
N |
当用两个补码表示的带符号数进行运算时,N=1 表示运算的结果为负数;N=0 表示运算的结果为正数或零 |
Z |
Z=1 表示运算的结果为零;Z=0表示运算的结果为非零 |
C |
可以有4种方法设置C的值: ─ 加法运算(包括比较指令CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 ─ 减法运算(包括比较指令CMP):当运算时产生了借位(无符号数溢出),C=0,否则C=1。 ─ 对于包含移位操作的非加/减运算指令,C为移出值的最后一位。 ─ 对于其他的非加/减运算指令,C的值通常不改变。 |
V |
可以有2种方法设置V的值: ─ 对于加/减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出。 ─ 对于其他的非加/减运算指令,V的值通常不改变。 |
保留位[27 : 8]:当改变PSR中的条件码标志位或者控制位时,保留位不要被改变,在程序中也不要使用保留位来存储数据。保留位将用于ARM版本的扩展。
控制位[7 : 0]:PSR的低8位(包括I、F、T和M[4:0])称为控制位,当发生异常时这些位可以被改变。如果处理器运行特权模式,这些位也可以由程序修改。
I |
I =1 表示禁止外部(硬件)中断(IRQ) |
F |
F=1 表示快速中断(FIQ) |
T |
反映处理器的运行状态 |
运行模式位M[4 : 0]:M0、M1、M2、M3、M4是模式位。这些位决定了处理器的运行模式。
ARM处理器的七种工作模式
用户模式(usr):ARM处理器正常的程序执行状态。
快速中断模式(fiq):用于高速数据传输或通道处理。
外部中断模式(irq):用于通用的中断处理。
管理模式(svc):运行系统级代码来访问硬件或运行操作系统调用的保护模式。
终止模式(abt):当数据或指令从无效的内存区域取值时进入该模式,用于虚拟存储及存储保护。
未定义指令模式(und):当未定义的指令执行时进入该模式,用于支持硬件协处理器的软件仿真。
系统模式(sys):运行具有特权的操作系统任务。
除用户模式外,其余六种模式称为非用户模式或特权模式。除用户模式和系统模式以外的五种模式又被称为异常模式,常用于处理中断或异常,以及需要访问受保护的系统资源等情况。
大多数应用程序运行在用户模式下,运行在用户模式下的某些被保护的系统资源是不能被访问的。应用程序也不能直接进行处理器模式的转换,除非产生异常处理,在异常处理中进行处理器模式切换。
当应用程序发生异常中断时,处理器进入相应的异常模式。在每一种异常模式中都有一组寄存器,供相应的异常处理程序使用,这样就可以保证在进入异常模式时,用户模式下的寄存器(保存了程序运行状态)不被破坏。
系统模式并不是通过异常过程进入的,它和用户模式具有完全一样的寄存器。但是系统模式属于特权模式,可以访问所有的系统资源,也可以直接进行处理器模式切换。它主要供操作系统任务使用。
M[4:0] |
处理器模式 |
可访问的寄存器 |
10000 |
用户模式 |
PC,CPSR,R0-R14 |
10001 |
FIQ模式 |
PC,CPSR,SPSR_fiq,R14_fiq-R8_fiq,R7-R0 |
10010 |
IRQ模式 |
PC,CPSR,SPSR_irq,R14_irq,R13_irq,R12-R0 |
10011 |
管理模式 |
PC,CPSR,SPSR_svc,R14_svc,R13_svc,R12-R0 |
10111 |
中止模式 |
PC,CPSR,SPSR_abt,R14_abt,R13_abt,R12-R0 |
11011 |
未定义模式 |
PC,CPSR,SPSR_und,R14_und,R13_und,R12-R0 |
11111 |
系统模式 |
PC,CPSR,R14-R0 |
在实际系统中,内核状态需要经常的切换(Interworking)来满足系统性能需求。具体的切换是通过Branch Exchange—即BX 指令来实现的。指令格式为:
Thumb状态 BX Rn
ARM状态 BX<condition> Rn
其中Rn可以是寄存器R0—R15中的任意一个。指令可以通过将寄存器Rn的内容拷贝到程序计数器PC来完成在4Gbyte地址空间中的绝对跳转,而状态切换是由寄存器Rn的最低位来指定的,如果操作数寄存器的状态位Bit0=0,则进入ARM状态,如果Bit0=1,则进入Thumb状态。
出处:https://www.cnblogs.com/goodhacker/archive/2013/04/25/3043158.html