什么叫程序映像

一、基本概念
什么是arm的映像文件,arm映像文件其实就是可执行文件,包括bin或hex两种格式,可以直接烧到rom里执行。
映像文件一般由域组成,域最多由三个输出段组成(RO,RW,ZI)组成,输出段又由输入段组成。在scatterfile中可以为每一个代码或数据区在装载和执行时指定不同的存储区域地址,所谓域,指的就是整个bin映像文件所处在的区域。
Scatlerloading的存储区块可以分成二种类型:装载域:当系统启动或加载时应用程序的存放区。执行域:系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行块。映像中所有的代码和数据都有一个装载地址和运行地址(二者可能相同也可能不同,视具体情况而定)。在系统启动时,C函数库中的__main初始化代码会执行必要的复制及清零操作,使应用程序的相应代码和数据段从装载状态转入执行状态。
我们输入的代码,一般有代码部分和数据部分,这就是所谓的输入段,经过编译后就变成了bin文件中ro段和rw段,还有所谓的zi段,这就是输出段。对于加载域中的输出段,一般来说ro段后面紧跟着rw段,rw段后面紧跟着zi段。在运行域中这些输出段并不连续,但rw和zi一定是连着的。zi段和rw段中的数据其实可以是rw属性。

 

 

http://www.eeworld.com.cn/mcu/article_2016063027305.html

1.ELF格式文件的结构


1.1映像文件组成部分


**一个映像文件有一个或多个域组成
**每个域包含一个或多个输出段
**每个输出段包含一个或多个输入段
**各输入段中包含了目标文件中的代码和数据

输入段中包含了四类内容:代码、已经初始化的数据、未经初始化的存储区域、内容初始化成0的存储区域。每个输入段有相应的属性,可以为只读的(RO)、可读写的(RW)以及初始化成0的(ZI)。ARM连接器根据个输入段的属性将这些输入段分组,再组成不同的输出段及域。
一个输出段中包含了一系列的具有相同的RO、RW和ZI属性的输入段。输出段的属性与其中包含的输入段的属性相同。在一个输出段的内部,各输入段是按照一定的规则排序的,这将在1.3节油详细地介绍。
一个域中包含1-3个输出段,其中个输出段的属性各不相同。各输出段的排列顺序是由其属性决定的。其中RO属性的输出段排在最前面,其次是RW属性的输出段,最后是ZI属性的输出段。一个域通常映射到一个物理存储器上,如ROM或RAM。


1.2ARM映像文件各组成部分的地址影射


ARM映像文件各组成部分在存储系统中的地址有两种:一种是映像文件位于存储器中时(也就是该映像文件运行之前)的地址,称之为加载地址;一种是映像文件运行时的地址,称之为运行时地址。之所以有这两种地址,是因为映像文件在运行时,其中的有些域是可以移动的新的存储区域。比如,已经初始化的RW属性的数据所在的段运行之前可能保存系统的ROM中,在运行时,他被移动至RAM中。
通常,一个映像文件包含若干个域,各域又包含若干的输出段。ARM连接器需要知道如下的信息,已决定如何生成相应的映像文件。
**分组信息 决定如何将个输入段组织成相应的输出段和域。
**定位信息 决定个域在存储空间地址中的起始地址。
根据映像文件中地址映射的复杂程度,有两种方法来告诉arm连接器这些相关信息。对于映像文件中地址映射关系比较简单的情况,可以使用命令行选项;对于映像文件中地址映射关系比较复杂的情况,可以使用一个配置文件。

 

2.arm映像文件的入口点


2.1arm映像文件的入口点有两种类型:一种是映像文件运行时的入口点,称为初始入口点(initial entry point),另一种是普通入口点(entry point).
初始入口点是映像文件运行时的入口点,每个映像文件只有一个唯一的初始入口点,它保存在ELF头文件中。如果映像文件是被操作系统加载的,操作系统是通过跳转到该初始入口点处来加载该映像文件。
普通的入口点是在汇编中用ENTRY伪操作定义。他通常用于标志该段代码是通过异常中断处理程序进入的。这样连接器删除无用的段时不会将该段代码删除。一个映像文件中可以定义多个普通入口点。
应该注意的是,初始入口点可以使普通入口点,但也可以不是普通入口点。


