汇编语言得玩转

时间:2022-03-02 01:21:52

一、ARM汇编编程概述

1.1为什么需要使用汇编
原因:1.汇编执行效率高 2.没有C语言运行环境。有两种情况需要使用汇编语言:1.Bootloader、内核在初始化的时候,2.启动代码、对效率要求高的地方(C和汇编混合编程)
1.2ARM汇编分类
目前常用的ARM汇编指令有两种:
1.ARM标准汇编:适用于ARM公司的汇编器,适合在Windows平台下使用,如ADS中使用。
2.GNU汇编:适用于GNU交叉编译工具链中的汇编器,适合于Linux开发平台。
1.3汇编程序框架

.section .data      
<初始化的数据>
.section .bss
<未初始化的数据>
.section .text
.global _start
_start:
<汇编代码>

还有一种是没有section这个关键字。

二、ARM指令分类

2.1算术和逻辑指令
2.1.1 MOV : 传送
实例:MOV R0, R0
MOV从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器
2.1.2MVN : 传送取反的值
实例:MVN R0, #4 ; R0 = -5
MVN从另一个寄存器、被移位的寄存器、或一个立即数转载一个值到目的寄存器。不同之处是在传送之前被反转了,所以把一个取反的值传送到一个寄存器中。这个是逻辑非操作而不是算术操作,这个取反的值加1才是他的取负的值。
类似的指令还有SUB、ADD、AND、BIC
2.2 比较指令
2.2.1 CMP:比较
实例:CMP {条件} {P} (op 1), (op 2)
status = op_1 - op_2
status有三种结果:1-正数,2-负数,3-零。其结果不会保存到某个寄存器,而是会影响CPSR寄存器的[31:30]N、Z这两位。如果结果是负数则N置位,结果是零则Z置位.
2.2.2 TST:测试位
实例:TST {条件} {P} (op 1), (op 2)
status = op_1 AND op_2
op_1和op_2进行按位与,其结果不会存放任何目的寄存器,而是影响CPSR寄存器。如果结果等于零则Z置位为1.
2.3 跳转指令
2.3.1 B:分支
实例: B {条件} (地址)
B是最简单的分支。一旦遇到一个B指令,ARM处理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的R15的值的一个偏移量;而不是一个绝对地址。{这里的条件可以参考B的分支条件}。
2.3.2 BL:带连接的分支
实例:BL {条件} (地址)
在分支之前,在寄存器R14中装载上R15的内容。可以重现装载R14到R15中来返回到在这个分支之后的那个指令。
B和BL的区别:B 跳转到指定的指令处执行。BL 跳转执行,保存子程序地址并返回。
2.4 移位指令
2.4.1 LSL:逻辑左移
实例:Rx, LSL #n
接收Rx的内容并按’n’指定的数量向高有效位方向移位。最低有效位用零来填充。
2.4.2 ROR:循环右移
实例:Rx, ROR #n
循环右移类似于逻辑右移,但是把从右移出来的位放置到左侧,如果逻辑类指令中S位被设置,则同时放置到进位标志中,这就是位的‘循环’。
2.5 程序状态字访问指令
在访问CPSR和SPSR寄存器时不能直接更改里面的值,我们需要特殊的指令把他们里面的内容搬移到通用寄存器中,然后在进行修改里面的值,最后再把修改之后的值搬移会CPSR和SPSR中。
2.5.1 MSR :复制一个寄存器到PSR中
实例:MSR CPSR, R0 :复制 R0 到 CPSR中
MSR SPSR, R0 : 复制 R0 到 SPSR中
2.5.2 MRS :复制PSR到一个寄存器中
实例:MRS R0, CPSR : 复制 CPSR 到 R0 中
MRS R0, SPSR : 复制 SPSR 到 R0 中
2.6 存储器访问指令
直接可以操作内存中的数据
2.6.1 LDR : 装载
实例:LDR {条件} Rd, (地址)
把内存中的值装载到Rd寄存器中。
2.6.2 STR : 存储
实例: STR {条件} Rd, (地址)
把寄存器Rd中的值存储到内存中。

三、ARM伪指令

3.1 ARM机器码
汇编语言得玩转
汇编语言得玩转
机器码分析:
MOV R0, R1
对应的机器码是E1A00001(H) = 11100001101000000000000000000001(O)
下面就对照ARM指令集手册分析二进制的机器码
1110 00 0 1101 0 0000 0000 000000000001(O)
cond[31:28]表示指令中是否带有条件,查看opcode表可知
1110表示Always(unconditional)无条件
汇编语言得玩转
[27:26]没有用填充00
[25]表示shifter_operand是一个立即数还是一个寄存器,如果是0表示是寄存器中的值,1表示是一个立即数。对应上面是0正好跟这个符合
[24:21]表示区分不同的指令。1101正好对应MOV指令
汇编语言得玩转
[20]表示是否影响CPSR寄存器。0表示没有影响CPSR寄存器
[19:16]表示指定一个源操作数的寄存器。上面没有使用
[15:12]表示目的操作数编号。上面没有使用
[11:0]源操作数。R1中的值
3.2 定义类伪指令
伪/指令本身并没有所对应的机器码,它只是在编程的时候起作用,或者转化为其他的实际指令来运行。
常用的伪指令有:.global、.ascii、.byte、.word、.data、.equ、.align
.global:标明一个全局的符合
.data:定义数据段
.ascii、.byte、.word:定义数据类型
.equ:定义宏变量
.align:对齐方式,是程序按照某种方式对齐
3.3 操作类伪指令
源操作数的大小是有范围限制的,当源操作数超过其范围就会用到伪指令。常用的操作类伪指令有nop、ldr(等以后在具体程序中说明)

四、协处理器访问指令

4.1什么是协处理器
协处理器用于执行特定的处理任务,如:数学协处理器可以控制数字处理,以减轻处理器的负担。ARM可支持多达16个协处理器,其中CP15是最重要的一个。
汇编语言得玩转
如何访问寄存器呢?
汇编语言得玩转
注意:协处理器我目前还没有用过,等以后具体操作了在详细说明!
总结:汇编需要主要用于Bootloader中第一步的设计,那是时候还没建立C语言的运行环境。处理器这部分主要用于程序出现异常时可以跟踪到寄存器内部去查找问题。