ARM汇编基础-GNU汇编语法
一、为什么需要汇编
嵌入式linux驱动开发和STM32一样,在设备启动时,需要一段汇编代码,引导设备运行到我们写的C语言入口。而STM32开发过程中,并不需要开发人员做这一步,原因其实是这段引导代码,已经由ST公司写好了,就是我们常见的 .s 启动文件,如 startup_stm32f10x_hd.s。
而在嵌入式linux开发时,不会提供这样的.s文件,这就需要我们自己实现。需要会一定的ARM汇编,但不会太多。
二、GNU汇编语法
开发STM32的主流IDE有 Keil 和 IAR 两种,但是它们的启动文件却不完全相同,是因为他们的编译器不同。在开发嵌入式linux,使用的是GCC编译器,因此,使用的就是GNU语法。
2.1、指令语法
GNU语法适用于所有架构,并不是ARM独享的,GNU语句基本结构如下:
label: instruction @ comment分为以下3个部分:
-
label:即标号,表示地址位置。有些指令前面可能会有标号,这样就可以通过这个标号得到指令的地址,标号也可以用来表示数据地址。
注意 label 后面的“:”,任何以“:”结尾的标识符都会被识别为一个标号。
-
instruction:即指令,也就是汇编指令或伪指令。
-
@ comment:@符号,表示后面的是注释,就跟 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 段这样就自定义了一个 .testsection 段。
汇编程序的默认入口标号是 _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》 。
2.2、函数语法
GNU 汇编同样也支持函数,函数格式如下:
函数名: 函数体 返回语句GNU 汇编函数返回语句不是必须的,如下代码就是用汇编写的 Cortex-A7 中断服务函数:
/* 未定义中断 */Undefined_Handler: ldr r0, =Undefined_Handler ; 将标签Undefined_Handler的地址加载到寄存器r0中 bx r0 ; 使用分支指令bx跳转到r0寄存器中的地址
/* SVC 中断 */SVC_Handler: ldr r0, =SVC_Handler bx r0
/* 预取终止中断 */PrefAbort_Handler: ldr r0, =PrefAbort_Handler bx r0以函数 Undefined_Handler 为例,Undefined_Handler 就是函数名, ldr r0, =Undefined_Handler 是函数体, bx r0 是函数返回语句, bx 指令是返回指令,函数返回语句不是必须的。
以上三个函数,都构成了一个死循环。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!













