概述
文章目录
- 指令基础
- 指令周期和时序
- 程序的执行过程
- ARM汇编语言
- 指令和指令格式
- 指令和指令系统
- 指令的表示方法
- 汇编的指令格式
- 指令的可选后缀
- S后缀
- !后缀
- 指令的条件执行
- ARM指令分类
- ARM指令的寻址方式
- 立即寻址
- 寄存器寻址
- 寄存器间接寻址
- 寄存器移位寻址
- 基址变址寻址
- 多寄存器寻址
- 相对寻址
- 堆栈寻址
- 数据处理指令
- 数据传送指令
- MOV
- MVN
- 移位操作
- LSL
- LSR
- ASR
- ROR
- RRX
- 算术指令
- ADD
- ADC
- SUB
- SBC
- RSB
- RSC
- 逻辑运算指令
- AND
- ORR
- EOR
- BIC
- 比较指令
- CMP
- CMN
- TST
- TEQ
- 乘法指令
- MUL
- MLA
- SMULL
- SMLAL
- UMULL
- UMLAL
- 数据加载与存储指令
- 数据加载与存储指令概述
- 数据加载与存储的方向问题
- 数据加载与存储指令的寻址
- 地址索引
- 前索引
- 自动索引
- 后索引
- 单寄存器加载与存储指令
- LDR/STR
- LDRB/STRB
- LDRH/STRH
- LDRSB/LDRSH
- 多寄存器加载与存储指令
- LDM/STM
- 堆栈操作
- 堆栈
- 堆栈操作
- 建栈
- 进栈
- 出栈
- 交换指令
- SWP
- SWPB
- 分支指令
- 分支指令B
- 带返回的分支指令BL
- 带状态切换的分支指令BX
- 带返回和状态切换的分支指令BLX
- 程序状态寄存器访问指令
- MRS
- MSR
- 协处理器指令
- CDP协处理器数据处理指令
- LDC协处理器数据加载指令
- STC协处理器数据存储指令
- MCR ARM处理器寄存器到协处理器存储器的数据传送指令
- MRC 协处理器寄存器到ARN处理器寄存器的数据传送指令
- 软件中断指令
- SWI软件中断指令
- SWI的调用
- ARM伪指令
- ADR小范围的地址读取伪指令
- ADRL中等范围的地址读取伪指令
- LDR大范围的地址读取伪指令
- NOP空操作伪指令
- Thumb指令集
- 概述
- Thumb指令寄存器的使用
- ARM-Thumb交互
- 数据处理指令
- 单寄存器加载和存储指令
- 多寄存器加载和存储指令
- 堆栈指令
- 软件中断指令
- Thumb伪指令
- ADR小范围地址读取
- LDR大范围地址读取
- NOP空操作
指令基础
指令周期和时序
时钟信号:是一个周期性的脉冲信号
时钟周期(clock cycle):一个时钟脉冲的时间长度,是主频的倒数
时钟频率:也称为主频,一秒内,时钟信号的个数
指令周期(instruction cycle):执行一条指令需要的时间,不同指令的指令周期不同,和操作数的寻址方式也有关,一般情况下,以访问寄存器所需的最长时间来衡量指令周期
对于ARM7而言,所有存储器的传输周期都可以被归结到以下4个类型:
- 不连续周期:上一次和本次访问的操作数地址没有联系,称为访问非顺序内存位置的周期,简称N周期
- 连续周期:上一次和本次访问的操作数地址相同或连续,称为访问顺序内存位置的周期,简称S周期
- 内部周期:ARM不请求传输,只是执行内部功能,称为内部周期,简称I周期
- 协处理器寄存器传输周期:ARM与协处理器之间的数据总线传输一个字的周期,简称C周期
程序的执行过程
执行一条指令的过程可以分为:取指、译码、执行
- 取指:CPU进入取指阶段,通过控制总线(control bus)发出读命令,并从地址总线(addr bus)所给出的地址,即存储器中取出指令代码,经过数据总线送到CPU的指令寄存器中
- 译码:翻译取出的指令代码
- 执行:执行代码指定的动作
ARM汇编语言
指令和指令格式
指令和指令系统
指令:指示计算机进行某种操作的命令
指令系统:指令的集合称为指令系统
助记符:指令的符号表示
指令的表示方法
指令在内存中,以二进制形式保存
ARM指令代码一般可以分为5个域:
- 【31:28】:条件码域
- 【27:20】:指令码域,除指令编码外,还包含几个很重要的指令特征和可选后缀的编码
- 【15:12】:地址基址Rn,为R0-R15共16个寄存器编码
- 【15:12】:目标或源寄存器Rd,为R0-R15共16个寄存器编码
- 【11:0】:地址偏移或操作寄存器、操作数区
汇编的指令格式
操作码 指令的执行条件 S 目的操作数 源操作数 源操作数2
<opcode> {<cond>} {S} <Rd>, <Rn> {, <OP2>}
- <> :括号里的内容必不可少
- {} : 括号里的内容可省略
- opcode:操作码,如ADD表示加法
- cond:指令执行的条件域,如EQ,NE,省略则为默认AL,无条件执行
- S:决定指令的执行结果是否影响CPSR的值,使用该后缀则影响
- Rd:目的操作数的寄存器
- Rn:第一个操作数的寄存器
- OP2:第二个操作数,可以是立即数、寄存器、偏移地址
指令的可选后缀
ARM指令集中大多数指令,都可以加后缀,这使得指令的使用更加灵活,常见的S和!
S后缀
- 指令使用“S”后缀时,指令执行后程序状态寄存器的条件标志位被刷新
- 不使用“S”后缀时,条件标志位不改变
- “S”后缀通常用于对条件进行测试,例如是否溢出、进位等
!后缀
- 地址表达式中不含“!”,则基址寄存器中的地址值不会发生变化
- 含有“!”,基址寄存器中的地址值发生变化,基址寄存器的值,变为原来的值再加上偏移地址
例如:LDR R3,[R0,#4],关键在于R0是否发生变化
使用“!”需要注意:
- 必须紧跟在地址表达式的后面,而地址表达式要有明确的偏移量
- 不能用于R15(PC)后面
- 当用在单个地址寄存器后面时,必须确信这个寄存器有隐形的偏移量
指令的条件执行
- 程序要执行的指令都保存在存储器中,需要执行时,先产生地址,再根据地址,去存储器取出指令代码,然后译码执行
- 当工作在ARM状态时,几乎所有的指令都根据CPSR中条件码和指令的条件域,有条件的执行,不满足则忽略
- ARM指令包含4位条件码,位于【31:28】,共16种,每种可用两个字母表示,它可以添加在指令助记符后面和指令同时使用
条件后缀和S后缀的关系: - 都存在时,S写后面,如ADDEQS
- 条件后缀是要测试条件标志位,而S后缀是要刷新条件标志位
- 条件后缀要测试的是执行前的标志位,而S后缀在执行后改变标志位
ARM指令分类
ARM指令集可以分为:数据处理指令、数据加载存储指令、分支指令、程序状态寄存器PSR处理指令、协处理器指令、异常产生指令
ARM指令的寻址方式
寻址方式:根据操作数的信息,来寻找操作数对应的实际物理地址
立即寻址
MOV R0,#5
#5就是立即寻址,必须加#前缀
对于十进制,可以加0d或缺省,如:#0d5
对于十六进制,必须加0x或者&,如:#0x5
对于二进制,必须加0b,如:#0b11
寄存器寻址
寄存器寻址,就是利用寄存器中的数值作为操作数
ADD R0, R1, R2
R1+R2 -> R0
寄存器间接寻址
以寄存器的值作为操作数的地址,而操作数本身存放在存储器中
LDR R0, [R4]
以R4的值为地址,去存储器中找到对应物理地址,取出的数才是操作数
寄存器移位寻址
操作数由寄存器的值经过移位后得到,移位的方式在指令中以助记符给出
ADD R0, R1, R2, LSL #1
R1 + (R2 << 1) -> R0
MOV R0, R1, LSL R3
(R1<<3) -> R0
基址变址寻址
将寄存器的内容,与指令给出的偏移地址相加,得到操作数的地址,操作数在存储器中
LDR R0, [R1. #4]
[R1+4] -> R0
LDR R0, [R1. #4]!
[R1+4] -> R0, R1+4 -> R1
LDR R0, [R1], #4
[R1] -> R0, R1+4 -> R1
LDR R0, [R1. R2]
[R1+R2] -> R0
多寄存器寻址
一条指令可以完成多个寄存器值的传送,连续的寄存器用“-”连接,否则用“,”连接
LDMIA R0!, {R1-R4}
[R0] -> R1
[R0+4] -> R2
[R0+8] -> R3
[R0+12] -> R4
该指令的后缀IA表示,每次执行完加载/存储操作后,R0按(32位)增加
相对寻址
相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,相加之后,得到操作数的地址,一般用于子程序的调用,中断异常的处理
堆栈寻址
使用堆栈指针表示当前栈顶位置,R13一般为堆栈指针
ARM中采用LDMFD、STMFD指令来支持POP和PUSH操作
STMFD R13!, {R0-R4}
LDMFD R13!, {R0-R4}
S-STORE,将R0-R4压栈
L-LOAD,将R0-R4出栈
数据处理指令
数据处理指令对存放在寄存器中的数据进行操作,分为
- 数据传送指令
- 算术指令
- 逻辑运算指令
- 比较指令
- 乘法指令
ARM数据处理指令机器编码格式如下:
- cond:指令执行的条件码
- I:用于区别第二操作数是立即数(I=1)还是寄存器移位(I=0)
- opcode:数据处理指令操作码
- S:用于设置条件码,S=0时条件码不变
- Rn:第一操作数寄存器
- Rd:目标寄存器
- op2:第二操作数,该操作数可以是立即数或寄存器移位数
数据传送指令
将一个寄存器中的数据或立即数,传送到另一个寄存器
MOV
MOV {<cont>} {S} Rd, op2
功能:
- MOV指令将源操作数op2传送到Rd中,通常op2是立即数、寄存器Rm、或寄存器Rm移位
- S决定结果是否影响CPSR中条件标志位
MOV R1, R0
R0 -> R1
MOV PC, R14
R14 -> PC,常用于子程序返回
MOV R1, R0, LEL #3
(R0<<3) -> R1
MOV R0, #5
5 -> R0
MVN
MVN {<cont>} {S} Rd, op2
功能:
- 将一个寄存器、移位寄存器、立即数传送到目的寄存器Rd
- 数据在传送之前按位取反
- S决定结果是否影响CPSR中条件标志位
MVN R0, #1
MVN R1, R2
移位操作
- ARM微处理器一个特点:在操作数进入ALU之前,对操作数进行预处理,如左移和右移
- 这种处理是通过内嵌的桶形移位器(barrel shifter)实现的
- 桶形移位器支持数据的各种移位操作,移位操作在ARM指令集不再作为单独的指令使用,而是作为一个选项
- 包括逻辑左移LSL,逻辑右移LSR,算术右移ASR,循环右移ROR,带扩展的循环右移RRX
LSL
Rm, LSL<opl>
- LSL指令完成对通用寄存器Rm中的内容进行逻辑左移,按opl指定的位数移位,低位用0填充,相当于无符号数乘2^n
- opl可以是立即数,也可以是寄存器方式
LSR
Rm, LSR<opl>
- 寄存器Rm右移opl指定的次数,空位用零填充,opl的要求如同LSL
ASR
Rm, ASR<opl>
- 寄存器Rm按opl指定的次数右移,其中高位用31位原本的值填充(注意有符号数的负数,31位为1)
- opl的要求同上,但是范围限制到1-32
ROR
Rm, ROR<opl>
- 右移指定次数,其中空出来的最高位,用最低位移出去的数来补
- opl要求同上,范围限制1-31
RRX
Rm, RRX
对通用寄存器中的内容进行RRX右移一位时,该寄存器的32位+C标志位,一共33位组成一个循环右移
算术指令
主要是加减法,实现两个32位数据的加减操作,通常与桶形移位器结合起来,实现许多灵活的功能
主要包括:加法ADD,带进位加法ADC,减法SUB,带借位减法SBC,逆向减法RSB,带借位逆向减法RSC
ADD
ADD {<cont>} {S} Rd, Rn, op2
- 将Rn与op2相加,结果送到Rd,Rn + op2 -> Rd
- Rn要求是寄存器,op2可以是寄存器、移位寄存器、立即数
- S决定指令的操作是否影响CPSR
ADD R0, R1, R2
ADD R0, R1, #5
ADD R0. R1. R2, LSL #2
第二操作数op2的要求:
- 是一个无符号的32位数
- 由一个8位无符号数,用0填充到32位,再循环右移偶数次,得到这个操作数,例如0x8801就不符合
ADC
ADC {<cont>} {S} Rd, Rn, op2
- Rn + op2 + C -> Rd,需要额外加上条件标志位C的值
- Rd,Rn必须是寄存器,op2可以是寄存器、移位寄存器、立即数
- 该指令用于实现超过32位的加法
例:两个64位数相加,第一个64位数,存放在R2、R3中,第二个存放在R4,R5中,64位结果存放在R0,R1中
分析:将两个64位数中,低32位相加,结果影响C标志位,然后将64位中的高32位以及低32位产生的进位相加
ADDS R0, R2, R4
ADC R1, R3, R5
SUB
SUB {<cont>} {S} Rd, Rn, op2
- Rn - op2 -> Rd
- 用于有符号、无符号数的减法运算
SUB R0, R1, R2
SUB R0, R1, #6
SUB R0, R2, R3, LSL #1
SBC
SBC {<cont>} {S} Rd, Rn, op2
- 带借位的减法,Rn - op2 - !C -> Rd
- S标志影响执行后CPSR的NZCV,SUB和SBC生成进位标志的方式不同于常规,如果需要进位,则清除进位标志,在指令执行期间自动反转此位
- 该指令使用进位标志表示借位,这样可以做大于32位的减法
- 注意,存在借位时,C=0
RSB
RSB {<cont>} {S} Rd, Rn, op2
- 逆向减法指令,op2 - Rn -> Rd
RSC
RSC {<cont>} {S} Rd, Rn, op2
- 带借位的逆向减法,op2 - Rn - !C -> Rd
- 用来做大于32位的减法
逻辑运算指令
逻辑运算是按位进行操作的,位与位之间没有进位或借位,没有数的正负大小之分
主要包括:AND逻辑与,ORR逻辑或,EOR逻辑异或,BIC位清除
AND
AND {<cont>} {S} Rd, Rn, op2
- 将操作数按位进行逻辑与运算,结果放到Rd
- Rn & op2 -> Rd
- 常用于将操作数Rn特定位清零
ORR
ORR {<cont>} {S} Rd, Rn, op2
- 将操作数按位进行逻辑或运算,结果放到Rd
- Rn | op2 -> Rd
- 常用于将操作数Rn特定位置1
EOR
EOR {<cont>} {S} Rd, Rn, op2
- 将操作数按位进行异或运算,结果放到Rd
- Rn ^ op2 -> Rd
- S决定执行后条件标志位的N Z
- 该指令常用于反转操作数Rn中的某些位
BIC
BIC {<cont>} {S} Rd, Rn, op2
- 用于清除操作数Rn的某些位,并把结果放到Rd中
- Rn & (!op2) -> Rd
- 这里的op2可以看做一个32位掩码,如果设置了某一位,则清除Rd中对应位
- S决定执行后条件标志位的N Z
比较指令
- 通常用于把一个寄存器与一个32位的值进行比较或测试
- 比较指令根据结果更新CPSR中的标志位
- 其它指令根据标志位来改变程序执行的顺序
- 包括比较指令CMP,反值比较指令CMN,位测试指令TST,相等测试TEQ
CMP
CMP {<cont>} Rn, op2
比较指令,将Rn与op2进行比较,实质是做减法运算,Rn - op2,并根据结果更新CPSR中条件标志位的值
CMN
CMN {<cont>} Rn, op2
反值比较指令,将Rn与op2取反后进行比较,实质上,是Rn + op2,并根据结果改变标志位
TST
TST {<cont>} Rn, op2
位测试指令
- 将Rn与op2,按位进行与运算,并根据结果改变标志位
- 该指令通常用于检查是否设置了特定的位
- op2可以看做32位的掩码,需要检查某位,则该位设为1
TEQ
TST {<cont>} Rn, op2
相等测试指令
- 将Rn与op2进行异或运算,并根据结果更新标志位
- 通常用于比较操作数Rn和操作数op2是否相等
乘法指令
- 把一对寄存器的内容相乘,然后根据指令类型把结果累加到其他寄存器
- 乘法与乘加指令共6条,分为32位运算和64位运算
- 64位乘法称为长整形乘法指令,结果存放在2个32位寄存器Rdlo(低32)和Rdhi(高32)
- 指令中的所有源、目的操作数必须是通用寄存器,不能是移位和立即数,Rd和Rm必须是不同寄存器
- 分为32位乘法MUL,32位乘加MLA,64位有符号乘SMULL,64位有符号乘加SMLAL,64位无符号乘法UMULL,64位无符号乘加UMLAL
在使用乘法指令时,应该注意以下事项:
- 操作数必须都是寄存器,但是不能是R15,也就是PC寄存器
- Rd和Rm不能是同一个寄存器
- 64位运算中,有符号运算和无符号运算的低32位是没有区别的
- Rdlo,Rdhi,Rm必须使用不同的寄存器
MUL
MUL {<cont>} {S} Rd, Rm, Rs
32位乘法指令
- 将操作数Rm与Rs的乘积,送到Rd
- Rm * Rs -> Rd
- S选项影响条件标志位N和Z
MLA
MLA {<cont>} {S} Rd, Rm, Rs,Rn
32位乘加指令
- 将操作数Rm与Rs的乘积,加上Rn,送到Rd
- Rm * Rs + Rn -> Rd
SMULL
SMULL {<cont>} {S} Rdlo, Rdhi, Rm,Rs
64位有符号乘法指令
- 将操作数Rm与Rs的乘积,低32位送到Rdlo,高32位送到Rdhi
- Rm * Rs -> Rdhi 和 Rdlo
- 其中操作数Rm和Rs都是32位有符号数
SMLAL
SMLAL {<cont>} {S} Rdlo, Rdhi, Rm,Rs
64位有符号乘加指令
- 将操作数Rm与Rs的乘积,低32位与Rdlo累加后送到Rdlo,高32位与Rdhi累加后送到Rdhi
- Rm * Rs + Rdhi/Rdlo -> Rdhi 和 Rdlo
- 其中操作数Rm和Rs都是32位有符号数
UMULL
UMULL {<cont>} {S} Rdlo, Rdhi, Rm,Rs
64位无符号乘法指令
- 将操作数Rm与Rs的乘积,低32位送到Rdlo,高32位送到Rdhi
- Rm * Rs + Rdhi/Rdlo -> Rdhi 和 Rdlo
- 其中操作数Rm和Rs都是32位无符号数
UMLAL
UMLAL {<cont>} {S} Rdlo, Rdhi, Rm,Rs
64位无符号乘加指令
- 将操作数Rm与Rs的乘积,低32位与Rdlo累加后送到Rdlo,高32位与Rdhi累加后送到Rdhi
- Rm * Rs + Rdhi/Rdlo -> Rdhi 和 Rdlo
- 其中操作数Rm和Rs都是32位无符号数
数据加载与存储指令
ARM处理器是加载/存储体系结构的处理器,对于存储器的访问只能通过加载和存储指令实现
数据加载与存储指令概述
数据加载与存储的方向问题
- 数据加载(load)与存储(store)用于在存储器和处理器之间传递数据
- load用于把内存的数据,装入寄存器
- store用于把寄存器的数据,装入内存
- 有三种类型:单寄存器、多寄存器、交换指令
数据加载与存储指令的寻址
基本格式为:
option {<cont>} Rd,addr
- option为指令代码,如LDR表示将存储器中的数据加载到寄存器
- addr为寄存器地址表达式,可以用基址寄存器+偏移量得到
addr有以下几种形式
- 立即数:一个无符号的数值
- 寄存器:寄存器的值
- 寄存器移位:由通用寄存器和立即数组成,根据立即数移位,生成地址偏移量,再结合基址寄存器,如:
- LDR R3, [R2, R4, LSL #2]
- LDR R3, [R2], -R4, LSR #3
- 标号:这是一种简单的寻址方法,PC是隐含的基址寄存器,偏移量是标号所在的地址与PC的差值
地址索引
- ARM指令中的地址索引也是指令的一个功能,索引作为指令的一部分,它影响指令的执行结果
- 地址索引分为前索引(pre-indexed),自动索引(auto-indexed),后索引(post-indexed)
前索引
前索引也称为前变址,这种索引是在指令执行前,把偏移量和基址相加减,得到的值作为寻址的地址,例如
LDR R5, [R6, #0x04]
STR R0, [R5, -R8]
先把R6加上偏移4,再去寻址
先把R5的值,减去R8,再去寻址
索引并不会改变寄存器的值
自动索引
自动索引也称为自动变址,有时为了修改基址寄存器的内容,使之指向数据传送地址,可以用来自动修改基址寄存器
LDR R5, [R6, #0x04]!
在寻址前,先将R6加上偏移4,再去寻址,通过可选后缀“!”,完成基址寄存器的更新
后索引
后索引也称为后变址,就是用基址寄存器的地址寻址,找到操作数后,完成指令要求的操作,最后把偏移量加到基址寄存器中
- LDR R5, [R6], #0x04
先根据R6寻址,找到操作数后,将地址给R5,再把偏移量加到R6中 - STR R6, [R7], #-0x08
先将R6的值存到R7指向的地址中,再将偏移加到R7中
单寄存器加载与存储指令
这种指令用于把单一的数据传入或传出一个寄存器
LDR/STR
32位数据的加载/存储指令
各个位的含义:
- cond:指令执行的条件编码
- I P U W:用于区别不同的地址模式(偏移量),I=0时偏移量位12位立即数,I=1时偏移量为寄存器移位,P表示前后索引,U表示加减,W表示回写
- L:L=1表示加载,L=0表示存储
- B:B=1表示字节访问,B=0表示字访问
- Rd:源/目标寄存器
- Rn:基址寄存器
- addr_mode:表示偏移量,是一个12位的无符号二进制数,与Rn一起构成地址addr
使用格式:
LDR/STR {<cont>} {T} Rd, addr
- LDR用于从存储器中,将一个32位的数据加载到目的寄存器Rd中,当PC作为Rd时,实现程序的跳转
- STR用于从源寄存器中,将一个32位的数据存储到寄存器中
- 后缀T可选,如果有T,即使在特权模式下,存储系统也将访问看成用户模式下的,T在用户模式下无效
addr的表达方式灵活多变,以下举例说明:
//使用标号
LDR R4, START //将存储地址为START的32位数据送入R4
STR R5, DATA1 //将R5的数据存放到地址DATA1中
//前索引
LDR R0, [R1] //将R1地址指向的值,送入R0
LDR R0, [R1, R2] //将存储器地址为R1+R2的值,送入R0
LDR R0, [R1, #8] //将存储器地址为R1+8的值,送入R0
LDR R0, [R1, R2, LSL #2] //将存储器地址为R1+R2<<2的值送入寄存器R0
//自动索引
STR R0, [R1, R2]! //将R0数据存入寄存器地址为R1+R2的存储单元中,并将新地址R1+R2写入R1
STR R0, [R2, #8]! //将R0数据存入寄存器地址为R1+8的存储单元中,并将新地址R1+8写入R1
STR R0, [R1, R2, LSL #2]! //将R0数据存入寄存器地址为R1+R2<<2的存储单元中,并将新地址R1+R2<<2写入R1
//后索引
LDR R0, [R1], #8 //将存储器地址为R1的值送入R0,然后将新地址R1+8写入R1
LDR R0, [R1], R2 //将存储器地址为R1的值送入R0,然后将新地址R1+R2写入R1
LDR R0, [R1], R2, LSL #2 //将存储器地址为R1的值送入R0,然后将新地址R1+R2<<2写入R1
使用时要注意以下事项:
- 立即数的规定:立即数的绝对值不大于4095,可以使用带符号数,范围-4095~4095
- 标号使用的限制:要注意语句标号不能指向程序存储区,而是指向数据存储区
- 地址对齐:使用传送指令时,偏移量必须保证偏移的结果能够使地址对齐
- 移位的使用:使用寄存器移位的方法计算偏移量时,位数不能超过规定的值
1、ASR 算术左移 1≤n≤32
2、LSL 逻辑左移 0≤n≤31
3、LSR 逻辑右移 1≤n≤32
4、POR 循环右移 1≤n≤31 - 程序计数器PC:R15作为基址寄存器时,不可使用回写,即不能用“!”,另外R15不能作为偏移寄存器使用
LDRB/STRB
字节数据加载/存储指令
使用格式:
LDRB/STRB {<cont>} {T} Rd, addr
- LDRB用于从存储器中,将一个8位的数据加载到目的寄存器Rd中,同时将高24位清零,当PC作为Rd时,实现程序的跳转
- STRB用于从源寄存器中,将一个8位的数据存储到寄存器中,注意是低8位
- 后缀T可选,如果有T,即使在特权模式下,存储系统也将访问看成用户模式下的,T在用户模式下无效
- 即使传送的是8位数据,地址总线仍然以32位的宽度工作,而数据总线也是以32位宽度工作
字节传送和字传送差别很大,下面说明:
- 从寄存器到存储器:寄存器是32位,但是字节传输时,只能将低8位送到存储器,如果想要送其他位,必须通过移位指令
- 从存储器到寄存器:可以选择存储器中任意一个字节,加载到目的寄存器中,传送时,数据总线的高24位填充0
LDRH/STRH
半字数据(16位)加载/存储指令
各个位的含义:
- cond:指令执行的条件编码
- I P U W:用于区别不同的地址模式(偏移量),I=0时偏移量8位立即数,I=1时偏移量为寄存器移位,P表示前后索引,U表示加减,W表示回写
- L:L=1表示加载,L=0表示存储
- S:S=1有符号访问,S=0无符号访问
- H:H=1表示半字访问,H=0表示字节访问
- Rd:源/目标寄存器
- Rn:基址寄存器
- addr_H、addr_L:表示偏移量,I=0时,偏移量为8位立即数,由addr_H和addr_L组成,I=1时,偏移量为寄存器移位addr_H为0,addr_L表示寄存器编号
使用格式:
LDRH/STRH {<cont>} Rd, addr
- LDRH用于从存储器中,将一个16位的数据加载到目的寄存器Rd中,同时将高16位清零,当PC作为Rd时,实现程序的跳转
- STRH用于从源寄存器中,将一个16位的数据存储到寄存器中,注意是低16位
使用半字加载/存储指令需要注意如下事项:
- 必须半字地址对齐
- 对于R15使用需要慎重,R15作为基址寄存器Rn时,不可使用回写功能,不可使用R15作为目的寄存器
- 立即数偏移使用的是8位无符号数
- 不能使用寄存器移位寻址
LDRSB/LDRSH
有符号字节/半字数据加载指令
使用格式:
LDRSB/LDRSH {<cont>} Rd, addr
- LDRSB用于从存储器中,将一个8位的数据加载到目的寄存器Rd中,同时将高24位进行符号位扩展
- LDRSH用于从存储器中,将一个16位的数据加载到目的寄存器Rd中,同时将高16位进行符号位扩展
多寄存器加载与存储指令
- 多寄存器加载/存储指令,也称为批量数据加载/存储指令,可以一次在连续的存储器单元和多个寄存之间传送数据
- 多寄存器加载/存储指令在数据块操作、上下文切换、堆栈操作等方面比单寄存器指令效率更高
LDM/STM
图中各位含义如下:
- cond:指令执行的条件编码
- P U W:用于区别不同的地址模式,P表示前/后变址,U表示加/减,W表示回写
- S :S=1有符号数访问,S=0无符号数访问
- L:L=1表示加载,L=0表示存储
- Rn:基址寄存器
- regs:表示寄存器列表
使用格式:
LDM/STM {<cont>} {<type>} Rn{!}, <regs>{^}
- LDM指令用于从基址寄存器Rn所指向的连续存储器读取数据,放入寄存器列表regs中,一般用于多个寄存器出栈
- STM指令用于将寄存器列表中多个寄存器的值,存入由基址寄存器所指示的连续存储器中
type表示类型,用于数据存储和读取时有以下几种情况:
- IA:每次传送后地址值加
- IB:每次传送前地址值加
- DA:每次传送后地址值减
- DB:每次传送前地址值减
用于堆栈操作时有如下情况: - FD:满递减堆栈
- ED:空递减堆栈
- FA:满递增堆栈
- EA:空递增堆栈
{!}为可选后缀,选用后,当数据加载或存储完毕,将最后的地址写入基址寄存器,基址寄存器不允许R15
{^}为可选后缀,当指令为LDM且寄存器列表含有R15时,还会将SPSR复制到CPSR,同时该后缀还表示传输的是用户模式下的寄存器
LDM/STM指令依据其后参数不同,寻址方式差别很大
堆栈操作
堆栈
- 堆栈就是在RAM存储器中开辟的,一个特定的存储区域,遵循先进后出的原则
- 堆栈栈底固定,栈顶浮动,堆栈指针SP(R13)指向栈顶
- 当32位数据入栈时,SP的值减4
堆栈操作
建栈
建栈就是规定堆栈底部在RAM存储器中的位置,用户可以通过LDR命令设置SP的值
进栈
- ARM体系结构使用多寄存器指令完成堆栈操作
- 出栈LDM,入栈STM
- LDM和STM指令往往结合下面的一些参数实现堆栈的操作
- FD满递减堆栈
- ED空递减堆栈
- FA满递增堆栈
- EA空递增堆栈
在使用堆栈时,需要确定它是向上生长(递增ascending),还是向下生长(递减descending)
满堆栈(full stack):指堆栈指针SP(R13)指向堆栈的最后一个数据项的地址
空堆栈(empty stack):指SP指向堆栈的第一个没有使用的地址
ARM制定了一个标准:ARM-Thumb过程调用标准(ATPCS),定义了例程如何被调用,寄存器如何分配
其中,堆栈被定义为满递减堆栈,因此ARM汇编中,堆栈的操作是LDMFD和STMFD
出栈
POP操作出栈,ARM中使用LDMFD实现出栈操作
交换指令
数据交换指令能在存储器和寄存器之间交换数据,它是加载与存储指令的特例,交换是原子操作
- cond:指令执行的条件编码
- B:B=0字交换,B=1字节交换
- Rn:基址寄存器
- Rd:目的寄存器
- Rm:源寄存器
SWP
SWP {<cont>} <Rd>, <Rm>, [<Rn>]
- SWP指令用于将寄存器Rn所指向的寄存器中的字数据,加载到目的寄存器Rd中,同时将源寄存器Rm中的字数据,保存到该存储器的位置
- 当Rd与Rm相同时,即完成交换
SWPB
SWPB {<cont>} <Rd>, <Rm>, [<Rn>]
- SWPB指令用于将寄存器Rn所指向的寄存器中的字节数据,加载到目的寄存器Rd中,同时Rd高24位清零,同时将源寄存器Rm中的字节数据,保存到该存储器的位置
- 当Rd与Rm相同时,即完成交换
使用SWP和SWPB时需要注意:
- PC不能作为其中的任何寄存器
- 基址寄存器Rn不应该与源寄存器Rm和目的寄存器Rd相同,但是Rm和Rd可以相同
- 寄存器位置不可以为空,必须满足3个寄存器
分支指令
- 分支指令用于实现程序流程的跳转,这类指令可以用来改变程序的执行流程,或者调用子程序
- 程序流程跳转的两种办法:一是使用分支指令,二是直接往PC寄存器写地址值
分支指令B
机器编码格式如图
- cond:表示指令执行的条件
- L:L=1带返回的分支,L=0普通分支
- Label:表示偏移量,是一个24位有符号立即数
B {<cond>} label
B指令是最简单的分支指令,直接跳转到label地址执行,即PC=lablel
label是一个偏移量,不是绝对地址,它的值由汇编器自动计算
带返回的分支指令BL
BL {<cond>} label
- BL指令在跳转前,将当前PC内容保存到R14(LR)中,因此,可以将R14内容恢复到PC中,跳转到之前的位置继续执行
- 该指令用于实现子程序的调用
带状态切换的分支指令BX
- cond:指令执行的条件
- op:op=0是BX指令,op=1是BLX指令
BX {<cond>} Rm
- BX指令跳转到所指定的目标地址,并实现状态的切换,Rm是一个表达目标地址的寄存器
- 当Rm最低位为1时,强制程序从ARM指令状态,转换到Thumb指令状态
- 当Rm最低位为0时,强制程序从Thumb指令状态,转换到ARM指令状态
带返回和状态切换的分支指令BLX
BLX {<cond>} label | Rm
- BLX指令跳转到指定的目标地址,并实现状态切换,同时将PC保存到R14
- 其目标地址可以是一个符号地址,或者是一个寄存器Rm
- 当子程序使用Thumb指令集,调用者使用ARM指令集,可以通过BLX指令实现子程序调用与状态切换
- 子程序的返回可以将R14复制到PC中
程序状态寄存器访问指令
ARM微处理器中的程序状态寄存器不属于通用寄存器,ARM专门用它设立了两条访问指令,用于在程序状态寄存器和通用寄存器之间传输数据
MRS
- cond:指令执行的条件
- R:用来区别CPSR(R=0)和SPSR(R=1)
- Rd:表示目的寄存器,Rd不允许为R15
MRS {<cond>} <Rd>, <CPSR | SPSR>
- MRS指令用于将程序状态寄存器的内容,传送到通用寄存器中
- 该指令通常在以下情况使用:
- 异常处理、进程切换时,需要保存状态寄存器的值
- 需要改变程序状态寄存器的值时,可以先读出,修改后再写回
MSR
- cond:指令执行的条件
- R:用来区别CPSR(R=0)和SPSR(R=1)
- Field_mask:域屏蔽
- immed:8位立即数
- Rm:操作数寄存器
MSR {<cond>} <CPSR | SPSR>_<fields>,<Rm #immed >
- MSR指令用于将操作数的内容,传送到程序状态寄存器的特定域中
- 状态寄存器是指CPSR或SPSR,一般是当前工作模式下的状态寄存器
- 操作数可以是通用寄存器Rm或立即数 #immed
- 域用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器分为4个域
位[31:24]:条件标志位域,用f表示
位[24:16]:状态位域,用s表示
位[16:8]:扩展位域,用x表示
位[8:0]:控制位域,用c表示
位域的表示方法:CPSR或SPSR后,使用下划线,位域必须小写,可随意组合,使用注意:
- 只有特权模式下,才可以改变处理器模式和设置中断
- 程序状态寄存器中的T位用于指示ARM状态和Thumb状态,但程序不能修改T位实现转换,任何时候不可修改T位
- 不可以使用R15作为目标寄存器
协处理器指令
- ARM微处理器可支持16个协处理器,用于各种协处理操作
- 在程序执行的过程中,协处理器只执行针对自身的协处理指令,忽略ARM处理器和其它处理器的指令
CDP协处理器数据处理指令
- cond:指令执行的条件
- opcode1/opcode2:协处理器将执行的操作
- CRm/CRn:存放操作数的协处理器寄存器
- CRd:作为目的寄存器的协处理器寄存器
- p:协处理器编号,0≤p≤15
CDP {<cond>} <p>, opcode1, CRd, CRm, CRn {, opcode2}
- ARM处理器通过CDP指令通知ARM协处理器p,要求其在寄存器CRn和CRm上进行操作op1,并把结果放在CRd中,可以使用op2提供有关的补充信息
- 若完成不了,则产生未定义指令异常
- 指令中的所有寄存器均为协处理器寄存器,操作由协处理器完成,指令不涉及ARM处理器的寄存器和存储器
LDC协处理器数据加载指令
- cond:指令执行的条件
- P U W:用于区别不同的地址模式
- N:数据的大小(依赖于协处理器)
- Op:用于区别LDC指令(op=1)还是STC指令(op=0)
- Rn:ARM处理器中作为基地址的寄存器
- CRd:作为目的寄存器的协处理器寄存器
- P:协处理器编号,0≤p≤15
LDC {<cond>} {L} <p>, <CRd>, <addr>
- LDC指令将addr所表示的存储器中的字数据,传送到目的寄存器CRd中
- 若协处理器不能完成传送操作,则产生未定义指令异常
- {L} 选项表示指令为长读取操作,例如用于双精度的传输
- addr为存储器的地址表达式,可表示为[Rn,offset],其中Rn表示基址寄存器,是ARM中的寄存器,offset表示偏移量,是8位无符号数,addr有如下几种表达式:
- 偏移offset为0,如[R6]
- 前索引立即数偏移,[R0, #0x04]
- 后索引立即数偏移,[R4],#0x08
STC协处理器数据存储指令
STC {<cond>} {L} <p>, <CRd>, <addr>
STC指令用于将寄存器CRd的字数据,传送到addr表示的存储器中
MCR ARM处理器寄存器到协处理器存储器的数据传送指令
- cond:指令执行的条件
- op1,op2:协处理器将执行的操作
- op:op=0表示MCR指令,op=1表示MRC指令
- CRm、CRn:存放操作数的协处理器寄存器
- Rd:ARM处理器中作为源或目的的寄存器
- P:协处理器编号,0≤p≤15
MCR {<cond>} <p>, op1, Rd, CRm, CRn{, op2}
- 指令用于将ARM寄存器Rd中的数据传送到协处理器CRm、CRn中
- op1和op2是协处理器将要执行的操作
- Rd为源寄存器,是ARM的寄存器,CRm、CRn是目的寄存器,是协处理器的寄存器
MRC 协处理器寄存器到ARN处理器寄存器的数据传送指令
MRC {<cond>} <p>, op1, Rd, CRm, CRn{, op2}
- MRC指令用于将协处理器中的数据传送到ARM处理器寄存器中
- op1和op2是协处理器将要执行的操作
- Rd为源寄存器,是ARM的寄存器,CRm、CRn是目的寄存器,是协处理器的寄存器
软件中断指令
- ARM指令集中的软件中断指令是唯一一条不适用寄存器的ARM指令,也是一条可以条件执行的指令
- ARM指令在用户模式下局限很大,访问一些特殊资源时,使用软件控制的唯一可行办法就是使用SWI(software interrupt)
SWI软件中断指令
- cond:指令执行的条件
- swi_num:24位立即数,表示调用类型
SWI {<cond>} SWI_number
- SWI指令用于产生软件中断,以便用户程序能够调用操作系统的例程
- 软件中断进入的是管理模式,中断后会改变程序状态寄存器中的相关位
SWI的调用
从用户模式切换到管理模式时,ARM硬件实现以下操作:
- 把中断处的地址值(PC-4)复制到R14,保留中断的地址
- 把CPSR复制到SWI模式的SPSR,保存状态寄存器的值
- 把状态寄存器的模式改为管理模式
- 把中断向量0x00000008赋值给PC
- 禁止IRQ中断,使CPSR[7] = 1
中断时,一般有两种方法进行功能号的传递:
- 把准备传递的参数通过寄存器进行传递:对R0赋值,SWI参数为0
- 用SWI指令传递中断号:SWI带不为0的参数
ARM伪指令
ARM伪指令不是ARM指令集中的指令,只是为了方便编程而定义的,伪指令可以像其他ARM指令一样使用,但是在编译时,将被等效替代
ADR小范围的地址读取伪指令
ADR {cond} Rm, addr
- 将基于PC相对的地址值或基于寄存器相对便宜的地址值读取到寄存中
- 编译时ADR被替换为合适的指令,如果不能替换,则编译失败
- Rm表示要加载的目的寄存器
- addr为地址表达式,当地址值是非字对齐时,取值范围-255 ~ 255字节之间,当地址值字对齐时,取值范围-1020 ~ 1020 字节之间,对于基于PC相对偏移的地址值时,给定范围是相对当前指令地址后两个字处
ADRL中等范围的地址读取伪指令
ADRL {cond} Rm, addr
- ADRL相对于ADR可以读取跟大范围的地址
- 当地址值是非字对齐时,取值范围-64 ~64KB之间,当地址值字对齐时,取值范围-256 ~ 256KB之间
LDR大范围的地址读取伪指令
LDR {cond} Rm, =addr
- 用于加载32位立即数或一个地址值到指定寄存器
- 与ARM指令相比,伪指令LDR的参数有“=”
NOP空操作伪指令
NOP
编译时替换为空操作,比如MOV R0, R0,一般用于延时
Thumb指令集
概述
- 为兼容数据总线宽度为16位的应用系统,ARM体系结构除了支持效率很高的32位ARM指令集外,同时支持16位的Thumb指令集
- 它是ARM指令集的子集,允许编码长度为16位,多用于存储器受限的系统中
Thumb指令寄存器的使用
- 在Thumb状态下,不能直接访问所有的寄存器,只有寄存器R0R7是可以被任意访问的,寄存器R8R12只能通过MOV ADD CMP等指令访问
- CMP指令和所有操作R0~R7的数据处理指令都会影响CPSR中的条件标志
- 没有与MSR MRS等价的Thumb的指令
- 为了改变CPSR和SPSR,只能切换到ARM状态
ARM-Thumb交互
- ARM-Thumb交互是指对汇编语言和c/c++语言中的ARM和Thumb代码进行连接的办法
- 它进行两种状态(ARM Thumb)的切换
- 在进行切换时,有时要使用额外的代码,这些代码称为胶合(veneer)
数据处理指令
数据处理指令可以操作寄存器中的数据
单寄存器加载和存储指令
Thumb指令集支持寄存器的加载和存储
多寄存器加载和存储指令
Thumb指令集的多寄存器加载和存储指令,是ARM指令集的多寄存器加载和存储指令的简化形式
堆栈指令
Thumb的堆栈操作与等效的ARM指令不同,因为它们使用更传统的POP和PUSH
软件中断指令
与ARM指令集中软件中断类似,Thumb软中断指令SWI也产生中断异常
Thumb伪指令
Thumb伪指令不是Thumb指令集中的指令,类似于ARM伪指令
ADR小范围地址读取
ADR Rm, addr
地址偏移量必须是正数,且小于1kb
LDR大范围地址读取
LDR Rm, =addr
用于加载32位立即数或一个地址值到指定寄存器
NOP空操作
一般用于延时操作
最后
以上就是俏皮飞机为你收集整理的【ARM汇编】第三章:ARM指令系统指令基础ARM汇编语言ARM指令的寻址方式数据处理指令数据加载与存储指令分支指令程序状态寄存器访问指令协处理器指令软件中断指令ARM伪指令Thumb指令集Thumb伪指令的全部内容,希望文章能够帮你解决【ARM汇编】第三章:ARM指令系统指令基础ARM汇编语言ARM指令的寻址方式数据处理指令数据加载与存储指令分支指令程序状态寄存器访问指令协处理器指令软件中断指令ARM伪指令Thumb指令集Thumb伪指令所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复