2.2定义初始入口点


初始入口点必须满足下面两个条件:
**初始入口点必须位于映像文件的运行时域内。
**饱含初始入口点的运行时域不能被覆盖,他的加载地址和运行地址必须是相同的。
可以使用连接选项-entry address来指定映像文件的初始入口点。这时,address指定了映像文件的初始入口点的地址值。
对于地址0x0处为rom的嵌入式应用系统,可以使用-entry 0x0来指定映像文件的初始入口点。这样当系统复位后,自动跳转到该入口开始执行。
如果映像文件是被一个加载器加载的,该映像文件该映像文件必须包含一个初始化入口点。这种映像文件通常还包含了其他普通入口点,这些普通入口点一般为异常中断处理程序的入口地址。
当用户没有指定-entry address时,连接器根据下面的规则决定映像文件的初始入口点。
**如果输入的目标文件中只有一个普通入口点,该普通入口点被连接器当成映像文件的初始入口点。
**如果输入的目标文件中没有一个普通入口点,或者其中的普通入口点多于一个,则连接器生成的映像文件中不包含初始入口点,并产生警告信息。


2.3普通入口点的用法


普通入口点是在汇编中用ENTRY 伪操作定义。在嵌入式应用中,各异常中断的处理程序入口使用普通入口点标示。这样连接器在删除无用段时不会将该段代码删除。
一个映像文件中可以定义多个普通入口点。没有指定连接选项-entry addres时,如果输入的目标文件中只有一个普通入口点,该入口点被连接器当成映像文件的初始入口点。

 


   3输入段的排序规则

   连接器根据输入段的属性来组织这些输入段,具有相同属性的输入段被放到域中一段连续的空间中,组成一个输出段。在一个输出段中,各输入段的起始地址与

输出段的起始地址和该输出段中个输入段的排列顺序有关。
通常情况下,一个输出段中个输入段的排列顺序由下面几个因素决定的。用户可以通过连接选项-first和-last来改变这些规则。
**输入段的属性。
**输入段的名称
**各输入段在连接命令行的输入段列表中的排列顺序
按照输入段的属性,其排列顺序如下所示:
**只读的代码段
**只读的数据段
**可读写的代码段
**其他已经初始化的数据段
**未出世化的数据
对于具有相同属性的输入段,按照其名称来排序。这是输入段名称是区分大小写的,按照其ASCII码顺序进行排序。
对于具有相同属性和名城的输入段,按照其在输入段列表中的顺序进行排序。也就是说,几十个输入段的属性和名称保持不变,如果其在编译时,各输入段在输

入段列表中的排列顺序不同,生成的映像文件也将不同。
可以通过连接选项-first和-last来改变这些规则。如果连接时使用了配置文件,可以在配置文件中通过伪属性FIRST和LAST达到相同的效果。
连接选项-first和-last不能改变根据输入段进行排序的规则,它只能改变根据输入段名称和其在输入列表中的顺序的排序规则。也就是说,如果使用-first指定

一个输入段,只有该输入段所在的输出段位于运行时域的开始位置时,该输入段才能位于整个运行时域的开始位置。
各个输入段排好顺序后,在确定各个输入段的起始地址之前,何以通过填充补丁是个输入段满足地址对齐的要求。

***********************************************************

ARM连接器介绍

***********************************************************

ARM连接器armlink将编译得到的ELF格式文件以及相关的C/C++运行时库连接生成相应的结果文件。armlink可以完成下面的操作:
**连接编译后得到的目标文件相应的c/c++运行时库,生成可执行的影像文件。
**将一些目标文件进行连接,生成一个新的目标文件,供将来进一步连接时使用,这成为部分连接。
**指定代码和数据在内存中的位置。
**生成被连接文件的调试信息和相互间的引用信息。
Armlink在进行部分连接和完全生成可执行文件时作进行的操作是不同的。下面分别介绍:
(1)解析输入的目标文件之间的符号引用关系。
(2)根据输入目标文件对c/c++函数的调用关系,从c/c++运行时库中提取相应模块。
(3)将各个输入段排序,组成相应的输出段。
(4)删除重复的调试信息。
(5)根据用户指定的分组和定位信息,建立映像文件的地址映射关系。
(6)重定位需要重定位的值。
(7)生成可执行的映像文件。
armlink在进行部分连接生成新的目标文件时执行下面的操作。
(1)删除重复的调试信息
(2)最小化符号表的大小
(3)保留那些未被解析的符号
(4)生成新的目标文件
下面根据各armlink的命令行选项的功能分类列举了armlink的命令行选项,各选项的具体用法将在后面有详细地介绍。
**提供关于armlink的帮助信息
**指定输出文件的名称和类型:*-output;*-partial;*-elf
**使用选项文件,其中可以包含一些连接选项。
**制定可执行映像文件的内存映射关系。*-rwpi;*-ropi;*-rw_base;*-ro_base;*-spit;*-scatter
**控制可执行映射文件的内容。*-first;*-last
**生成与映像文件的相关信息
**控制armlink生成相关的诊断信息。

