一、汇编指令
1.1 指令与伪指令
汇编的指令
指令是CPU机器指令的助记符,编译后会得到一串二进制机器码,由CPU执行
汇编的伪指令
伪指令本质上不是指令,它是编译器环境提供用来指导编译过程,编译后伪指令不会生成机器码
伪指令的意义在于指导编译过程
区别
经过编译后会不会生成二进制机器码
1.2 gun汇编中的符号
符号 | 作用 |
---|---|
@ | 用来做注释,可以在行首也可以在代码后面同一行直接跟,和C语言中 // 类似 |
: | 以冒号结尾的是标号 |
. | 点号在gnu汇编中表示当前指令的地址 |
# | 立即数前面要加#或$,表示这是个立即数 |
1.3 gun汇编中的伪指令
1、ARM中有一个ldr指令,还有一个ldr伪指令,一般都使用ldr伪指令而不用ldr指令
2、adr与ldr:
① adr编译时会被sub或add指令替代,
② ldr编译时会被mov指令替代或者文字池方式处理
③ adr总是以PC为基准来表示地址,指令本身和运行地址有关,用来检测程序当前的运行地址在哪里
④ ldr加载的地址和链接时给定的地址有关,由链接脚本决定
符号 | 作用 |
---|---|
ldr | 大范围的地址加载 |
adr | 小范围的地址加载 |
adrl | 中等范围的地址加载 |
nop | 空操作 |
.global _start | 给_start外部链接属性 |
.section .text | 指定当前段为代码段 |
.align 4 | 以16字节对齐 |
.balignl 16 | 16字节对齐填充 |
.end | 标识文件结束 |
.include | 头文件包含 |
.arm / .code32 | 声明以下为arm指令 |
.thumb / .code16 | 声明以下为thubm指令 |
.ascii .byte .short .long | 定义数据 |
.word.quad .float .string | 定义数据 |
二、不同风格的ARM指令
ARM官方的ARM汇编风格
指令一般用大写、 Windows中IDE开发环境(如ADS、MDK等)常用。
LDR R0, [R1]
GNU风格的ARM汇编
指令一般用小写字母、 linux中常用。
ldr r0, [r1]
三、ARM汇编的特点
3.1 LDR/STR架构
1、 ARM的CPU不能直接读取内存,需要先将内存加载到CPU通用寄存器中才能被CPU处理
2、 ldr(load register)指令将内存加载到通用寄存器
3、 str(store register)指令将寄存器内容保存到内存空间
4、 ldr/str组合用来实现 ARM CPU和内存之间数据的交换
3.2 8种寻址方式
寻址方式 | 例子 |
---|---|
寄存器寻址 | mov r1, r2 |
立即寻址 | mov r0, #0xFF00 |
寄存器移位寻址 | mov r0, r1, lsl #3 |
寄存器间接寻址 | ldr r1, [r2] |
基址变址寻址 | ldr r1, [r2, #4] |
多寄存器寻址 | ldmia r1!, {r2-r7,r12} |
堆栈寻址 | stmfd sp!, {r2-r7, lr} |
相对寻址 | beq flag flag: |
3.3 指令后缀
汇编指令中,同一指令经常附带不同后缀,变成不同的指令
经常使用的后缀有:
1、B(byte)功能不变,操作长度变为8位
2、H(half word)功能不变,长度变为16位
3、S(signed)功能不变,操作数变为有符号
4、S(S标志)功能不变,影响CPSR标志位
// B H SB SH
ldr ldrb ldrh ldrsb ldrsh
//mov和movsmovs r0, #0
3.4 条件执行后缀
操作码 | 条件码助记符 | 标志 | 含义 |
---|---|---|---|
0000 | EQ | Z=1 | 相等 |
0001 | NE | Z=0 | 不相等 |
0010 | CS/HS | C=1 | 无符号数大于或等于 |
0011 | CC/LO | C=0 | 无符号数小于 |
0100 | MI | N=1 | 负数 |
0101 | PL | N=0 | 正数或零 |
0110 | VS | V=1 | 溢出 |
0111 | VC | V=0 | 没有溢出 |
1000 | HI | C=1、Z=0 | 无符号数大于 |
1001 | LS | C=0、Z=1 | 无符号数小于或等于 |
1010 | GE | N=V | 有符号数大于或等于 |
1011 | LT | N!=V | 有符号数小于 |
1100 | GT | Z=0、Z=V | 有符号数大于 |
1101 | LE | Z=1、Z!=V | 有符号数小于或等于 |
1110 | AL | 任意 | 无条件执行(指令默认条件) |
1111 | NV | 任意 | 从不执行(不要使用) |
3.5 8种后缀
后缀 | 含义 |
---|---|
ia | 先传输,再地址+4 |
ib | 先地址+4,再传输 |
da | 先传输,再地址-4 |
db | 先地址-4,再传输 |
fd | 满递减堆栈 |
ed | 空递减堆栈 |
fa | 满递增堆栈 |
ea | 空递增堆栈 |
3.6 4种栈
空栈:栈指针指向空位,存入时可直接存入然后指针移动一格;取出时需要先移动一格才能取出
满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针
增栈:栈指针移动时向地址增加的方向移动的栈
减栈:栈指针移动时向地址减小的方向移动的栈
注意:操作栈时使用相同的后缀就不会出错
四、ARM汇编的常用指令
4.1 数据处理指令
指令类型 | 指令 |
---|---|
数据传输指令 | mov mvn |
算术指令 | add sub rsb adc sbc rsc |
逻辑指令 | and orr eor bic |
比较指令 | cmp cmn tst teq |
乘法指令 | mvl mla umull umlal smull smlal |
前导零计数 | clz |
4.2 CPSR访问指令
CPSR寄存器比较特殊,需要专门的指令进行访问
指令类型 | 指令 |
---|---|
mrs | 读取psr |
msr | 写入psr |
4.3 跳转指令
指令 | 作用 |
---|---|
b | 直接跳转(跳转后不返回) |
bl | 跳转前把返回地址放入lr中,用于函数调用返回 |
bx | 跳转同时切换到ARM模式,用于异常处理的跳转 |
4.4 访存、软中断指令
ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢
stm/ldm每周期可以批量读取、写入内存
指令 | 作用 |
---|---|
ldr/str | 单个字/半字/字节访问 |
ldm/stm | 多字批量访问 |
swi(software interrupt) | 软中断指令,用来实现操作系统中系统调用 |
4.5 协处理器操作指令
1、SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定任务
2、ARM设计上支持16个协处理器,一般SoC只实现其中的CP15
3、协处理器和MMU、 cache、 TLB等处理有关
4、功能上和操作系统的虚拟地址映射、cache管理等有关
指令 | 作用 |
---|---|
mrc | 用于读取CP15中的寄存器 |
mcr | 用于写入CP15中的寄存器 |
五、ARM汇编符号的作用
5.1 ! 的作用
ldmia r0 , {r2 - r3}
ldmia r0! , {r2 - r3}
!的作用:
r0的值在ldm过程中发生的增加或者减少最后写回到r0去
也就是说ldm时会改变r0的值。
5.2 ^ 的作用
ldmfd sp!, {r0 - r6, pc}
ldmfd sp!, {r0 - r6, pc}^
^ 的作用:在目标寄存器中有pc时,会同时将spsr写入到cpsr,一般用于从异常模式返回