第1课-ARM汇编编程概述
ARM标准汇编:适用于ARM公司的汇编器,适合在windows平台下使用,如ADS中使用
GNU汇编:适用于GUN交叉编译工具链中的汇编器,适合于Linux开发平台
汇编程序框架:
.section .data <初始化的数据> .section .bss <未初始化的数据> .section .text .global _start _start: <汇编代码>
建立汇编编程环境:汇编文件+链接脚本+Makefile+Ecplise
注意:
- 从SD卡启动,停留在uboot阶段,格式化整个内存
- 保存JLinkGDBServer一直在运行状态
第2课-ARM指令分类学习
算术和逻辑类指令
mov
MOV 从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器(只能是通用寄存器)。你可以指定相同的寄存器来实现 NOP 指令的效果,你还可以专门移位一个寄存器:MOV R0, R0 ; R0 = R0... NOP 指令 MOV R0, R0, LSL#3 ; R0 = R0 * 8
mvn
在MOV的基础上进行取反之后再装载到目的寄存器MVN R0, #4 ; R0 = -5 MVN R0, #0 ; R0 = -1
sub
SUB 用操作数 one 减去操作数 two,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:SUB R0, R1, R2 ; R0 = R1 - R2 SUB R0, R1, #256 ; R0 = R1 - 256 SUB R0, R2, R3,LSL#1 ; R0 = R2 - (R3 << 1)
add
ADD 将把两个操作数加起来,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:ADD R0, R1, R2 ; R0 = R1 + R2 ADD R0, R1, #256 ; R0 = R1 + 256 ADD R0, R2, R3,LSL#1 ; R0 = R2 + (R3 << 1)
and
AND 将在两个操作数上进行逻辑与,把结果放置到目的寄存器中;对屏蔽你要在上面工作的位很有用。 操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:AND R0, R0, #3 ; R0 = 保持 R0 的位0和1,丢弃其余的位。
bic
BIC 是在一个字中清除位的一种方法,与 OR 位设置是相反的操作。操作数 2 是一个 32 位位掩码(mask)。如果如果在掩码中设置了某一位,则清除这一位。未设置的掩码位指示此位保持不变。BIC R0, R0, #%1011 ; 清除 R0 中的位 0、1、和 3。保持其余的不变。
比较指令
- cmp
CMP 允许把一个寄存器的内容如另一个寄存器的内容或立即值进行比较,更改状态标志来允许进行条件执行。它进行一次减法,但不存储结果,而是正确的更改标志。标志表示的是操作数 1 比操作数 2 如何(大小等)。如果操作数 1 大于操作操作数 2,则此后的有 GT 后缀的指令将可以执行。此操作影响CPSR的N位和Z位。 - tst
与CMP类似,对两个操作数进行按位与操作,根据操作结果修改CPSR的N位和Z位。
跳转指令
- b
B 是最简单的分支。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的 R15 的值的一个偏移量;而不是一个绝对地址。它的值由汇编器来计算,它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(+/- 32 M)。 - bl
BL 是另一个分支指令。就在分支之前,在寄存器 14 中装载上 R15 的内容。你可以重新装载 R14 到 R15 中来返回到在这个分支之后的那个指令,它是子例程的一个基本但强力的实现。
以上两条指令可以配合条件来实现条件跳转语句,有以下条件可以使用:
EQ : 等于 如果一次比较之后设置了 Z 标志。 NE : 不等于 如果一次比较之后清除了 Z 标志。 GE : 大于或等于(有符号) 如果一次比较之后... 设置了 N 标志并设置了 V 标志 或者... 清除了 N 标志并清除了 V 标志。 GT : 大于(有符号) 如果一次比较之后... 设置了 N 标志并设置了 V 标志 或者... 清除了 N 标志并清除了 V 标志 并且... 清除了 Z 标志。 LE : 小于或等于(有符号) 如果一次比较之后... 设置了 N 标志并清除了 V 标志 或者... 清除了 N 标志并设置了 V 标志 并且... 设置了 Z 标志。 LT : 小于(有符号) 如果一次比较之后... 设置了 N 标志并清除了 V 标志。 或者... 清除了 N 标志并设置了 V 标志。
移位指令
lsl
Rx, LSL #n or Rx, ASL #n or Rx, LSL Rn or Rx, ASL Rn
接受 Rx 的内容并按用‘n’或在寄存器 Rn 中指定的数量向高有效位方向移位。最低有效位用零来填充。除了概念上的第 33 位(就是被移出的最小的那位)之外丢弃移出最左端的高位,如果逻辑类指令中 S 位被设置了,则此位将成为从桶式移位器退出时进位标志的值。
考虑下列:MOV R1, #12 MOV R0, R1, LSL#2
在退出时,R0 是 48。 这些指令形成的总和是 R0 = #12, LSL#2 等同于 BASIC 的 R0 = 12 << 2
ror
Rx, ROR #n or Rx, ROR Rn
循环右移类似于逻辑右移,但是把从右侧移出去的位放置到左侧,如果逻辑类指令中 S 位被设置了,则同时放置到进位标志中,这就是位的‘循环’。一个移位量为 32 的操作将导致输出与输入完全一致,因为所有位都被移位了 32 个位置,又回到了开始时的位置!
程序状态字访问指令
msr
复制一个寄存器到 PSR 中MSR CPSR, R0 ; 复制 R0 到 CPSR 中 MSR SPSR, R0 ; 复制 R0 到 SPSR 中
mrs
复制 PSR 到一个寄存器中MRS R0, CPSR ; 复制 CPSR 到 R0 中 MRS R0, SPSR ; 复制 SPSR 到 R0 中
存储器访问指令
ldr
把数据从内存装载到寄存器LDR{条件} Rd, <地址>
str
把数据从寄存器写回内存STR{条件} Rd, <地址>
第3课-ARM伪指令
ARM机器码
ARM机器码就是指令的二进制代码,通过将elf格式的执行程序进行反汇编后可以查看每条指令的机器码,是一个32位的整数。机器码分为若干个段,每个段可以反映指令本身的一些信息,比如指令的条件类型,操作数类型,操作数的值,是否影响CPSR,寄存器编号等。
定义类伪指令
伪指令本身并没有所对应的机器码,它只是在编译的时候起作用,或者转化为其他的实际指令来运行。类似于C语言中的预处理指令。
- global:定义全局符号
- data:定义数据段
- ascii:定义字符串数据
- byte:定义一个字节数据
- word:定义一个字的数据
equ:类似于C语言中的宏定义
.equ DA, 0x89 ; DA=0x89 mov r0, #DA ; r0=0x89
align:控制对齐
.data hello: .ascii "helloworld" .align 4 bh: .byte 0x1 wd: .word 0xff
操作类伪指令
- nop
空操作,一般用来延时,实际上是用mov r0, r0来替代。 ldr
mov r0, #0x1ff ;出错,对于mov指令,不能使用超过8位的立即数,这根机器码有关 ldr r0, =0x1ff ;正确,对于超过8位的赋值,需要使用ldr伪指令,小于8位也可以使用ldr进行赋值
第4课-协处理器访问指令
协处理器用于执行特定的任务,比如数学协处理器可以控制数字处理,以减轻处理器的负担。ARM可支持多达16个协处理器,其中CP15是最重要的一个。
协处理器可以用于提供额外的寄存器,用于控制缓存,MMU,保护系统,时钟模式以及其他的CPU选项,比如大小端工作模式。
对CP15的寄存器访问需要通过MCR和MRC来完成。
CP15提供了c0-c15共16组寄存器,在每组下面还有c0-cx若干小组寄存器,每个小组下面还有若干编码的具体寄存器。
MCR:将通用寄存器中的值放到协处理器中
MRC:与MCR相反,将值放回协处理器
You can access CP15 registers with MRC and MCR instructions: MCR{cond} P15,,,,, MRC{cond} P15,,,,,
示例:
mrc P15, 0, r0, c0, c0, 0 ;将CP15的Main ID寄存器读取到r0中 mcr P15, 0, r0, c1, c0, 0 ;将r0赋值到CP15的Control寄存器
- 无标签