ARM汇编框架
xx.s
.text @表示当前为代码段
.global _start @将_start定义成全局符号
_start: @汇编的入口
MOV R1,#1
MOV R2,#2
MOV R3,#3
.end @汇编的结束
ARM汇编概述
汇编中的符号
- 指令:能够编译成一条32位的机器码,并且能被CPU识别和执行。
- 伪指令:本身不是指令,编译器可以将其替换成若干条指令
- 不会生成指令,只是在编译阶段告诉编译器怎么编译,类似C语言的条件编译
ARM的指令
- 数据处理指令:进行数学运算、逻辑运算
- 跳转指令:实现程序的跳转,本质就是修改PC寄存器
- Load/Store指令:访问(读写)内存
- 状态寄存器传送指令:用于访问(读写)CPSR寄存器
- 软中断指令:触发软中断
- 协处理器指令:操作协处理器的指令
指令基本格式
<操作码> <目标寄存器>, <第一操作寄存器>, <第二操作数>
ARM指令集
数据处理指令
.text
.global _start
_start:
@ 数据搬运指令
MOV R1,#1 @把一个数搬运到一个寄存器
MOV R2,R1 @从一个寄存器搬运到另一个寄存器
MVN R0,#0xFF @按位取反再搬运
@ MOV PC,#0 @搬运一个数到PC寄存器,程序会跳转
@ 立即数,本质是包含在指令中的数,属于指令的一部分
@ 所以立即数不能太大,范围在0-255之间。
@ MOV R0, #0x12345678 @0x12345678这不是立即数,不能被编译成功
@ 0xFFFFFFFF这不是立即数,但是能被编译成功
@ 这一条是伪指令,编译器会把他替换成同样效果的指令。
MOV R0, #0xFFFFFFFF @ MVN R0,#0x00
@ 加法指令
ADD R3,R1,R2 @ R3 = R1 + R2
ADD R3,R2,#5 @ R3 = R2 + 5
@ 不合法的指令
@ ADD R3,#5,R2 @第一寄存器不能放数
@ 减法指令
SUB R1,R2,R3 @ R1 = R2 - R3
RSB R1,R2,#3 @ R1 = 3 - R2 逆向减法指令
@ 乘法指令
MUL R1,R2,R3 @ R1 = R2 * R3
@ 按位与
AND R1,R2,R3 @ R1 = R2 & R3
@ 按位或
ORR R1,R2,R3 @ R1 = R2 | R3
@ 按位异或
EOR R1,R2,R3 @ R1 = R2 ^ R3
@ 移位
LSL R1,R2,R3 @ R1 = R2 << R3, R2左移R3位,给R1
LSR R1,R2,R3 @ R1 = R2 >> R3, R2右移R3位,给R1
@ 位清零
BIC R1, R2, #0xF
@ 第二操作数(0xF)中的哪一位,就将第一操作寄存器中的哪一位清零,然后放入目标寄存器
@ 数据运算指令的格式扩展
MOV R1,R2,LSL #1 @ R1 = (R2 << 1)
@ 数据运算指令对条件位的影响,CPSR NZVC
@ 默认情况下数据运算不会对条件为产生影响,当指令加后缀S后可以影响
MOV R1,#3
SUBS R2,R1,#5
@ 两个64位的数据做加法运算
@ 0x00000001 FFFFFFFF
@ 0x00000002 00000005
MOV R1,#0xFFFFFFFF
MOV R2,#0x00000001
MOV R3,#0x00000005
MOV R4,#0x00000002
ADDS R5,R1,R3 @溢出时条件位溢出位会自动置1
ADC R6,R2,R4 @ R6 = R2 + R4 + 'C',在执行的过程中,会把条件位的溢出位加上
@ 带借位的减法指令
@ 0x00000002 00000001
@ 0x00000001 00000005
MOV R1,#0x00000001
MOV R2,#0x00000002
MOV R3,#0x00000005
MOV R4,#0x00000001
SUBS R5,R1,R3
SBC R6,R2,R4
@ 本质: R6 = R2 - R4 - '!C',即执行的过程中,会把条件位的溢出位取反再减
stop:
B stop
.end
跳转指令
.text
.global _start
_start:
@ 方式一:直接去修改PC寄存器的值
@ MOV R1,#1
@ MOV R2,#2
@ MOV R3,#3
@ MOV PC,#0x18
@ MOV R4,#4 @ 这条指令被跳过
@ MOV R6,#6
@ 方式二:通过跳转指令B
@ 本质也是修改PC
@ MOV PC,LR 跳转失败,它会跳转回:跳转指令,因为B跳转指令,没有保存返回地址给LR
@MAIN:
@ MOV R1,#1
@ B FUNC
@ MOV R2,#2
@ MOV R3,#3
@FUNC:
@ MOV R4,#4
@ MOV PC,LR
@ 方式三:通过跳转指令BL
@ 跳转的同时,会修改CPSR的跳转状态位的值,并且保存返回的地址给LR
MAIN:
MOV R1,#1
MOV R2,#2
BL FUNC
MOV R3,#3
MOV R4,#4
FUNC:
MOV R5,#5
MOV PC,LR
stop:
B stop
.end
ARM条件码(不算指令)
@条件码
.text
.global _start
_start:
MAIN:
MOV R1,#1
MOV R2,#1
@比较指令
CMP R1,R2 @没有目标寄存器,结果自动存储在状态寄存器CPSR的NZCV
@本质就是一条减法指令,SUBS,只是没有将运算的结果存入寄存器
@如果R1==R2,Z=1,产生0
@如果R1!=R1,Z=0
@如果R1<R2,Z=0且C=0,产生了借位
@如果R1<=R2,C=0或Z=1
@如果R1>R2,C=1且Z=0
@如果R1>=R2,C=1或Z=1
BEQ FUNC @EQ是一个条件码助记符后缀,大多数指令都可以加后缀
MOV R3,#3 @该条指令会被跳过
FUNC:
MOV R4,#4 @程序会跳转到这里
.end
ARM条件码和助记符后缀
ARM内存访问指令
内存访问指令1
@内存访问指令
.text
.global _start
_start:
@ 写内存
MOV R1,#0xFFFFFFFF
MOV R2,#0x40000000 @0x40000000 是可读可写的内存地址
@STR R1,[R2] @把R1寄存器中的数据存储到R2指向的内存空间4个字节
STRB R1,[R2] @把R1寄存器中的数据存储到R2指向的内存空间
@ 读内存
LDR R3,[R2] @把R2指向的内存空间的数据读取到R3
.end
ARM指令的寻址方式
@ ARM寻址方式
.text
.global _start
_start:
@ 方式一:立即寻址
@ 回顾一下立即数,立即寻址即直接使用指令机器码中的立即数
MOV R1,#1
ADD R1,R2,#1
@ 方式二:寄存器取址
ADD R1,R2,R3
@ 方式三:寄存器移位寻址
MOV R1,R2, LSL #1
@ 方式四:寄存器间接寻址
STR R1, [R2]
@...还有很多,ARM一共九种
.end
内存访问指令2
@ 内存访问指令2
@ 基于ARM指令的寻址方式
@ 基址加变址寻址内存访问
.text
.global _start
_start:
MOV R1, #0xFFFFFFFF
MOV R2, #0x40000000
MOV R3, #4
@ 前索引:
@STR R1, [R2,#4]
@ 将R1寄存器中的数据写入到R2+4指向的内存空间:0x40000004
@ R2的值并不会改变,对比自动索引
@STR R1, [R2,R3]
@ 将R1寄存器中的数据写入到R2+R3指向的内存空间:0x40000004
@STR R1, [R2,R3,LSL #1]
@ 将R1寄存器中的数据写入到R2+(R3<<1)指向的内存空间:0x40000008
@*****************************************************************
@ 后索引:
STR R1, [R2], #8
@ 将R1寄存器中的数据写入到R2指向的内存空间:0x40000000
@ 然后R2自增8
@ 自动索引:
STR R1, [R2,#8]!
@ 将R1寄存器中的数据写入到R2+8指向的内存空间:0x40000008
@ 然后R2自增8
.end
END