ARM处理器汇编语言
Thumb状态切换
Thumb是16位指令的状态,可以使用16位指令,在进行切换时不会改变通用寄存器。
1 | ;现在是ARM指令集 |
16位Thumb地址一般位于奇数地址,所以跳转到1就进入了Thumb状态。
ARM工作模式切换
- 用户模式(Usr) 最普通的模式,资源和指令都受限
接下来的都是特权模式,可以对CPSR寄存器所有的位直接进行读写,而用户模式只能进行间接访问,如使用MRS指令将CPSR寄存器读入另一个寄存器。
系统模式(Sys) 特权模式,和用户模式共用一套寄存器但是权限更高
一般中断模式(IRQ) 通用的中断模式。IRQ异常响应时进入该模式
快速中断模式(FIQ) 用来处理优先级更高的中断 。FIQ异常响应时进入该模式
管理模式(SVC) CPU上电后默认的模式,用来做系统的初始化。系统复位或开机、软中断时进入到该模式
终止模式(ABT) 用户程序访问非法地址或者没有权限的地址时会进入。
未定义模式(UND) CPU在译码阶段不能够识别指令时会进入未定义模式
除了系统模式之外的5种特权模式,都是异常模式,异常模式只有在对应的异常发生时才会进入对应的模式。
在发生异常或者中断时,会有一个异常向量表或者中断向量表
+++
ARM寄存器
ARM一共有37个用户可见寄存器。
通用寄存器
- R0-R15 全模式下可用,其中R13是SP堆栈指针,R14是LR链接寄存器,R15是PC寄存器。
- R13_SVC、R14_SVC 管理模式专用寄存器
- R13_ABT、R14_ABT 终止模式专用寄存器
- R13_UND、R14_UND 未定义模式专用寄存器
- R13_IRQ、 R14_IRQ 中断模式专用寄存器
- R8_FIQ~R14_FIQ 快速中断模式专用寄存器,为了减少保护寄存器使用的时间而进行快速中断,直接多几个专用寄存器
状态寄存器
- CPSR当前程序状态寄存器,具有四位条件标志位,两位中断屏蔽(包含快速中断),一位当前工作状态。
最后五位是处理器工作模式。可以通过修改这五位进行工作模式的改变。
- CPSR的条件标志位:
N(Negative)是否为负数,N=1就代表结果为负数。
Z(Zero) Z=1表示运算的结果为零。
C(Carry) 加法指令中结果产生了进位,则C=1,反之则为0;减法指令中发生了借位则C=0,没有借位则为1;移位操作中,C是最后被移出的位。
V(Overflow) 在有符号数的加减法指令中,发生了符号位溢出,则V=1
- SPSR 分别对应五种异常模式,五种异常模式发生时可以用来记录CPSR的值,然后跳转到对应的异常模式后再使用CPSR。
在通用寄存器中R0-R12是完全的通用寄存器,不会被用来做特殊用途,所有的针对普通寄存器的指令都可以用于他们。
特殊寄存器的操作
- R13(SP)
往后看,有堆栈寻址的详细解释。堆栈往往用来实现函数跳转等操作。
- R14(LR)
执行BL、BLX指令时,会将PC-4(也就是要执行的下一条指令)的值自动记录到LR中,以便函数返回时将LR的值送回PC。但是在其他跳转时并不会自动记录,而是需要手动记录PC-4并存储。
一般可以这样用,也就是进行多重嵌套时,将LR压栈才能进入下一层嵌套,回到上一层嵌套就将寄存器出栈。
1 | STMFD SP!, {<registers>, LR} |
在处理异常时会将异常处理的返回地址放在对应模式下的LR寄存器中,但是这个返回地址应该是发生异常代码的下一条代码也就是PC+4,而在返回时应该去执行发生异常时正在执行的那条代码,因为那条代码并没有执行完,也就需要LR减去一个偏移量。在发生异常时,所有的跳转地址都是自动配置好的,不需要我们程序员来关心。
- R15(PC)
arm采用了三级流水线的结构,每一条指令的执行都会经过取指、译码、执行三个阶段,所以正在执行的代码往后两条指令是正在取指的代码,也就是说PC的值是当前正在执行的代码地址+8。
+++
ARM存储器体系
ARM的存储器支持大端模式和小端模式,默认是小端模式,也就是数据的低位存储在低地址内存单元中。
ARM处理器的ROM一般是FLASH,所有程序都存储在FLASH中,分为片内和片外两种。
ARM外设有统一的存储器映射编址,也就是访问对应的内存单元就可以访问特定外设的寄存器。这些内存地址不会被缓存。
STM32存储架构详解
+++
指令
ARM汇编指令遵循着相对固定的格式,如**< opcode > {< cond >} {S}< Rd >,< Rn > {,< OP2 >}**。
在其中
- opcode就是指令的操作码的助记符,例如ADD、MOV。
- cond是可选的条件执行,可以是EQ、NE等,满足条件则执行这条指令,条件就是一个CPSR的标志位。
- S也是一个可选的指令,就是S,表示是否刷新CPSR中的条件标志位。如果不使用就仍是原来的值。
- Rd、Rn分别代表第一个操作数和第二个操作数。
- OP2表示可选的第三操作数。
条件执行的条件码和对应的条件
- 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 无条件执行
- NV (ARMV3之前)从不执行
寻址
- 立即数寻址 arm汇编一般在立即数前面加上#,x86汇编不需要加
- 寄存器寻址 寄存器中的值直接作为操作数
1 | MOV r1, r2 ;将r2的值传到r1 |
- 寄存器间址 寄存器中的值作为内存地址,使用内存地址上的数据作为操作数。
1 | LDR r1, [r2] ;以r2中的内存地址加载数据进r1 |
- 基址寻址 使用寄存器中的地址生成新地址并且寻址,一般用于查表和数组访问。
1 | LDR R1, [R0, #2] ;(前变址,不修改基址)将R0中的值加2作为新地址 |
- 多寄存器寻址 STM/LDM指令完成多个寄存器的寻址
- 堆栈寻址 一般使用
STMFD SP! {R0-R3}
这样的指令进行寻址,最后SP指向栈顶元素。
常用指令
基础指令
- ADD 加法运算
- MOV 将一个值从一个寄存器传入另一个寄存器,或者将立即数传入一个寄存器
- SUB 减法运算
- RSB 反向减法运算
- ADC 带进位的加法运算,多用来进行大数的加法运算
- SBC 带借位的减法运算,减法会减去(1-C)进行借位操作,多用来进行大数的减法运算
- RSC 反向的带借位减法运算
- CMP 两数相减不保存结果只更新条件标志位
- CMN 两数相加不保存结果只更新条件标志位,常用于反向比较两个数,将其中一个数取负数进行比较
- MUL 将寄存器中的有符号数值相乘,并且只保留低32位到一个寄存器中
- MLA 和MUL类似但是将乘法的结果加上第三个寄存器的值
- UMULL 高精度的无符号数乘法,将结果存储到两个寄存器中
- UMLAL 高精度的无符号加和乘法,将结果加和到两个寄存器
- SMULL 高精度的有符号数乘法
- SMLAL 高精度的有符号加和乘法
位操作指令
- LSL 逻辑左移,空位补零
- LSR 逻辑右移,空位补零
- ASL 算数左移,空位补零
- ASR 算数右移,空位根据符号来补0或1
- ROR 循环右移,将最右侧的位移到最左侧
- RRX 循环右移,将CPSR中进位标志位放在最高位并将最低位移进进位标志位
- MVN 按位取反然后移入到通用寄存器
- AND 按位与
- ORR 按位或
- EOR 按位异或
- TST 按位与但是不保存结果只更新条件标志位
- TEQ 按位异或但是不保存结果只更新条件标志位
- BIC 按位清零
操作内存指令
当偏移地址为非字对齐时,会自动舍弃掉不满一个字的部分。半字同理
- LDR 从内存中取得数据传入寄存器
- STR 向内存中写入数据
- LDRB 从内存中读取一个字节写入寄存器并且空位补零
- STRB 向内存中写入一个字节
- LDRSB 从内存中读取一个字节写入寄存器并且空位按符号扩展
- LDRH 从内存中读取一个半字写入寄存器并且空位补零
- STRH 向内存中写入一个半字
- LDRSH 从内存中读取一个半字写入寄存器并且空位按符号扩展
- LDM 从内存中取得数据放到多个寄存器中
- STM 将多个寄存器的输入写入到内存中
1 | LDMIA R0, {R1-R5} ;以ro为基址读取五个数据单元加载到r1-r5 |
多寄存器寻址和堆栈寻址时,需要加上不同的后缀,向不同的寻址。
1 | IA 操作后递增 |
堆栈寻址时,堆栈指针指向的是栈顶元素就是满栈,堆栈指针指向栈顶元素的下一个元素就是空栈。
每入栈一个元素,栈指针SP都会往栈增长的方向移动一个存储单元。如果栈指针SP从高地址往低地址移动,那么这个栈就是递减栈;如果栈指针SP从低地址往高地址移动,那么这个栈就是递增栈,ARM处理器使用的一般都是满递减堆栈。
SP!代表着在操作之后递增SP指针。
1 | FA 满递增堆栈 |
MRS 从特殊寄存器中取数据到一个普通寄存器
MSR 从普通寄存器写入数据到一个特殊寄存器,这里的特殊寄存器也就是CPSR
BX,BLX,B,BL四种跳转指令,带L的会自动记录PC的值到LR中,带X的可以用于跳转Thumb模式。
伪指令
声明全局变量
1 | GBLA amount ;定义一个全局数字变量,默认值为0 |
声明局部变量
1 | LCLA amount ;定义一个局部数字变量 |
变量赋值
1 | amount SETA 10 ;给amount赋值10 |
定义寄存器列表
1 | RegList RLIST {R0-R4} ;将R0到R4定义为RegList |
数据定义
1 | LTORG ;在代码段最后或者无条件跳转后面或者子程序返回指令,定义数据缓冲池,存储常量信息 |
程序控制
1 | IF 逻辑表达式 |
1 | WHILE 逻辑表达式 |
其他伪指令
1 | ALIGN 4,3 ;4个字节对齐并且在上一个位置之后偏移3个字节 |
宏
1 | MACRO |
运算符
1 | x + y ;相加 |
- Title: ARM处理器汇编语言
- Author: HarderHeng
- Created at : 2024-04-08 08:32:37
- Updated at : 2024-06-05 22:33:37
- Link: https://harderheng.life/2024/04/08/ARM汇编语言/
- License: This work is licensed under CC BY-NC-SA 4.0.