ARM映像文件组成详解

这篇具有很好参考价值的文章主要介绍了ARM映像文件组成详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

        ARM编译器将各种源文件(汇编文件、C语言程序文件、C++语言程序文件)编译生成ELF格式的目标文件(后缀为.o文件,以下将目标文件简称为.o文件),.o文件经过连接器,和C/C++运行时库一起编译生成ELF格式的映像文件(image,如常用的MKD使用 fromelf.exe生成的bin文件就是image),bin文件可以直接写入到flash中,实际上使用jlink下载的内容就是bin文件的内容(hex文件是包含地址信息的bin文件,可以理解为hex=地址信息+bin)。下文中也将映像文件称为bin文件或者image文件。编译流程如下图。

ARM映像文件组成详解,ARM体系,arm开发,stm32,mcu,嵌入式硬件,单片机,硬件架构,物联网

图片来源于《Introductiontothe  Armv8-M  Architecture  and its ProgrammersModel》

相关文档在后面有链接

1、ARM映像文件的组成

1.1 ARM映像文件的组成

ARM映像文件是一个层次性的结构,有如下三部分组成:域(region)、输出段(output section)、输入段(input section),三者有如下的关系:

  • 一个bin文件由一个或多个域组成

  • 一个域包含一个或多个输出段

  • 一个输出段包含一个或多个输入段

  • 各输入段包含了目标文件中的代码和数据

ARM映像文件组成详解,ARM体系,arm开发,stm32,mcu,嵌入式硬件,单片机,硬件架构,物联网

        输入段可以理解为我们写的代码具体包含哪些属性。输入段包含4类:代码、已经初始化的数据、未初始化的存储区域、内容初始化为0的区域,即(code+RW)、ZI、ZI,分别为RO段、RW段、ZI段。编译器根据输入段的属性,将这些输入段分组,组成不同的输出段以及域。

        一个输出段里面包含了一些列具有相同RO、RW、ZI属性的输入段。输出段的属性于其中包含的输入段的属性相同,在一个输出段内部,各个输入段是按照一定的规律排序的。

        一个域包含1到3个输出段,其中各输出段的属性各不相同。各输出段的排列顺序是由其属性决定的,RO属性排在最前面,其次RW,最后ZI段。一个域通常映射到一个物理储存器上,如flash、ram等。

        抛开上面较书面的表达,我们已keil为例。在mdk中,域的定义由分散链接文件(sct)决定,随便打开一个keil的sct文件,可以看到:

ARM映像文件组成详解,ARM体系,arm开发,stm32,mcu,嵌入式硬件,单片机,硬件架构,物联网

在sct中,定义了三个域,名字分别为LR_IROM1、ER_IROM1、RW_IRAM1,LR_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中。

ARM映像文件组成详解,ARM体系,arm开发,stm32,mcu,嵌入式硬件,单片机,硬件架构,物联网

        一个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_region
  ER_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中可以看到如下的汇编写法:

ARM映像文件组成详解,ARM体系,arm开发,stm32,mcu,嵌入式硬件,单片机,硬件架构,物联网

这个就是初始入口点定义的代码部分。

        在一个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文章来源地址https://www.toymoban.com/news/detail-764814.html