关键字:ARM  基础知识  映像文件

<think>我们正在讨论的是“程序映像”在软件开发或嵌入式系统中的含义和作用。根据引用[2]中的描述,程序映像是指通过连接器将目标文件与存储器布局设置连接后生成的可执行文件(如.axf文件),它可以转化为二进制文件(.bin)或十六进制文件(.hex)。这种文件包含了程序的所有代码、数据以及必要的元信息,可以直接加载到目标硬件上运行。在嵌入式系统中,程序映像尤为重要,因为嵌入式设备通常没有操作系统(或使用轻量级RTOS),程序需要直接运行在硬件上。程序映像的布局必须符合目标硬件的存储器结构,例如将代码段放在Flash中,数据段放在RAM中。###程序映像的定义程序映像(ProgramImage)是指存储在非易失性存储器(如Flash)中的完整可执行程序,它包含:1.**代码段(TextSegment)**:存放可执行指令2.**数据段(DataSegment)**:-已初始化的全局变量和静态变量-常量数据(如字符串常量)3.**未初始化数据段(BSSSegment)**:存放未初始化的全局变量和静态变量(运行时初始化为零)4.**堆栈信息(Heap/Stack)**:在运行时动态分配的空间在嵌入式系统中,程序映像通常还包括:-**中断向量表**:位于存储器的起始位置,指向各种异常处理程序-**启动代码(StartupCode)**:初始化堆栈指针、配置内存、调用`main()`函数###程序映像在软件开发中的作用1.**硬件执行基础**程序映像是微控制器(MCU)上电后直接加载执行的实体。MCU复位后,从固定地址(通常为0x00000000)获取初始堆栈指针(SP)和程序计数器(PC)值,并开始执行启动代码。2.**存储器布局管理**通过链接脚本(LinkerScript)控制程序映像中各段的存储位置,例如:```ldMEMORY{FLASH(rx):ORIGIN=0x08000000,LENGTH=512KRAM(rwx):ORIGIN=0x20000000,LENGTH=128K}SECTIONS{.text:{*(.text*)}>FLASH.data:{*(.data*)}>RAMAT>FLASH/*初始数据存储在Flash,运行时复制到RAM*/.bss:{*(.bss*)}>RAM}```3.**固件更新依据**程序映像的二进制格式(.bin或.hex)是固件烧录和OTA(空中升级)的标准载体。例如,STM32通过Bootloader将.bin文件写入Flash。4.**调试信息载体**带调试符号的映像文件(如.axf)支持源码级调试。调试器通过映像中的符号表关联机器码与源代码位置。###程序映像生成过程引用[2]描述了典型的交叉编译流程:1.**编译(Compile)**:源文件(.c/.s)→目标文件(.o)2.**链接(Link)**:目标文件+链接脚本→可执行映像(.axf)3.**格式转换(Convert)**:.axf→.bin/.hex(烧录格式)###示例:程序映像在启动过程中的作用```c//启动文件(startup_stm32.s)片段Reset_Handler:/*1.初始化.data段(从Flash复制到RAM)*/ldrr0,=_sdata//RAM中.data段起始地址ldrr1,=_edata//RAM中.data段结束地址ldrr2,=_sidata//Flash中.data段初始值起始地址movsr3,#0bLoopCopyDataInitCopyDataInit:ldrr4,[r2,r3]strr4,[r0,r3]addsr3,r3,#4LoopCopyDataInit:addsr4,r0,r3cmpr4,r1bccCopyDataInit/*2.清零.bss段*/ldrr0,=_sbssldrr1,=_ebssmovsr3,#0bLoopFillZerobssFillZerobss:strr3,[r0]addsr0,r0,#4LoopFillZerobss:cmpr0,r1bccFillZerobss/*3.调用主函数*/blmain```###关键点总结-**程序映像=代码+数据+元信息**它是硬件可执行的完整程序表示形式。-**与本地程序的区别**嵌入式程序映像需严格匹配硬件存储结构(如STM32的Flash起始地址为0x08000000)。-**优化意义**合理布局程序映像可提升执行效率(如将热点代码放入零等待Flash区)。§§相关问题§§1.链接脚本(LinkerScript)在程序映像生成中起什么作用?2.如何验证程序映像在Flash中的正确性?3.程序映像中的中断向量表结构是怎样的?4.固件升级时如何确保程序映像的完整性?</think>### 程序映像(Program Image)的定义与作用 #### **定义** **程序映像**是指将编译后的可执行程序(包括代码、数据和资源)以特定格式存储在存储介质中的完整副本。它是源代码经过编译、链接后生成的最终二进制文件,可直接被操作系统或硬件加载执行。在嵌入式系统中,程序映像通常指烧录到微控制器(MCU)Flash中的固件文件(如`.bin`、`.hex`或`.axf`格式)。 #### **关键组成部分** 1. **代码段(Text Segment)** - 存储可执行指令(如函数、算法)。 - 在嵌入式系统中通常固化在Flash中。 2. **数据段(Data Segment)** - **初始化数据**:全局变量、静态变量(如`int global = 10;`)。 - **未初始化数据(BSS段)**:运行时初始化为零的变量(如`static int buffer[100];`)。 3. **堆栈(Heap/Stack)** - **堆**:动态分配的内存(`malloc`分配)。 - **栈**:局部变量、函数调用上下文。 4. **元信息** - 调试符号(如`.axf`文件中的地址-源码映射)。 - 中断向量表(MCU启动时加载的异常处理入口)。 #### **在软件开发中的作用** 1. **硬件执行的直接载体** - 嵌入式系统上电后,Bootloader直接从Flash加载程序映像到RAM执行。 - 示例:STM32启动时从`0x08000000`(Flash起始地址)加载中断向量表[^2]。 2. **存储空间优化** - 通过链接脚本(Linker Script)精确控制各段存储位置: ```ld MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } SECTIONS { .text : { *(.text*) } > FLASH /* 代码段放Flash */ .data : { *(.data*) } > RAM /* 数据段放RAM */ } ``` 3. **固件升级与调试** - 程序映像(如`.bin`文件)是OTA(空中升级)的传输单元。 - 带调试符号的映像(如`.axf`)支持源码级调试(通过JTAG/SWD)。 4. **安全验证** - 完整性校验:通过CRC或哈希值确保映像未被篡改。 - 版本管理:映像头部可包含版本号、编译时间等元数据。 #### **生成过程(以嵌入式开发为例)** 1. **编译**:`.c` → `.o`(目标文件) 2. **链接**:`.o` + 链接脚本 → `.elf`(可执行链接格式) 3. **格式转换**:`.elf` → `.bin`(二进制映像) ```bash arm-none-eabi-objcopy -O binary firmware.elf firmware.bin ``` 4. **烧录**:将`.bin`写入MCU Flash。 #### **示例:程序映像在启动时的行为** 当MCU复位时: 1. 从Flash固定地址(如`0x08000000`)读取初始栈指针(SP)。 2. 从`0x08000004`读取复位向量(Reset Handler地址)。 3. 跳转到`Reset_Handler`初始化.data/.bss段,最后调用`main()`[^2]。 --- ### 相关问题 1. **链接脚本如何控制程序映像中各段(如`.text`、`.data`)的内存布局?** 2. **程序映像中的中断向量表在ARM Cortex-M架构中是如何工作的?** 3. **固件升级时如何确保程序映像的完整性和安全性?** 4. **调试符号(如`.axf`文件)在程序映像崩溃分析中起什么作用?**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值