cortex-a8裸机系列:第三章 ARM汇编指令
1赞(汇编)指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。
(汇编)伪指令本质上不是指令(只是和指令一起写在代码中),他是由编译器环境提供,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。
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
指令后缀
Ø 统一指令经常附带不同后缀,变成不同的指令
Ø B(byte) 功能不变,操作长度变为8位
Ø H(half word)功能不变,操作长度变为16位
Ø S(signed)功能不变,操作数变成有符号数
Ø S(S标志)功能不变,影响CPSR标志位
条件执行后缀
比较指令:
比较指令用来比较2个寄存器中数据,比较指令不加后缀S,就会影响CPSR的标志位
cmp : 两个寄存器数据一样, 标志位Z为1
cmn : 判断两个数是否互补
tst : 测试某些位是否为0,为0,Z为1 tst r0, #0xf r0的bit0-bit3是否全为0
teq : 两个数异或,
CPSR访问指令
mrs 和 msr
跳转指令
B 直接跳转
Bl 跳转,保存返回地址
Bx 跳转同时切换到ARM模式。一般用于异常处理的跳转
访存指令
单个字/半字/字节访问 ldr/str
多字批量访问 ldm/stm
swp r1, r2, [r0] 内存和寄存器互换指令 r0的内存地址数据读取到r1中,并把r2的数据写入到r0的内存地址
swp r1, r1, [r0] 实现了r0的内存地址数据和r1寄存器数据互换
软中断指令
swi (software interrupt)
软中断指令用来实现操作系统中系统调用
多寄存器访问指令
• 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(·······)空递增堆栈
^作用:
• ldmfd sp!, {r0 - r6, pc}^
在目标寄存器中有pc时,会同时将SPSR写入到CPSR
总结:
l 批量读取或写入内存时要用ldm/stm指令
GNU伪指令
.global _start 给_start外部链接属性
.section .text 制定当前的段为代码段
.ascii .byte .short .long .word
.quad .float .string 定义数据
.align 4 以16字节对齐
.balignl 16, 0xabcdefgh 16字节对齐填充
.equ 类似于C中宏定义
.balignl 16, 0xdeadbeef
B表示位填充, align 表示要对齐, l表示long,以4字节为单位填充;16表示16字节对齐; 0xdeadbeef是用来填充的原料
0x0000_0008: .balignl 16, 0xdeadbeef
0x0000_000c: 保存0xdeadbeef
0x0000_0010: 下一条指令
.balignl 32, 0xdeadbeef
0x0000_0008: .balignl 32, 0xdeadbeef
0x0000_000c: 保存0xdeadbeef
0x0000_0010: 保存0xdeadbeef(继续填充,直到32字节)
0x0000_0014: 下一条指令
.arm / .code32 声明以下的代码是ARM指令
.thumb /.code16 声明以下的代码是thumb指令
ldr 大范围的地址加载指令
adr 小范围的地址加载指令
adrl 中等范围的地址加载指令
nop 空操作
ldr指令 ldr r0, #0xff
ldr伪指令 ldr r0, =0xff
adr和ldr
l adr编译时会被一条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理
l adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里
l ldr加载的地址和链接时给定的地址有关,由链接脚本决定。
因此,adr加载的是相对地址(运行时决定),ldr加载的是绝对地址(链接时决定),因此可以通过adr和ldr加载的地址来判断当前程序是否在链接时制定的地址运行