1 汇编程序概述
1.1 为什么使用汇编
(1)bootloader和Linux内核的初始化代码都需要汇编进行编写
(2)在对效率有特殊要求的地方需要使用汇编程序编写
1.2 ARM汇编分类
(1)ARM汇编标准:使用于ARM公司的汇编器,适合在Windows平台下使用,如ADS中使用
(2)GNU汇编:适用于GNU交叉编译工具链中的汇编器,适用于Linux开发平台
(3)ARM指令集手册链接:https://pan.baidu.com/s/1brav0Mb 密码:tm5g
1.3 汇编程序框架
.section .data
<初始化的数据>
.section .bss
<未初始化的数据>
.section .text
.global _start
_start:
<汇编代码>
1.4 汇编程序
start.S
.text
.global _start
_start:
mov r1, #1
mov r2, #2
mov r3, #3
Makefile
all:start.o
arm-linux-ld -Ttext 0x30000000 -o start.elf $^
%.o:%.S
arm-linux-gcc -g -o $@ $^ -c
clean:
rm *.o *.elf
2 指令分类学习
2.1算术逻辑指令
(1)mov:传送
将另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器
mov r1, #8
mov r2, r2
mov r3, #10
(2)mvn:传送取反的值
从另一个寄存器、被移位的寄存器、或一个立即数值装载一个值到寄存器。不同之处是在传送之前位被反转了,所以把一个值取反的值传送到一个寄存器中。这是逻辑非操作而不是算术操作,这个取反的值加1才是它的取负值。
mvn r1, #0b10
mvn r2, #5
mvn r3, r1
(3)sub:减法
用操作数one减去操作数two,把结果放置到目的寄存器中。操作数1是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器或一个立即值
mov r2, #4
sub r1, r2, #2
mov r0, #1
sub r3, r1, r0
(4)add:加法
把两个操作数加起来,把结果放置到目的寄存器中。操作数1是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即值
add r1, r2, #3
(5)and:逻辑与
将两个操作数进行逻辑与,把结果放置到目的寄存器中。操作数1是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器或一个立即值
mov r1, #5
and r2, r1, #0
mov r1, #5
and r2, r1, #1
(6)bic:位清除
在一个字中清除位的一种方法,与OR位设置是相反的操作。操作数2是一个32位位掩码(mask)。如果在掩码中设置了某一位,则清除这一位。未设置的掩码位指示此位保持不变
mov r0, #5
bic r0, r0, #0b1011
2.2比较指令
(1)cmp:比较
允许把一个寄存器的内容如另一个寄存器的内容或立即值进行比较,更改状态标识允许进行条件执行。它进行一次减法,但不存储结果,而是正确的更改标志。标志表示操作数1bi操作数2如何(大、小、等)。如果操作数1大于操作数2,则此后的有GT后缀的指令可以执行
mov r1, #2
cmp r1, #3
(2)test:测试位
类似于cmp,不产生放置到目的寄存器的结果。而是将两个操作数的操作结果反映到状态标志上。使用TST来检查是否设置了特定的位。操作数1是要测试的数据字,而操作数2是一位掩码。经过测试后,如果匹配则设置Zero标志,否则清除它。
mov r1, #0b101
tst r1, #0b001
mov r1, #0b101
tst r1, #0b10
2.3跳转指令
(1)b:分支
b是最简单的分支。一旦遇到一个b指令,ARM处理器将立即跳转到指定的地址,从那里继续执行。注意存储在分支指令中的实际值是相对于R15的值的一个偏移量;而不是一个绝对地址。它的值由汇编器来计算,它是24位有符号数,左移两位后有符号扩展为32位,表示的有效偏移为26位(+/-32M)。
mov r1, #6
mov r2, #5
cmp r1, r2
bgt branch1
add r3, r1, r2
b end
branch1:
sub r3, r1, r2
end:
nop
(2)bl:带连接的分支
bl是另一个分支指令。这就是分支之前,在寄存器R14中转载R15的内容。你可以重新装载R14到R15中来返回到在这个分支之后的那个指令,它是子例程的一个基本但强力的实现。
mov r1, #2
cmp r1, #1
bl func1
mov r1, #2
cmp r1, #3
func1:
mov r1, #2
mov r2, #3
mov pc, lr
2.4移位指令
(1)lsl:逻辑或算术左移
mov r1, #0b1
mov r1, r1, lsl #2
(2)ror:循环右移
mov r1, #0b11
mov r1, r1, ror #1
2.5程序状态字访问
(1)msr
msr cpsr, r0 ;复制r0到cpsr中
msr spsr, r0 ;复制r0到spsr中
msr cpsr_flg, r0 ;复制r0的标志位到cpsr中
msr cpsr_flg, #1 << 28 ;复制立即值标志位到cpsr中
(2)mrs
mrs r0, cpsr ;复制cpsr到r0中
mrs r0, spsr ;复制spsr到r0中
2.6存储器访问指令
(1)ldr
mov r1, #0x30000000
ldr r0, [r1] ;从0x30000000加载数值到r0
(2)str
mov r0, #0xff
mov r1, #0x30000000
str r0, [r1] ;将r0中的数据保存到0x30000000中
3 伪指令
3.1ARM机器码
3.2定义类伪指令
伪指令本身并没有所对应的机器码,它只是在编译的时候起作用,或者转化为其他的实际指令来运行
(1)global(定义全局变量)
(2)ascii(字符数据)
(3)byte(byte类型数据)
(4)word(word类型数据)
(5)data(定义数据)
(6)equ(定义宏)
(7)align(内存对齐)
.data
.align 4
hello:
.ascii "hello world"
bh:
.byte 0x1
ADD:
.word 0xff
.equ DA, 0x89
3.3操作类伪指令
mov操作符的立即数不能大于八位
ldr r0, =0x1ff
nop:空操作
4 协处理访问指令
4.1什么是协处理器
协处理器用于执行特定的处理任务,如:数学协处理器可以控制数字处理,以减轻处理器的负担。ARM可支持多达16个协处理器,其中CP15是非常重要的一个协处理器
CP15:系统控制协处理器
4.2协处理器的访问
(1)mcr
mcr{cond} P15, <Opcode>, <Rd>, <CRn>, <CRm>, {<Opcode2>} (L=0)
(2)mrc
mcr{cond} P15, <Opcode>, <Rd>, <CRn>, <CRm>, {<Opcode2>} (L=1)