【ARM汇编】第三章:ARM指令系统

文章目录

指令基础

指令周期和时序

时钟信号:是一个周期性的脉冲信号
时钟周期(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处理指令、协处理器指令、异常产生指令
[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ULuzORYx-1587825834457)(en-resource://database/892:1)]

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出栈

数据处理指令

数据处理指令对存放在寄存器中的数据进行操作,分为

  • 数据传送指令
  • 算术指令
  • 逻辑运算指令
  • 比较指令
  • 乘法指令
    [败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EhTlPnIy-1587825834458)(en-resource://database/894:1)]

ARM数据处理指令机器编码格式如下:
[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UC4P9enj-1587825834460)(en-resource://database/896:1)]

  • 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位组成一个循环右移
[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KUdPGkn6-1587825834462)(en-resource://database/898:1)]

算术指令

主要是加减法,实现两个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处理器是加载/存储体系结构的处理器,对于存储器的访问只能通过加载和存储指令实现

[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7yXnMFgE-1587825834463)(en-resource://database/900:1)]

数据加载与存储指令概述

数据加载与存储的方向问题

  • 数据加载(load)与存储(store)用于在存储器和处理器之间传递数据
  • load用于把内存的数据,装入寄存器
  • store用于把寄存器的数据,装入内存
  • 有三种类型:单寄存器、多寄存器、交换指令

数据加载与存储指令的寻址

基本格式为:

option {<cont>} Rd,addr
  • option为指令代码,如LDR表示将存储器中的数据加载到寄存器
  • addr为寄存器地址表达式,可以用基址寄存器+偏移量得到

addr有以下几种形式

  • 立即数:一个无符号的数值
  • 寄存器:寄存器的值
  • 寄存器移位:由通用寄存器和立即数组成,根据立即数移位,生成地址偏移量,再结合基址寄存器,如:
  1. LDR R3, [R2, R4, LSL #2]
  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位数据的加载/存储指令
[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ST8tDh84-1587825834464)(en-resource://database/902:1)]

各个位的含义:

  • 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位)加载/存储指令

[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oJQDyCKJ-1587825834464)(en-resource://database/904:1)]

各个位的含义:

  • 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

[,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5GEf1r3-1587825834465)(en-resource://database/906:1)]

图中各位含义如下:

  • 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指令依据其后参数不同,寻址方式差别很大
[外,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mv3m8rYq-1587825834466)(en-resource://database/908:1)]

堆栈操作

堆栈

  • 堆栈就是在RAM存储器中开辟的,一个特定的存储区域,遵循先进后出的原则
  • 堆栈栈底固定,栈顶浮动,堆栈指针SP(R13)指向栈顶
  • 当32位数据入栈时,SP的值减4

堆栈操作

建栈

建栈就是规定堆栈底部在RAM存储器中的位置,用户可以通过LDR命令设置SP的值

进栈

  • ARM体系结构使用多寄存器指令完成堆栈操作
  • 出栈LDM,入栈STM
  • LDM和STM指令往往结合下面的一些参数实现堆栈的操作
  1. FD满递减堆栈
  2. ED空递减堆栈
  3. FA满递增堆栈
  4. EA空递增堆栈

在使用堆栈时,需要确定它是向上生长(递增ascending),还是向下生长(递减descending)
满堆栈(full stack):指堆栈指针SP(R13)指向堆栈的最后一个数据项的地址
空堆栈(empty stack):指SP指向堆栈的第一个没有使用的地址

ARM制定了一个标准:ARM-Thumb过程调用标准(ATPCS),定义了例程如何被调用,寄存器如何分配
其中,堆栈被定义为满递减堆栈,因此ARM汇编中,堆栈的操作是LDMFD和STMFD

出栈

POP操作出栈,ARM中使用LDMFD实现出栈操作

交换指令

数据交换指令能在存储器和寄存器之间交换数据,它是加载与存储指令的特例,交换是原子操作

[外链败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQOE8hSV-1587825834467)(en-resource://database/910:1)]

  • 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寄存器写地址值
    [外,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6QeN4LYu-1587825834468)(en-resource://database/914:1)]

分支指令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指令用于将程序状态寄存器的内容,传送到通用寄存器中
  • 该指令通常在以下情况使用:
  1. 异常处理、进程切换时,需要保存状态寄存器的值
  2. 需要改变程序状态寄存器的值时,可以先读出,修改后再写回

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有如下几种表达式:
  1. 偏移offset为0,如[R6]
  2. 前索引立即数偏移,[R0, #0x04]
  3. 后索引立即数偏移,[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空操作

一般用于延时操作请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

猜你喜欢

转载自blog.csdn.net/whitefish520/article/details/105758787