到了这里,关于ARM映像文件组成详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • SQLite3移植STM32MP157 ARM开发板

    SQLite3移植STM32MP157 ARM开发板

    移植首先就得有源码,从SQLite官网下载最新版源码 下载地址 这里使用的环境为Ubuntu16 所以直接在Ubuntu下下载的。 下载完成后解压文件 进入解压后的目录 进入后可以看到解压出的源码文件如下 配置生成Makefile 在源码个目录下执行如下命令 –host为指定交叉编译器为arm-linux-

    2024年02月07日
    浏览(11)
  • ARM开发,stm32mp157a-A7核(UART总线实验)

    ARM开发,stm32mp157a-A7核(UART总线实验)

    ---.h头文件--- ---.c功能实现文件--- ---.c主函数测试文件--- 结果: 字符:  字符串: 

    2024年02月11日
    浏览(11)
  • arm学习stm32之spi总线数码管倒计时,裸机开发,soc

    arm学习stm32之spi总线数码管倒计时,裸机开发,soc

    由于时间没有用时间计时器操作,有些误差,后续有空会翻新计时器版本 main.c spi.c spi.h

    2024年02月16日
    浏览(4)
  • ARM开发,stm32mp157a-A7核中断实验(实现按键中断功能)

    ARM开发,stm32mp157a-A7核中断实验(实现按键中断功能)

    ---key.h头文件--- ---key.c函数实现--- ---do_irq.c终端处理函数--- ---main.c测试文件---

    2024年02月11日
    浏览(8)
  • 使用arm-none-eabi-gcc编译器搭建STM32的Vscode开发环境

    make:Windows中没有make,但是可以通过安装MinGW或者MinGW-w64,得到make。 gcc-arm-none-eabi:建议最新版,防止调试报错 OpenOCD vscode cubeMX Arm Assembly:汇编文件解析 C/C++:c语言插件 Cortex-Debug:调试插件 gcc-arm-none-eabibin OpenOCDbin 建议MinGW-make工具重命名为make.exe并添加到gcc-arm-none-eabi

    2024年02月06日
    浏览(16)
  • ARM开发,stm32mp157a-A7核SPI总线实验(实现数码管的显示)

    ARM开发,stm32mp157a-A7核SPI总线实验(实现数码管的显示)

            a.数码管显示相同的值 0000 1111 ......9999;         b.数码管显示不同的值 1234; ---spi.h头文件--- ---spi.c函数文件--- ---main.c测试文件--- a.数码管显示相同的值 0000 1111 ......9999; b.数码管显示不同的值 1234;

    2024年02月11日
    浏览(12)
  • ARM开发,stm32mp157a-A7核IIC实验(采集温湿度传感器值)

    ARM开发,stm32mp157a-A7核IIC实验(采集温湿度传感器值)

    ---iic.h封装时序协议头文件--- ---iic.c封装时序函数实现--- ---si7006.h读取温湿度头文件--- ---si7006.c读取温湿度函数--- ---main.c主函数测试---

    2024年02月11日
    浏览(23)
  • 【stm32f4 C++与C混合开发】建立keil5的ARM Compiler 6(AC6)标准库开发工程

    【stm32f4 C++与C混合开发】建立keil5的ARM Compiler 6(AC6)标准库开发工程

    一:请先确保keil5的版本为5.30版本以上,笔者这里是5.36版本: 二:F4标准库的pack包本版是2.9.0以上,笔者这里是2.15版本: 上述资源可在https://zhuanlan.zhihu.com/p/262507061找到 提示:本工程创建用例基于正点原子的F407标准库例程 工程如下图所示: 把工程拷贝一份新工程到纯英文

    2024年02月15日
    浏览(27)
  • arm-none-eabi-size 查看内存映像大小

    一、概述 1.1 功能 1.2 命令格式 1.3 支持的目标文件 二、基本应用示例 2.1 查看单个对象文件 2.2 查看整个工程的内存映像 三、命令选项描述 3.1 以不同的进制格式显示内存映像 示例:以十六进制格式显示 3.2 不同的输出方式 3.2.1 可选的表示方式与对应的选项 3.2.2 -A (–format=

    2024年02月09日
    浏览(11)
  • 什么是ARM,STM32?

    什么是ARM,STM32?

    🙌秋名山码民的主页 😂oi退役选手,Java、大数据、单片机、IoT均有所涉猎,热爱技术,技术无罪 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 获取源码,添加WX STM32是意法半导体公司推出的32位ARM Cortex-M系列微控制器(MCU)的一种品牌。这些MCU功能丰富、性能卓越、功耗低、价格

    2024年02月03日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包