东莞做网站-南城信科,凡客诚品网,wordpress重置主题,齐齐哈尔城市建设档案馆网站引言 ARM编译器将各种源文件#xff08;汇编文件、C语言程序文件、C语言程序文件#xff09;编译生成ELF格式的目标文件#xff08;后缀为.o文件#xff0c;以下将目标文件简称为.o文件#xff09;#xff0c;.o文件经过连接器#xff0c;和C/C运行时库一起编译生成ELF格…引言 ARM编译器将各种源文件汇编文件、C语言程序文件、C语言程序文件编译生成ELF格式的目标文件后缀为.o文件以下将目标文件简称为.o文件.o文件经过连接器和C/C运行时库一起编译生成ELF格式的映像文件image如常用的MKD使用 fromelf.exe生成的bin文件就是imagebin文件可以直接写入到flash中实际上使用jlink下载的内容就是bin文件的内容hex文件是包含地址信息的bin文件可以理解为hex地址信息bin。下文中也将映像文件称为bin文件或者image文件。编译流程如下图。 图片来源于《Introductiontothe Armv8-M Architecture and its ProgrammersModel》
相关文档在后面有链接
1、ARM映像文件的组成
1.1 ARM映像文件的组成
ARM映像文件是一个层次性的结构有如下三部分组成域region、输出段output section、输入段input section三者有如下的关系 一个bin文件由一个或多个域组成 一个域包含一个或多个输出段 一个输出段包含一个或多个输入段 各输入段包含了目标文件中的代码和数据 输入段可以理解为我们写的代码具体包含哪些属性。输入段包含4类代码、已经初始化的数据、未初始化的存储区域、内容初始化为0的区域即codeRW、ZI、ZI分别为RO段、RW段、ZI段。编译器根据输入段的属性将这些输入段分组组成不同的输出段以及域。 一个输出段里面包含了一些列具有相同RO、RW、ZI属性的输入段。输出段的属性于其中包含的输入段的属性相同在一个输出段内部各个输入段是按照一定的规律排序的。 一个域包含1到3个输出段其中各输出段的属性各不相同。各输出段的排列顺序是由其属性决定的RO属性排在最前面其次RW最后ZI段。一个域通常映射到一个物理储存器上如flash、ram等。 抛开上面较书面的表达我们已keil为例。在mdk中域的定义由分散链接文件sct决定随便打开一个keil的sct文件可以看到 在sct中定义了三个域名字分别为LR_IROM1、ER_IROM1、RW_IRAM1LR_IROM1是最终的bin文件ER_IROM1是加载域RW_IRAM1是执行域。keil生成的bin中一般包含三个段RO段代码只读数据、RW段、ZI段。一个域至少包含上述三个段中的一个。 对于一个C文件来说可能包含代码、全局变量、只读数据、为0的数据、未初始化的数据。在编译的时候会自动将各个段进行分类例如led.c文件会将代码部分放到RO段里面全局变量放到RW段未初始化的变量存放到ZI段。 以下进行一些猜测如果说我们有led1.c和led2.c两个文件二者分别生成RO、RW、ZI则可以理解为led1.c和led2.c是输入段1.1.1和1.1.2他们生成的RO、RW、ZI为输出段1.1和1.2最终合并在域1中实际上我们知道这个域存放的地方是M4芯片内部的flash。
1.2 ARM映像文件各组成部分的地址映射 bin文件在储存系统如内部flash中的地址有两种一种是bin文件位于储存器中时的地址称为加载地址。一种时bin文件运行时的地址称为运行地址。之所以分成两类是因为在bin文件中有些域是可以移动到新的储存区域比如RW域中的数据在运行的时候会搬运到RAM中。 如下图所示为例flash的起始地址为0x0800 0000依次存放RO、RW、ZI段在运行的时候ZI和RW会搬运到SRAM中。 一个bin文件一般包含若干个域一个域包含若干个输出段。ARM链接器在链接时需要知道如下信息才能正确的生成bin文件 分组信息 决定如何将各输入段组织成相应的输出段和域 定位信息 决定各域在储存空间中的起始地址 根据bin文件中地址映射的复杂程度可以使用命令行选项的方式提供或者提供配置文件如keil的sct文件
2、ARM映像文件的入口点
2.1 ARM映像文件中的两类入口点 bin文件有两类入口点一种是映像文件运行时的入口点称为初始入口点initial entry point另一种时普通的入口点entry point。 初始入口点时bin文件运行时的入口点每个bin只有唯一的初始入口点保存在ELF头文件中。如果bin是被操作系统加载的则OS正是用过跳转到该初始入口点处执行来加载该映像文件。 普通入口点是在汇编中用ENTRY来定义的在嵌入式系统中一个典型的用途就是将中断服务程序定义为普通入口点防止在链接的时候将中断服务程序给删除了。在C库中__main是入口点。在sct中可以看到:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************LR_IROM1 0x10000000 0x0000F000 { ; load region size_regionER_IROM1 0x10000000 0x0000F000 { ; load address execution address*.o (RESET, First)*(InRoot$$Sections).ANY (RO)}RW_IRAM1 0x1FFFC000 0x00003000 { ; RW data.ANY (RW ZI)}
}其中REST就是初始入口点属性将初始入口点放到ROM中在start.s中可以看到如下的汇编写法 这个就是初始入口点定义的代码部分。 在一个bin文件中只有一个初始入口点普通入口点可以由多个初始入口点可以是普通入口点也可以不是。
2.2 定义初始入口点
初始入口点需要满足如下两个条件 初始入口点必须位于bin文件的运行时域内 包含初始入口点的运行时域不能被覆盖它的加载地址和运行地址必须相同这种域称为固定域root region
可以使用链接选项-entry address来指定bin的初始入口点address表示初始入口点的地址。 如果bin被一个加载器加载再运行如被引导程序或者OS加载则bin文件必须包含一个初始入口点。比如一个操作系统的映像文件被一个引导程序加载这时程序跳转到该映像文件的初始入口点处开始执行它覆盖了引导程序称为系统中的操作系统。这种映像文件中通常包含了其它的普通入口点这些入口点一般为异常中断处理程序的入口地址。 当用户没有指定链接选项-entry指定链接地址则按照如下规则决定映像文件的初始入口点 如果输入的目标文件中只有一个普通入口点该普通入口点被链接器当作bin文件的初始入口点 如果输入的目标文件没有普通入口点或者普通入口点多余一个则链接器生成的bin文件不包含初始入口点且产生警告。
2.3 普通入口点的用法
普通入口点一般用作两种用途 指定中断服务程序的入口防止链接的时候删除中断服务器程序代码 没有指定链接选项-entry address且输入的目标文件中只有一个普通入口点则该普通入口点被当作初始入口点
3、输入段的排列顺序
链接器根据各输入段的属性来组织这些输入段具有相同属性的输入段被放到域中一段连续的地址空间中组成一个输出段。在输出段中各输入段的起始地址与输出段的起始地址和该输出段中各输入段的排列顺序有关。
通常情况下输出段中各输入段的排列顺序由如下几个因素决定 输入段的属性 输入段的名称 各输入段在连接命令行的输入段列表中的排列顺序
按照输入段的属性排列顺序如下 只读的代码段(RO-code) 只读的数据段(RO-data) 可读写的代码段(RW-code) 其它以及初始化的数据段(RW-data) 未初始化的数据ZI 对于相同属性的输入段按照名称顺序来排序输入段的名称区分大小写按照ASCII码顺序进行排序。如果输入段的名称也相同按照其在输入段列表中的顺序进行排序。也就是说即使各输入段的属性和名称保持不变若在编译时各个输入段在列表中的排列属性不同生成的映像文件也将不同。 可以使用连接选项-first、-last改变输入段的排列顺序也可以使用配置文件改变输入段的排列顺序。排序规则影响因素有三个输入段属性、输入段名称、输入段在列表中的顺序。连接选项-first、-last只对输入段的名称和在列表中的顺序有效无法改变因输入段的属性进行的排序规则。 在各个输入端排好序之后在最终确定各个输入段的起始地址之前可以通过填充“补丁”使各个输入段满足地址对齐要求。
4、题外话 本篇文章是博主在学习ARM体系的时候写的笔记性质的文章先在CSDN上分享用到的参考文档有
《Introductiontothe Armv8-M Architecture and its ProgrammersModel》《ARM体系结构与编程》
相关文档已经上传到博主的仓库里面链接https://gitee.com/zichuanning520/htq_library