第三章 ARM汇编指令集
(汇编)指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。
(汇编)伪指令本质上不是指令(只是和指令一起写在代码中),他是由编译器环境提供,目的是用来指导编译过程。
1、寻址方式
8种寻址方式
◾寄存器寻址 mov r1, r2
◾立即寻址 mov r0, #0xff
◾寄存器移位寻址 mov r0,r1,lsl #3
◾寄存器间接寻址 ldr r0,[r2]
◾基址变址寻址 ldr r1,[r2,#4]
◾多寄存器寻址 ldmia r1!, {r2-r7,r12}
◾堆栈寻址 stmfd sp!, {r2-r7,lr}
◾相对寻址 beq flag
2、指令后缀
统一指令经常附带不同后缀,变成不同的指令
◾B(byte) 功能不变,操作长度变为8位
◾H(half word)功能不变,操作长度变为16位
◾S(signed)功能不变,操作数变成有符号数
◾S(S标志)功能不变,影响CPSR标志位更新
3、CPSR
CPSR是保存系统状态的寄存器。
4、条件执行后缀
ARM指令,支持条件执行,当条件满足条件,指令才会执行,否则该指令,不会被执行。
5、比较指令
比较指令用来比较2个寄存器中数据是否一致,比较指令会影响CPSR的标志位。
Cmp : 两个寄存器数据一样, 标志位Z为1
cmn : 判断两个数是否互补
tst : 测试某些位是否为0,为0,Z为1。Tst r0,#0xf 判断r0的bit0-bit3是否全为0
teq : 两个数异或
6、CPSR访问指令
通过MRS,可以访问CPSR,通过MSR,可以设置CPSR。
7、跳转指令
B 直接跳转
Bl 跳转,保存返回地址
Bx 跳转同时切换ARM/thumb模式。
8、访存指令
单个字/半字/字节访问 ldr,ldrb,ldrh/str,strb,strh
多字批量访问 ldm/stm
swp r1, r2, [r0] 内存和寄存器互换指令 r0的内存地址数据读取到r1中,并把r2的数据写入到r0的内存地址
swp r1, r1, [r0] 实现了r0的内存地址数据和r1寄存器数据互换
9、软中断指令
swi (software interrupt)
软中断指令用来实现操作系统中系统调用
10、多寄存器访问指令
这一类指令,可以从内存同时读取多个数据到寄存器,或者将多个寄存器值写入到内存,当批量读取或写入内存时,使用这一类指令,效率高。
stmia sp, {r0 – r12}
将r0存入sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后地址再+4(指向0x30001008),将r2存入该地址······直到r12内容放入(0x3000130),指令完成。
一个访存周期同时完成13个寄存器对一段地址空间的写操作。
ldmia sp, {r0 – r12}
将sp指向的内存处(假设为0x30001000)的数据写入到r0中;然后地址+4(即指向0x30001004),将地址数据写入到r1;然后地址再+4(指向0x30001008),将地址数据写入到r2······直到(0x3000130)地址数据写入到r12中,指令完成。
一个访存周期同时完成13个寄存器对一段地址空间的读操作。
8种后缀
◾ia(increase after)先传输,再地址+4
◾ib(increase before)先地址+4,再传输
◾da(decrease after)先传输,再地址-4
◾db 先地址-4,再传输
◾fd(full decrease)满递减堆栈
◾ed(empty decrease)空递减堆栈
◾fa(·······) 满递增堆栈
◾ea(·······)空递增堆栈
11、^符号作用
在目标寄存器中有pc时,会同时将SPSR写入到CPSR
如指令 ldmfd sp!, {r0 – r6, pc}^, 当更新PC后,会将SPSR回复到CPSR。
12、GNU伪指令
在写汇编程序的时候,会使用一些伪指令,这些伪指令不是ARM指令,而是编译器提供的指令。
.global _start 定义全局标号,外部可以使用这个标号
.section .text 指定当前的段为代码段
.ascii .byte .short .long .word .quad .float .string 定义数据
.align 指定地址对齐
.equ 定义宏,类似于C中宏定义
.balignl 16, 0xdeadbeef
B表示位填充, align 表示要对齐, l表示long,以4字节为单位填充;16表示16字节对齐; 0xdeadbeef是用来填充的原料
如以下:
0x0000_0008: .balignl 16, 0xdeadbeef
0x0000_000c: 保存0xdeadbeef
0x0000_0010: 下一条数据
如以下:
0x0000_0008: .balignl 32, 0xdeadbeef
0x0000_000c: 保存0xdeadbeef
0x0000_0010: 保存0xdeadbeef(继续填充,直到32字节)
0x0000_0014: 下一条数据
.arm / .code32 声明以下的代码是ARM指令
.thumb /.code16 声明以下的代码是thumb指令
13、ldr和adr
ldr和adr指令,都可以获取地址值。
ldr 大范围的地址加载指令
adr 小范围的地址加载指令
adrl 中等范围的地址加载指令
adr和ldr
◾adr编译时会被一条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理
◾adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里
◾ldr加载的地址和链接时给定的地址有关,由链接脚本决定。
因此,adr加载的是相对地址(运行时决定),ldr加载的是绝对地址(链接时决定),因此可以通过adr和ldr加载的地址来判断当前程序是否在链接时指定的地址运行。
系列其他篇
原文首发于骏的世界博客
作者:卢骏.
更多Arm技术相关的文章请关注Arm技术博客极术专栏,每日更新。