KEIL中启动文件详解(汇编语言)
原文在此:http://www.cnblogs.com/mddblog/p/4920063.html
概述
在嵌入式系统中,启动文件是整个系统非常关键的部分,它会进行一些底层的初始化,构建程序运行必要的环境,比如堆栈初始化,变量初始化等。如果启动文件出现错误,则整个系统就跑不起来,因此研究启动文件非常必要。
在keil中,启动文件由汇编代码编写,一般命名为startup_xxx.s,xxx为支持的某种芯片,比如可以是lpc15xx(NXP的LPC15xx系列)、MK60D10(飞思卡尔)、stm32f10x(意法半导体stm32f10x系列)等Cortext-M0/M3/M4内核芯片。它们的代码格式非常相近,根据启动文件代码由上到下的编写顺序.
可以将其分为以下5个典型部分:
1.堆栈空间定义;
2.存放中断向量表;
3.复位中断函数(Reset_Handler);
4.其它中断异常服务函数,以及弱[WEAK]声明;
5.将堆栈地址传递给库函数,利用库函数初始化堆栈,和库函数自身初始化。
5个部分具体说明如下:
1.堆栈空间定义
如下图所示,定义了栈大小Stack_Size = 0X200,即512字节;堆大小Heap_Size = 0X100,256字节。还定义了三个标号:__initial_sp(栈顶)、__heap_base(堆起始地址)和__heap_limit(堆终止地址),它们的空间由SPACE关键字来申请,并记作Stack_Mem和Heap_Mem。

通过这些我们可以很容易的知道堆栈的大小,但是它们的绝对地址或者说基地址仅仅从这里是得不到的。编译器编译完工程后,根据生成.bss段(比如未初始化的全局变量)和.data段(比如初始化的全局变量)的大小以及RAM的起始地址,来计算堆栈的基地址。
举个例子:
一个芯片的RAM起始地址为0x0200_0000,RAM大小为0x500字节,程序编译后.bss段为0x100个字节,.data段为0x100个字节。堆栈大小定义如上图。则:
A:堆起始地址 __heap_base==Heap_Mem==0x0200_0200;
B:堆终止地址即栈底 __heap_limit==Stack_Mem==0x0200_0300;
C:栈顶地址 __initial_sp==0x0200_0500(栈是向下生长,栈顶处于RAM最大地址处)。
其实,我可以在.map文件中查看堆栈的大小和基地址,如下图所示:

2.存放中断向量表
在启动代码中,会见到许多由DCD申请空间存放的一个个函数入口,即中断向量表,如下图所示,只列出了部分。

关键字DCD代表申请一个字的空间,后面的函数名即为中断服务函数入口地址。另外中断向量表一般存放在Flash 0地址。
另外,对于NXP微控制器,均实现了芯片的加密,加密的设置在向量表的结尾处,具体地址为0x02FC处。通过在此地址存放不同的值实现是否加密或者加密的等级。加密分为三个等级,CRP1:0x12345678;CRP2:0x87654321;CRP3:0x43218765。至于每个等级的具体说明请参考芯片用户手册。下面说一下加密步骤,以CRP1为例:

首先将下图中0xFFFFFFFF,修改为0x12345678。
其次,图中IF :LNOT::DEF:NOCRP表示如果没有定义宏NOCRP则执行下面的代码,那么必须保证汇编中没有定义NOCRP宏。即保证下图中Define:一栏中没有定义NOCRP即可。

3. 复位中断函数(Reset_Handler)
程序上电后,首先加载SP和PC,ARM规定从0地址处加载SP,从偏移为4的地址(0x00000004)处加载PC。然后将程序控制权交给程序。我们知道0地址处存放__initial_sp,0x00000004地址处存放Reset_Handler,加载PC后,程序跳转到Reset_Handler开始运行。Reset_Handler函数体如下图所示:

首先调用SystemInit函数来初始化系统的各种时钟,然后调用__main函数(由KEIL微库或者C库实现),在__main函数中:.data段数据的初始化->.bss段变量清零->设置堆栈指针->库函数初始化(比如常用的malloc函数)->如果必要会设置main函数的argc和argv两个参数->调用用户main函数->退出。
4.其它中断异常服务函数,以及弱[WEAK]声明

如上图所示,这里的中断服务函数是弱声明的(由[WEAK]关键字标注)。所谓弱声明,即:如果用户定义了相同的函数则此处函数失效而使用用户定义的中断服务函数。这样是为了防止用户使能了中断而没有中断服务函数,从而造成程序崩溃。假设使能了中断,而用户又没有定义中断服务函数则会进入默认中断,如下图所示,默认中断为死循环(死循环与程序崩溃不是一个概念)。

5.将堆栈地址传递给库函数
第三步骤中,调用__main函数,然后__main调用库函数初始化堆栈,但库函数并不知道堆栈的大小,因此我们需要告诉它,具体做法就是传递参数或声明标号。
下图为具体做法,可以看到第一行为:
IF :DEF:__MICROLIB
是条件编译选项,如果定义__MICROLIB,则编译图中红线上面部分,否则编译红线下面部分。那么就分2种情况。

