ARM开发入门与汇编基础
2019-12-12
关键字:汇编指令基础
首先 ARM 是一家公司,它成立于 1990 年。ARM 公司主要是设计 ARM 系列的 RISC 处理器内核,并将这些内核授权给合作伙伴进行生产与销售。ARM 公司是一家只负责设计内核而不生产芯片的公司。
ARM 芯片的产品线主要分为三种:
1、应用级
应用于高端产品的芯片,如智能手机等。其芯片代号为 A 系列,如 Cortex-A8 , Cortex-A9。
2、实时嵌入式
应用于一些对性能要求稍低一些的设备。其芯片代号为 R 系列,如 Cortext-R4。
3、MCU、FPGA
主要应用于对成本要求较高但性能要求较弱的产品。其芯片代号为 Cortext-M 系列。
ARM 的体系架构主要有以下四种:
1、ARMv4
2、ARMv5
3、ARMv6
4、ARMv7
不同体系架构拥有不同的指令集。
一个典型的 ARM 设备至少需要包含三个模块:1、FLASH;2、内存;3、CPU。
FLASH 负责存储程序,内存负责临时管理程序的运行状态而CPU则负责做计算处理。
CPU 中又有三个很重要的组成:1、控制器;2、运算器;3、寄存器。
控制器负责去 FLASH 中准确读取程序内容。运算器负责执行程序代码,或者说负责执行计算需求,而寄存器则负责存储需要计算的数据。
什么是交叉编译工具链?
交叉编译工具链是嵌入式行业常听的词汇。嵌入式设备的芯片通常都是 ARM 架构的,而我们用于开发嵌入式程序的电脑却通常都是 X86 架构的。两种芯片架构不同,所编译出来的程序自然也不能通用。那为了能在电脑上编译出嵌入式设备能用的程序来,就必须要用到这个交叉编译工具链了。它的作用就类似于一个“翻译官”,将在电脑上写的代码翻译成能在 ARM 架构的芯片上运行的程序出来。
ARM 的工作模式
ARM 主要有七种工作模式:
1、User
非特权模式,或者称为普通模式。大部分的任务执行都在这一模式下完成。
2、FIQ
中断模式(Fast)。当一个高优先级的中断发生时,就会进入这个模式。
3、IRQ
中断模式(normal)。当一个低优先级的中断发生时,就会进入这个模式。
4、Supervisor
超级用户模式。当复位或软中断指令执行时会进入这种模式。
5、Abort
当需要存取异常信息时会进入这个模式。
6、Undef
当执行未定义指令时会进入这个模式。
7、System
几乎与 User 模式一样,只是其权限会比 User 稍高一些。
ARM 有 37 个寄存器,其中 1 个是 PC 寄存器,1个是CPSR(Currnet program status register)寄存器,5个是SPSR(Saved program status register)寄存器以及30个通用寄存器。
汇编指令基础
MOV指令
MOV指令就是 move 的缩写。它表示移动寄存器的值的意思。
mov r1,#13
mov r2,#0xff
以上两条指令表示将十进制数值 13 寄存到 r1 寄存器中以及将十六进制数值 0xff 寄存到 r2 寄存器中。
mov r1,r2,LSL#2
这条指令表示将寄存器 r2 中的值向左移动两位以后再寄存到 r1 寄存器中。LSL 即 left shift logic 的缩写。 假设 r2 寄存器中的值是1,那么指执行了这条指令以后 r1 中的值将会是 4。与之相对应的还有 LSR#2,表示向右移动2位。
MRS 指令
MOV指令只能操作普通的寄存器,如果要操作特殊寄存器,就得使用 MRS 指令。
mrs r1,cpsr
mrs cpsr,r0
以上两条指令分别表示将 CPSR 寄存器中的值读取到普通寄存器 r1 中以及将普通寄存器 r0 中的值写入到 CPSR 寄存器中。
逻辑指令
and
逻辑与,例如 and r0,r1 #0xff 相当于 r0 = r1 & 0xff。
orr
逻辑或,例如 orr r3,r0,#0xf 相当于 r3 = r0 | 0xf。
cmp
比较。 例如 cmp r1,r0,比较 r1 与 r0 是否相等。
bic
清除指令。例如 bic r0,r0,#0x03。清除 r0 寄存器中的第 0 号位与第 3 号位。
tst
测试。例如 tst r0,#0x20。用于测试第 6 位的值是否为0,为0则Z标志位置1。
算术指令
add
加法指令。例如:add r0,r1,r2 表示将 r1 与 r2 两寄存器的值相加后保存在 r0 寄存器中。
sub
减法指令。例如:sub r0,r1,#3 表示将 r1 寄存器中的值减 3 后保存在 r0 寄存器中。
mul
乘法指令。例如: mul r0, r1, r2 表示将 r1 与 r2 中的值相乘后保存到 r0 寄存器中。
跳转指令
b
普通跳转指令。常见的用法为: b label。表示将程序指针跳转到标签为 label 的代码处。即 C 语言中的 goto 语句。
bl
记忆跳转指令。常见用法为: bl func。这条指令会将下一条指令的地址保存到 LR 寄存器,然后将程序指针跳到 func 标签处执行。待 func 标签处的代码全部执行完毕后可以通过 mov pc,lr 指令将程序指针跳回到先前跳转func前的位置继续执行。这就是单片机中的中断的概念,执行完以后还要回来的那种。
beq
bne
以下是一个实例,将一段普通 C 语言程序翻译成汇编语言:
void main() { int ret = 0; func1(2); while(1); } int func1(int a) { if(a == 2) return func2(a); else return func3(a); } int func2(int a) { return a+3; } int func3(int a) { return a-1; }
.text main: mov r5,#0 mov r0,#2 b1 func1 main_end: b main_end func1: mov r12,lr cmp r0,#2 bleq func2 blne func3 func_end: mov pc,r12 func2: add r0,#3 mov pc,lr func2_end: func3: sub r0,r0,#1 mov pc,lr func3_end: .end
Load/Store 指令
load/store 架构规定,存储器之间不能直接拷贝,必须通过CPU中的寄存器作中转。
load指令的汇编语句为: ldr。它的作用是将指定地址中的数据加载进CPU的寄存器中。
例如:
ldr r0,=buf
ldr r1,[r0]
第一句的意思是将 'buf' 标签的地址存到 r0 寄存器中。其中 buf 标签是定义在 .data 区段的 .byte 数组。
第二句的意思就是将 r0 寄存器中的值作为地址,将这个地址中的内容加载到 r1 寄存器中。
ldr r1,[r0,#8] 相当于C语言的 r0 = *(r0 + 8)
store指令的汇编语句为:str。与 ldr 相反,将CPU寄存器中的值写到指定地址中的内存中去。
例如:
mov r0,#9
mov r1,=dest_buf
str r0,[r1]
第一句先准备好一个寄存器中的数据。
第二句确定好内存中的数据段地址。
第三句将 r0 寄存器中的数据输出到 dest_buf 内存段中去。
GNU汇编伪指令
GNU汇编伪指令是辅助汇编程序编程用的指令,它不参与实际代码逻辑的构建,仅作辅助标识之用。
.text 将定义符开始的代码编译到代码段
.end 文件结束
.data 将定义符开始的代码编译到数据段
.equ 定义宏
.byte 定义1个字节的变量,定义字节数组的指令为: .byte 0x11,'a',0
.word 定义word变量,长度为4个字节。
.string 定义字符串,如 .string "hello worl\0"
.global 声明全局符号,如 .global =start
批量操作指令
前面提到的 ldr 与 str 指令都是单寄存器操作的。如果想要一次性操作多个寄存器,则可以使用以下指令
ldmia 与 stmia。
例如:
ldmia r0!,{r7 - r10}。这条指令执行完毕后,会自动将 r7 ~ r10 寄存器中的数据加载到 r0 ~ r3 寄存器中。
stmia r0!,{r7 - r10}。与上一条指令相反。
堆栈操作指令
stmfd sp!,{r0 - r12,lr} 将寄存器 r0 ~ r12 lr中的值存入栈中,常用于中断保护现场,'!' 号表示会自动偏移。
ldmfd sp1,{r0-r12,pc}^ 与上一条指令相反,常用于中断恢复现场。
软中断
swi
该指令可以产生一个软中断,用法为:swi 0x02,表示产生一个中断号为 2 的软中断。
2