ARM汇编基础

ARM汇编基础

我们在学习 STM32的时候几乎没有用到过汇编,可能在学习 UCOS、 FreeRTOS等 RTOS类操作系统移植的时候可能会接触到一点汇编。但是我们在进行嵌入式 Linux开发的时候是绝
对要掌握基本的 ARM汇编,因为 Cortex-A芯片一上电 SP指针还没初始化, C环境还没准备
好,所以肯定不能运行 C代码,必须先用汇编语言设置好 C环境,比如初始化 DDR、设置 SP指针等等,当汇编把 C环境设置好了以后才可以运行 C代码。所以 Cortex-A一开始肯定是汇
编代码,其实 STM32也一样的,一开始也是汇编,以 STM32F103为例,启动文件
startup_stm32f10x_hd.s就是汇编文件,只是这个文件 ST已经写好了,我们根本不用去修改,所
以大部分学习者都没有深入的去研究。汇编的知识很庞大,本章我们只讲解最常用的一些指令,
满足我们后续学习即可。
I.MX6U-ALPHA使用的是 NXP的 I.MX6UL芯片,这是一款 Cortex-A7内核的芯片,所以
我们主要 讲的是 Cortex-A的汇编指令。为此我们需要参考两份跟 Cortex-A内核有关的文档:
《 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》和《 ARM Cortex-A(armV7)编程手册 V4.0.pdf》 ,第一份文档主要讲解 ARMv7-A和 ARMv7-R指令集的开发,
Cortex-A7使用的是 ARMv7-A指令集,第二份文档主要讲解 Cortex-A(armV7)编程的,这两份
文档是学习 Cortex-A不可或缺的文档。在《 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》的 A4章详细的讲解了 Cortex-A的汇编指令,要想系统的学习 Cortex-A的指令就要认真的阅读 A4章节。
对于 Cortex-A芯片来讲,大部分芯片在上电以后 C语言环境还没准备好,所以第一行程序
肯定是汇编的,至于要写多少汇编程序,那就看你能在哪一步把 C语言环境准备好。所谓的 C语言环境就是保证 C语言能够正常运行。 C语言中的函数调用涉及到出栈入栈,出栈入栈就要
对堆栈进行操作,所谓的堆栈其实就是一段内存,这段内存比较特殊,由 SP指针访问, SP指
针指向栈顶。芯片一上电 SP指针还没有初始化,所以 C语言没法运行,对于有些芯片还需要
初始化 DDR,因为芯片本身没有 RAM,或者内部 RAM不开放给用户使用,用户代码需要在
DDR中运行,因此一开始要用汇编来初始化 DDR控制器。后面学习 Uboot和 Linux 内核的时
候汇编是必须要会的,是不是觉得好难啊?还要会汇编!前面都说了只是在芯片上电以后用汇
编来初始化一些外设,不会涉及到复杂的代码, 而且使用到的指令都是很简单的,用到的就那
么十几个指令。所以,不要看到汇编就觉得复杂,打击学习信心。

GNU汇编语法

如果大家使用过
STM32的话就会知道 MDK和 IAR下的启动文件 startup_stm32f10x_hd.s其中的汇编语法是有所不同的,将 MDK下的汇编文件直接复制到 IAR下去编译就会出错,因
为 MDK和 IAR的编译器不同,因此对于汇编的语法就有一些小区别。我们要编写的是 ARM汇编,编译使用的 GCC交叉编译器,所以我们的汇编代码要符合 GNU语法。
GNU汇编语法适用于所有的架构,并不是 ARM独享的, GNU汇编由一系列的语句组成,
每行一条语句,每条语句有三个可选部分,如下:
label instruction @ comment
label即标号,表示地址位置,有些指令前面可能会有标号,这样就可以通过这个标号得到
指令的地址,标号也可以用来表示数据地址。注意 label后面的“:”,任何以“:”结尾的标识
符都会被识别为 一个标号。
instruction即指令,也就是汇编指令或伪指令。
@符号,表示后面的是注释,就跟 C语言里面的“ “/”和 “/”一样,其实在 GNU汇编文
件中我们也可以使用“ “/”和 “/”来注释。
comment就是注释内容。
比如如下代码:
add: MOVS R0, #0X12 @设置 R0=0X12
上面代码中“
add:”就是标号 MOVS R0,#0X12”就是指令,最后的 “@设置 R0=0X12”就是
注释。
注意! ARM中的指令、伪指令、伪操作、寄存器名等可以全部使用大写,也可以全部使用
小写,但是不能大小写混用。
用户可以使用
.section伪操作来定义一个段,汇编系统预定义了一些段名:
.text 表示代码段。
.data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。
我们当然可以自己使用 .section来定义一个段,每个段以段名开始,以下一段名或者文件结
尾结束,比如:
.section .testsection @定义一个 testsetcion段
汇编程序的默认入口标号是 _start,不过我们也可以在链接脚本中使用 ENTRY来指明其它
的入口点,下面的代码就是使用 _start作为入口标号:
.global _start _start: ldr r0, =0x12 @r0=0x12
上面代码中 .global是伪操作,表示 _start是一个全局标号,类似 C语言里面的全局变量一
样,常见的伪操作有:
.byte 定义单字节数据,比如 .byte 0x12。
.short 定义双字节数据,比如 .short 0x1234。
.long 定义一个 4字节数据,比如 .long 0x12345678。
.equ 赋值语句,格式为: :.equ 变量名,表达式,比如 .equ num, 0x12,表示 num=0x12。
.align 数据字节对齐,比如: :.align 4表示 4字节对齐。
.end 表示源文件结束。
.global 定义一个全局符号,格式为: :.global symbol,比如 :.global _start。
GNU汇编还有其它的伪操作,但是最常见的就是上面这些,如果想详细的了解全部的伪操
作,可以参考《 ARM Cortex-A(armV7)编程手册 V4.0.pdf》的 57页。
GNU汇编同样也支持函数,函数格式如下:
函数名 : 函数体
返回语句
GNU汇编函数返回语句不是必须的,如下代码就是用汇编写的 Cortex-A7中断服务函数:
示例代码7.1.1.1 汇编函数定义 /* 未定义中断 / Undefined_Handler: ldr r0, =Undefined_Handler bx r0 / SVC中断 / SVC_Handler: ldr r0, =SVC_Handler bx r0 / 预取终止中断 */ PrefAbort_Handler: ldr r0, =PrefAbort_Handler bx r0
上述代码中定义了三个汇编函数: Undefined_Handler、 SVC_Handler和
PrefAbort_Handler。以函数 Undefined_Handler为例我们来看一下汇编函数组成,
Undefined_Handler”就是函数名 ldr r0, =Undefined_Handler”是函数体 bx r0”是函数
返回语句,“ bx”指令是返回指令,函数返回语句不是必须的。

Cortex-A7常用汇编指令

本节我们将介绍一些常用的 Cortex-A7汇编指令,如果想系统的了解 Cortex-A7的所有汇
编指令请参考《 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》的 A4章节。

你可能感兴趣的:(Linux学习之路,汇编,单片机,stm32)