2种情况的选择可以如下实现:
如果勾选【Options for Target】->【Target】->【Use MicroLIB】,如下图所示。即使用微库,则__MICROLIB会被定义,编译器编译红线以上代码。用EXPORT声明 __initial_sp、__heap_base和__heap_limit。

如果不勾选【Use MicroLIB】,则缺省使用KEIL C库,上图红线以下会参与编译,KEIL C库函数会调用__user_initial_stackheap,通过R0~R3将堆栈以参数形式传递给KEIL C库。
KEIL中启动文件详解(汇编语言)的更多相关文章
- Liunx中fstab文件详解
Liunx中fstab文件详解 /etc/fstab是用来存放文件系统的静态信息的文件.位于/etc/目录下,可以用命令less /etc/fstab 来查看,如果要修改的话,则用命令 vi /etc ...
- 【转】linux中inittab文件详解
原文网址:http://www.2cto.com/os/201108/98426.html linux中inittab文件详解 init的进程号是1(ps -aux | less),从这一点就能看出, ...
- 第14章 启动文件详解—零死角玩转STM32-F429系列
第14章 启动文件详解 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...
- STM32启动文件详解
启动文件使用的 ARM 汇编指令汇总 启动程序源码注释(点此下载) 1. Stack—栈 Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE ...
- 单片机STM32的启动文件详解--学习笔记
启动文件简介 启动文件由汇编编写,是系统上电复位后第一个执行的程序.主要做了以下工作: 1.初始化堆栈指针SP=_initial_sp 2.初始化PC 指针=Reset_Handler 3.初始化中断 ...
- (转)stm32启动文件详解
在<<STM32不完全手册里面>>,用的是STM32F103RBT6,所有的例程都采用了一个叫STM32F10x.s的启动文件,里面定义了STM32的堆栈大小以及各种中断的名字 ...
- linux中inittab文件详解
init的进程号是1(ps -aux | less),从这一点就能看出,init进程是系统所有进程的起点,Linux在完成核内引导以后,就开始运行init程序. init程序需要读取配置文件/etc/ ...
- (转) eclipse项目中.classpath文件详解
背景:对于java项目中.classpath文件中的相关定义一直不是很了解,有必要进行深入的学习. 1 前言 在使用eclipse或者myeclipse进行Java项目开发的时候,每个project( ...
- windows中.msc文件详解
msc是Microsoft Management Console的缩写.其实是一种可执行程序类型,可.exe类似.一般可以通过直接双击.msc文件或者在windows的运行中输入相应的文件名来启动. ...
随机推荐
- 一起学微软Power BI系列-官方文档-入门指南(5)探索数据奥秘
我们几篇系列文章中,我们介绍了官方入门文档与获取数据等基本知识.今天继续给大家另外一个重点,探索数据奥秘.有了数据源,有了模型,下一步就是如何解析数据了.解析数据的过程需要很多综合技能,不仅仅是需要掌 ...
- 为SubSonic3.0的查询(SubSonic.Query.Select和存储过程)添加更多的执行功能
在使用SubSonic3.0的查询功能时,会发现想通过执行返回我们想要的数据,切没有相关的功能,比如说:SubSonic.Query.Select,在使用查询时没有返回DataSet或DataTabl ...
- Microsoft Build 2015 汇总
简要概括(GitHub 完成约 45%): Visual Studio Code Preview(意料之外) Visual Studio 2015 RC Visual Studio 2013 Upda ...
- 【记录】ASP.NET MVC RegisterBundles
1. Install the package from nuget Install-Package Microsoft.AspNet.Web.Optimization 2,BundleConfig 配 ...
- css截断长文本显示
实现 截断长文本显示处理,以前是通过后台的截取,但这种方法容易丢失数据,不利于SEO. 而通过前端css的截断,则灵活多变,可统一运用与整个网站. 这项技术主要运用了text-overflow属性,这 ...
- Tools - Docker与Vagrant
Docker Docker - HomePage Wiki - Docker Docker简介 Overview Docker 是一个开源的应用容器引擎,基于 Go 语言并遵从 Apache2.0 协 ...
- 会务准备期间材料准备工作具体实施总结 ----(vim技巧应用, python信息提取与整合, microsoft word格式调整批量化)
会务准备期间材料准备工作具体实施总结(vim, python, microsoft word) span.kw { color: #007020; font-weight: bold; } code ...
- 项目积累html标签
今天遇到一个不太常用都标签,网上以后慢慢记下项目中用到都东西. 1.<em> 标签 告诉浏览器把其中的文本表示为强调的内容.对于所有浏览器来说,这意味着要把这段文字用斜体来显示. 在文本中 ...
- HtmlHelper拓展实现RadioList
mvc中HtmlHelper可以帮助我们生成许多Html控件,但是没有类似DropDownList的RadioList,但是发现这些方法都是拓展方法,于是就想自己也拓展一个RadioList 从网上下 ...
- 高效率去掉js数组中重复项
Array类型并没有提供去重复的方法,如果要把数组的重复元素干掉,那得自己想办法: function unique(arr) { var result = [], isRepeated; for (v ...