Linux--汇编语法配置初始化的原理

------改编自正点原子Linux开发手册

我们在学习 STM32 的时候几乎没有用到过汇编,可能在学习 UCOS 、 FreeRTOS 等 RTOS
类操作系统移植的时候可能会接触到一点汇编。但是我们在进行嵌入式 Linux 开发的时候是绝
对要掌握基本的 ARM 汇编,因为 Cortex-A 芯片一上电 SP 指针还没初始化, C 环境还没准备
好,所以肯定不能运行 C 代码,必须先用汇编语言设置好 C 环境,比如初始化 DDR 、设置 SP
指针等等,当汇编把 C 环境设置好了以后才可以运行 C 代码。所以 Cortex-A 一开始肯定是汇
编代码,其实 STM32 也一样的,一开始也是汇编,以 STM32F103 为例,启动文件 startup_stm32f10x_md.s 或 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****汇编语法

Keil MDK与IAR的编译器不一样,底层的汇编语法也不一样,那一样的c语言由编译器转换成底层汇编语言也是不同的汇编语法,所以启动文件也得不同的汇编语法来编辑

编译器的作用就是根据汇编语法,把C语言 python Java 等等现成简单的编程语言转换成底层汇编语言

我们用的Linux开发,使用gcc编译,转换的底层是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 中断服务函数:

cs 复制代码
示例代码 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 "指令是返回指令,函数返回语句不是必须的。

相关推荐
码农君莫笑8 分钟前
Blazor项目中使用EF读写 SQLite 数据库
linux·数据库·sqlite·c#·.netcore·人机交互·visual studio
mubeibeinv18 分钟前
项目搭建+图片(添加+图片)
java·服务器·前端
dessler23 分钟前
Docker-如何启动docker
运维·docker·云原生·容器·eureka
zhy2956323 分钟前
【DOCKER】基于DOCKER的服务之DUFS
运维·docker·容器·dufs
无为之士28 分钟前
Linux自动备份Mysql数据库
linux·数据库·mysql
秋名山小桃子38 分钟前
Kunlun 2280服务器(ARM)Raid卡磁盘盘符漂移问题解决
运维·服务器
与君共勉1213839 分钟前
Nginx 负载均衡的实现
运维·服务器·nginx·负载均衡
岑梓铭1 小时前
(CentOs系统虚拟机)Standalone模式下安装部署“基于Python编写”的Spark框架
linux·python·spark·centos
努力学习的小廉1 小时前
深入了解Linux —— make和makefile自动化构建工具
linux·服务器·自动化
MZWeiei1 小时前
Zookeeper基本命令解析
大数据·linux·运维·服务器·zookeeper