ARM 之十 ARMCC(Keil) map 文件(映射文件)详解

注意:因为没有找到 CSDN 的 Markdown 编辑器显示两对连续的 $$ 的方法,因此本文中的两个连续的 $ $ 之间有个空格。实际应该把空格去掉。例如 $$ 内容 $$ (不以代码形式时)显示异常,只能改为 $ $ 内容 $ $来显示。

map 文件是什么

  map 文件对应的中文名应该是映射文件,用来展示(映射)项目构建的链接阶段的细节。通常包含程序的全局符号、交叉引用和内存映射等等信息。目前,大多数编译套件(主要是其中的链接器)都可以生成 Map 文件。常见的 gcc、VC、IAR 都可以输出 map 文件。
  在 ARM 的官方文档中,并没有找到有关于 ARM 内核的 map 文件的介绍文档。不过倒是有个 C51 生成的 map 文件的说明文档:Listing (MAP) File。但是 C51 的 map 文件和 ARM 核的 map 文件差别比较大,也没啥参考价值!
  map 文件就是用来展示链接器工作过程的东西。想要了解 map 文件还需要对 ARM ELF 文件有一定的了解(可以参考博文ARM 之一 ELF文件、镜像(Image)文件、可执行文件、对象文件 详解)以及需要对于编译过程有一定的了解。下图显示了链接器在软件开发过程中的角色。链接器接受几种类型的文件作为输入,包括对象文件、命令文件、库和部分链接的文件。链接器创建一个可执行对象模块。
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第1张图片

map 文件从哪来

  map 文件是由编译套件中的链接器产生的。ARM 的编译套件中链接器为armlink,map 文件中的各信息均由armlink的各参数(–info topic、–map、–symbols等)控制输出(由 --list=filename 文件名输出到文件)。关于 ARM 编译套件的详细信息,参考博文ARM 之七 主流编译器(armcc、iar、gcc for arm)详细介绍 中关于 ARM 链接器的详细参数。下面是 armlink 的和 map 文件有关的参数介绍

–list=filename 参数

将诊断输出重定向到文件。

语法

--list=filename。其中 filename 是用于保存诊断输出的文件。 文件名可以包含路径。

使用

  将参数 --info, - map, - symbol, - verbose, - xref, - xreffrom 和 --xrefto的诊断信息输出重定向到文件。
  输出诊断信息时将创建指定的文件。 如果已存在同名文件,则会覆盖该文件。 但是,如果未输出诊断,则不会创建文件。 在这种情况下,具有相同名称的任何现有文件的内容保持不变。如果指定了 filename 而没有路径,则会在输出目录中创建它,即输出镜像的写入目录。

–info=topic[,topic,…] 参数

打印有关指定主题的信息。您可以使用 --list=file参数将输出内容写入文本文件。

语法

--info=topic[,topic,…]。其中 topic 是以下主题关键字的逗号分隔列表:

  • any:对于使用 .ANY 模块选择器的节区,列出:

    • The sort order.
    • The placement algorithm.
    • The sections that are assigned to each execution region in the order they are assigned by the placement algorithm.
    • Information about the contingency space and policy used for each region.

    在分散加载文件中使用执行区域属性 ANY_SIZE 时,此关键字还会显示其他信息。

  • architecture:通过列出处理器,FPU和字节顺序来归纳镜像架构。

  • common:Lists all common sections that are eliminated from the image. Using this option implies --info=common,totals.

  • compression:Gives extra information about the RW compression process.

  • debug:Lists all rejected input debug sections that are eliminated from the image as a result of using --remove. Using this option implies --info=debug,totals.

  • exceptions:Gives information on exception table generation and optimization.

  • inline:Lists all functions that are inlined by the linker, and the total number of inlines if --inline is used.

  • inputs:Lists the input symbols, objects and libraries.

  • libraries:Lists the full path name of every library automatically selected for the link stage.You can use this option with --info_lib_prefix to display information about a specific library.

  • merge:Lists the const strings that are merged by the linker. Each item lists the merged result, the strings being merged, and the associated object files.

  • sizes:列出镜像中每个输入对象和库成员的代码和数据(RO数据,RW数据,ZI数据和调试数据)大小。 使用此选项意味着–info=sizes,totals。

  • stack:Lists the stack usage of all functions.

  • summarysizes:Summarizes the code and data sizes of the image.

  • summarystack:Summarizes the stack usage of all global symbols.

  • tailreorder:Lists all the tail calling sections that are moved above their targets, as a result of using --tailreorder.

  • totals:列出输入对象和库的代码和数据(RO数据,RW数据,ZI数据和调试数据)大小的总和。

  • unused:列出由于使用 --remove 而从用户代码中删除的所有未使用的部分。 它不会列出从 ARM C 库加载的任何未使用的部分。

  • unusedsymbols:Lists all symbols that have been removed by unused section elimination.

  • veneers:列出链接器生成的胶合代码。

  • veneercallers:Lists the linker-generated veneers with additional information about the callers to each veneer. Use with --verbose to list each call individually.

  • veneerpools:Displays information on how the linker has placed veneer pools.

  • visibility:Lists the symbol visibility information. You can use this option with either --info=inputs or --verbose to enhance the output.

  • weakrefs:Lists all symbols that are the target of weak references, and whether or not they were defined.

用法

--info=sizes,totals 的输出始终包含输入对象和库的总计中的填充值。如果使用 RW 数据压缩(默认值),或者使用 --datacompressor=id 选项指定了压缩器,则 --info=sizes,totals 的输出包括 Grand Totals 下的条目以反映真实镜像大小。列表中的主题关键字之间不允许有空格。

Keil 配置

  如果使用 Keil,则可以直接在 Keil 的设置界面来选择,如下图:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第2张图片
其中,各选项的基本功能如下:

  • Select Folder for Listings…:选择存储清单文件的文件夹。
  • Page Width:为清单文件指定每行字符数。
  • Page Length:为清单文件指定每页的行数。
  • Assembler Listing:为汇编源文件创建列表文件。
    • Cross Reference:列出有关符号的交叉引用信息,包括它们的定义位置以及宏的内部和外部的使用位置。
  • C Compiler Listing:为C源文件创建列表文件。
  • C Preprocessor Listing:指示编译器生成预处理文件。 宏调用将被展开并且注释将被删除。
  • Linker Listing:从链接器为目标项目创建映射文件(map 文件)。对应的armlink参数为--list=filename,如果不选择则不会生成文件。
    • Memory Map:包含一个内存映射,其中包含镜像中每个加载区,执行区和输入节的地址和大小,包括调试和链接器生成的输入节。对应的armlink参数为--map
    • Callgraph:以 HTML 格式创建函数的静态调用图文件。 调用图给出了镜像中所有函数的定义和参考信息。对应的armlink参数为--callgraph。该项会独立生成一个配置的输出名.htm的文件。如下图所示:
      ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第3张图片
      其中显示了详细的调用关系。最重要的是,其中还有使用的栈的大小!
    • Symbols:列出本地,全局和链接器生成的符号以及符号值。对应的armlink参数为--symbols
    • Cross Reference:列出输入节之间的所有交叉引用。对应的armlink参数为 --xref
    • Size Info:给出镜像中每个输入对象和库成员的代码和数据(RO数据,RW数据,ZI数据和调试数据)的大小的列表。对应的armlink参数为 --info sizes
    • Totals Info:提供输入对象和库的代码和数据(RO数据,RW数据,ZI数据和调试数据)大小的总和。对应的armlink参数为 --info totals
    • Unused Section Info:列出从镜像中删除的所有未使用的部分。对应的armlink参数为 --info unused
    • Veneers Info:提供链接器生成的 Thumb/ARM 胶合代码的详细信息。对应的armlink参数为 --info veneers

以上的选项其实就是选择链接器 armlink 的各参数!下文中均以使用的具体参数来介绍。

map 文件有啥用

map 文件对于分析问题是非常有用的!

  1. 分析问题
  2. 优化程序
  3. 了解连接过程

map 文件中的符号

   在 map 文件中,有很多符号是编译套件的开发商预定义好的,用户的符号不能与编译套件的开发商预定义好的符号冲突。以下内容来自于 ARM 的链接器手册!关于如何导入这些符号,链接器的手册有专门的章节来介绍!

About mapping symbols

  映射符号由编译器和汇编器生成,以识别文字池边界处的代码和数据之间的内联转换,以及 ARM 代码和 Thumb 代码之间的内联转换。例如 ARM/Thumb 交互操作胶合代码。其必须由 armlink 的参数 --list_mapping_symbols--no_list_mapping_symbols 分别来控制显示与不显示。在默认情况下为 --no_list_mapping_symbols,即不显示这部分符号。映射符号有如下这些:

  • $a:一系列 ARM 指令的开始
  • $t:一系列 Thumb 指令的开始
  • $t.x:一系列 ThumbEE 指令的开始
  • $d:一系列数据项的开始,如文字池

需要注意与参数 --symbols--no_symbols 控制的符号的区别!这里的符号由 armlink 生成 $d.realdata 映射符号,以便与 fromelf 通信该数据来自非可执行节区。 因此,fromelf -z 输出的代码和数据大小与armlink --info sizes的输出相同,例如:

Code (inc. data)   RO Data
   x          y          z

在以上的示例中,y 标记为 $d,RO Data 标记为 $d.realdata。如果启用了该参数,则会在 map 文件中有体现,如下图:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第4张图片
  以字符 $v 开头的符号是与 VFP 相关的映射符号,在使用 VFP 构建目标时可能会输出。 避免在源代码中使用以 $v 开头的符号。请注意,使用fromelf --elf --strip=localsymbols命令修改可执行镜像会从镜像中删除所有映射符号。

Linker-defined symbols

  链接器定义了 ARM 保留的一些符号。包含字符序列 $ $ 的符号,以及包含序列 $ $ 的所有其他外部名称,是 ARM 保留的名称。您可以导入这些符号的地址,并将它们用作汇编语言程序的可重定位地址,或者将它们作为 C 或 C++ 源代码中的外部符号引用。

  • 如果使用--strict 编译器命令行选项,则编译器不接受包含 $ 的符号名称。 要重新启用支持,请在编译器命令行中包含 --dollar 选项。
  • 链接器定义的符号仅在代码引用它们时生成。

Region-related symbols

  链接器生成各种类型的 Region 相关符号,您可以根据需要访问这些符号。如果您使用的是分散加载文件,则会为分散加载文件中的每个区域生成这些符号。如果未使用分散加载文件,则会以默认的 region 名称来生成符号。 也就是说,region 名称是固定的,并且提供相同类型的符号。

Image$ $ execution region symbols

  链接器为镜像中存在的每个执行区域生成 Image$ $ 符号。下表显示了链接器为镜像中存在的每个执行区域生成的符号。 初始化 C 库后,所有符号都指向执行地址。

Symbol Description
Image$ $region_name$ $Base Execution address of the region.
Image$ $region_name$ $Length Execution region length in bytes excluding ZI length.
Image$ $region_name$ $Limit Address of the byte beyond the end of the non-ZI part of the execution region.
Image$ $region_name$ $RO$ $Base Execution address of the RO output section in this region.
Image$ $region_name$ $RO$ $Length Length of the RO output section in bytes.
Image$ $region_name$ $RO$ $Limit Address of the byte beyond the end of the RO output section in the execution region.
Image$ $region_name$ $RW$ $Base Execution address of the RW output section in this region.
Image$ $region_name$ $RW$ $Length Length of the RW output section in bytes.
Image$ $region_name$ $RW$ $Limit Address of the byte beyond the end of the RW output section in the execution region.
Image$ $region_name$ $XO$ $Base Execution address of the XO output section in this region.
Image$ $region_name$ $XO$ $Length Length of the XO output section in bytes.
Image$ $region_name$ $XO$ $Limit Address of the byte beyond the end of the XO output section in the execution region.
Image$ $region_name$ $ZI$ $Base Execution address of the ZI output section in this region.
Image$ $region_name$ $ZI$ $Length Length of the ZI output section in bytes.
Image$ $region_name$ $ZI$ $Limit Address of the byte beyond the end of the ZI output section in the execution region.

Load$ $ execution region symbols

  链接器为镜像中存在的每个执行区域生成 Load$ $ 符号。Load$ $region_name 符号仅适用于执行区域。Load$ $LR$ $load_region_name 符号仅适用于加载区域。下表显示了链接器为镜像中存在的每个 Load$ $ 执行区域生成的符号。 初始化 C 库后,所有符号都指向加载地址。

Symbol Description
Load$ $region_name$ $Base Load address of the region.
Load$ $region_name$ $Length Region length in bytes.
Load$ $region_name$ $Limit Address of the byte beyond the end of the execution region.
Load$ $region_name$ $RO$ $Base Address of the RO output section in this execution region.
Load$ $region_name$ $RO$ $Length Length of the RO output section in bytes.
Load$ $region_name$ $RO$ $Limit Address of the byte beyond the end of the RO output section in the execution region.
Load$ $region_name$ $RW$ $Base Address of the RW output section in this execution region.
Load$ $region_name$ $RW$ $Length Length of the RW output section in bytes.
Load$ $region_name$ $RW$ $Limit Address of the byte beyond the end of the RW output section in the execution region.
Load$ $region_name$ $XO$ $Base Address of the XO output section in this execution region.
Load$ $region_name$ $XO$ $Length Length of the XO output section in bytes.
Load$ $region_name$ $XO$ $Limit Address of the byte beyond the end of the XO output section in the execution region.
Load$ $region_name$ $ZI$ $Base Load address of the ZI output section in this execution region.
Load$ $region_name$ $ZI$ $Length Load length of the ZI output section in bytes.
The Load Length of ZI is zero unless region_name has the ZEROPAD scatter-loading
keyword set. If ZEROPAD is set then:
Load Length = Image$ $region_name$ $ZI$ $Length
Load$ $region_name$ $ZI$ $Limit Load address of the byte beyond the end of the ZI output section in the execution region.

此表中的所有符号都是在初始化 C 库之前引用加载地址。请注意以下事项:

  • 这些符号是绝对的,因为相对于节的符号只能有执行地址。
  • 这些符号考虑了RW压缩。
  • 从 RW 压缩执行区引用链接器定义的符号必须是在应用RW压缩之前可解析的符号。
  • 如果链接器检测到从 RW 压缩区域重定位到依赖于 RW 压缩的链接器定义符号,则链接器将禁用该区域的压缩。
  • 通过Limit和Length值考虑写入文件的任何零初始化数据。 使用ZEROPAD分散加载关键字时,零初始化数据将写入文件。

Load$ $LR$ $ load region symbols

  链接器为镜像中存在的每个加载区生成 Load$ $LR$ $ 符号。一个 Load$ $LR$ $ 加载区域可以包含许多执行区域,因此没有单独的 $ $RO 和 $ $RW 部分。Load$ $region_name 符号仅适用于执行区域。Load$ $LR$ $load_region_name 符号仅适用于加载区域。下表显示了链接器为镜像中存在的每个 Load$ $LR$ $ 加载区域生成的符号。

Symbol Description
Load$ $LR$ $load_region_name$ $Base Address of the load region.
Load$ $LR$ $load_region_name$ $Length Length of the load region.
Load$ $LR$ $load_region_name$ $Limit Address of the byte beyond the end of the load region.

Region name values

链接时未使用分散加载时,链接器使用默认区域名称值。 如果您不使用分散加载,则链接器使用以下区域名称值:

  • ER_XO : for an execute-only execution region, if present.对于仅执行属性的执行区域(如果存在)。
  • ER_RO : for the read-only execution region. 对于只读执行区域。
  • ER_RW : for the read-write execution region.对于可读写执行区域。
  • ER_ZI : for the zero-initialized execution region.对于零初始化的执行区域。

您可以将这些名称插入以下符号以获取所需的地址:

  • Image$ $ execution region symbols.
  • Load$ $ execution region symbols.

例如 Load$ $ER_RO$ $Base.

使用分散加载时,分散文件中的名称将用于链接器定义的符号中。分散加载文件可以实现以下功能:

  • 命名镜像中的所有执行区域,并提供其加载和执行地址。
  • 定义堆栈和堆。 链接器还会生成特殊的堆栈和堆符号。

Section-related symbols

与 Section 相关的符号是链接器在创建没有分散加载的镜像时生成的符号。链接器为输出和输入 Section 生成不同类型的 Section 相关的符号。

  • 镜像符号,如果不使用分散加载来创建简单的镜像文件。 简单的镜像文件具有多达四个输出 Section(XO,RO,RW 和 ZI),用于生成相应的执行区域。
  • 输入节符号,用于镜像中存在的每个输入节。

链接器首先按属性 RO,RW 或 ZI 对执行区域内的节进行排序,然后按名称排序。 因此,例如,所有 .text 节都放在一个连续的块中。 具有相同属性和名称的连续块部分称为合并节。

当您不使用分散加载文件来创建简单镜像时,链接器会生成镜像符号。下表显示了镜像符号:

Symbol Section type Description
Image$ $RO$ $Base Output Address of the start of the RO output section.
Image$ $RO$ $Limit Output Address of the first byte beyond the end of the RO output section.
Image$ $RW$ $Base Output Address of the start of the RW output section.
Image$ $RW$ $Limit Output Address of the byte beyond the end of the ZI output section.
(The choice of the end of the ZI region rather than the end of the RW region is to maintain compatibility with legacy code.)
Image$ $ZI$ $Base Output Address of the start of the ZI output section.
Image$ $ZI$ $Limit Output Address of the byte beyond the end of the ZI output section.

如果您使用分散加载文件,则镜像符号未定义。 如果您的代码访问这些符号中的任何一个,则必须将它们视为弱引用。__user_setup_stackheap() 的标准实现使用 Image$ $ZI$ $Limit 中的值。 因此,如果您使用的是分散加载文件,则必须手动放置堆栈和堆。 你也可以这样做:

  • 在分散文件中使用下列方法之一
    • 定义名为 ARM_LIB_STACK 和 ARM_LIB_HEAP 的单独栈和堆区域。
    • 定义包含堆栈和堆的组合区域,名为 ARM_LIB_STACKHEAP。
  • 通过重新实现 __user_setup_stackheap() 来设置堆和堆栈边界。

输入节符号由链接器为镜像中存在的每个输入节生成。下表显示了输入节符号:

Symbol Section type Description
SectionName$ $Base Input Address of the start of the consolidated section called SectionName.
SectionName$ $Length Input Length of the consolidated section called SectionName (in bytes).
SectionName$ $Limit Input Address of the byte beyond the end of the consolidated section called SectionName.

如果您的代码引用输入节符号,则假定您希望镜像中具有相同名称的所有输入节都连续放置在镜像内存映射中。如果分散加载文件不连续地放置输入节,则链接器会发出错误。 这是因为在非连续存储器上使用基本符号和限制符号是不明确的。

ARMCC(Keil)map 文件

  根据选择的参数不同,map 文件中的内容肯定是有变化的!下面以 Keil 中全选以上所说的参数后生成的 map 文件为例来进行说明。map 文件中,有如下图所示的五个大部分:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第5张图片
其中,每一部分都是对应上面的配置中的一个或者多个选项,也就是对应链接器armlink的一个或者多个参数

Section Cross References

  该部分显示了节区之间的交叉引用,指的是各个源文件生成的模块之间相互引用的关系。交叉引用中可以分为三大部分。

用户模块之间交叉引用

  这部分主要就是用户自己实现的代码之间的引用关系。例如gprs.o(i.GPRSGetBytes) refers to uart.o(i.UartGetData) for UartGetData 表示 gprs.o 中的函数GPRSGetBytes 引用了 uart.o 中的函数 UartGetData。其中的 gprs.o 是由用户代码 gprs.c 生成的模块; uart.o 使用用户源码 uart.c 生成的模块。

用户模块与 C 库交叉引用

  这部分主要就是用户自己实现的代码中调用 C 库函数时的引用关系。C 库的代码一般都是编译套件以二进制文件的形式提供的,用户看不到源码。例如 upcomm.o(i.UpCommFrameFilter) refers to memcmp.o(.text) for memcmp 表示 upcomm.o 中的函数UpCommFrameFilter 引用了 memcmp.o 中的函数 memcmp。其中,memcmp 为 C 库函数。再例如 startup_stm32f411xe.o(.text) refers to __main.o(!!!main) for __main 中的 __main 为程序的启动入口,其也位于 C 库中。
  在 ARM 编译套件中,所有的 C 库由工具armar来管理,位于 ARM 编译器目录 lib 下。使用 armar 即可从指定的库文件中解压出 __main.o 等模块。至于如何操作,参见博文ARM 之九 Cortex-M/R 内核启动过程 / 程序启动流程(基于ARMCC、Keil)。

C 库之间交叉引用

  C 库函数之间也有互相的引用关系。用户使用的 C 库函数之间的引用关系也会显示在该部分。例如 dflt_clz.o(x$fpl$dflt) refers (Special) to usenofp.o(x$fpl$usenofp) for __I$use$fp,其中所有的函数都是 C 库中的。同样可以使用armar解压库文件来导出符号表查看各接口。

Removing Unused input sections from the image

  这部分列出了链接器移除的我们源码中实际未使用的数据和函数。其中包含移除数据的大小。例如Removing flash.o(.rrx_text), (6 bytes). 表示移除flash.o中的 6 字节的数据;Removing virtualuart.o(i.VirtualUartBufClear), (92 bytes). 表示移除 virtualuart.o 中的函数 VirtualUartBufClear,共 92 字节。
  需要注意的是,被移除的函数在调试时将无法进行调试。如果不注意,在调试时很容易造成困扰。如下图所示:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第6张图片

Image Symbol Table

符号映射表。就是每个符号(这里的符号可以指模块、变量、函数)实际的地址等信息。

Local Symbols

不知道 ARMCC 是怎么分的 Local 和 Global。

Global Symbols

不知道 ARMCC 是怎么分的 Local 和 Global。

Memory Map of the image

  这部分给出了镜像文件的布局。这部分与分散加载文件(Scatter File) 有密切的关系。如果使用 Keil,在 Keil 的配置界面中有如下配置:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第7张图片
这里的设置就是对应的 map 文件中的内容。如果我们在链接器的配置页面不选择 Use Memory Layout from Taget Dialog,则需要如上图自己指定一个分散加载文件。其实,如果选择 Use Memory Layout from Taget DialogKeil 会根据我们左边的配置自行生成一个分散加载文件来给链接器使用(这个文件就在我们的编译输出指定的目录中)。上图的示例就是没有使用Keil默认,而是通过自己指定的分散加载文件生成镜像文件。
  以上的 Keil 配置,全部是是通过链接器的参数--scatter=filename来让链接器使用该文件的。分散加载文件一次性描述了我们的镜像文件怎么布局。了解链接器的应该知道,链接器还有一些独立使用的和镜像文件生成有关的参数:--first, --last, --partial, --reloc, --ro_base, --ropi,--rosplit, --rw_base, --rwpi, --split, --startup, --xo_base, and --zi_base.,如果使用了 --scatter=filename,则以上参数就不可再用了!Keil 就是直接使用的 --scatter=filename。(默认下,Keil 根据配置界面的配置,会成一个分散加载文件)。
接下来看看 map 文件中的内容,如下图:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第8张图片

  • Image Entry point 这个是镜像的入口点。就是镜像在被执行时,开始的位置(地址)。其就是指向了 0x08010218 0x00000008 Code RO 4985 * !!!main c_w.l(__main.o) 这一行。
  • Load Region LR_IROM1 加载域。这是个概念。
  • Execution Region ER_IROM1、Execution Region ER_IROM2、Execution Region ER_IROM3 这其中就是我们的代码以及使用的 C 库代码。
      我们先来介绍一下每个字段的含义。首先我们要明白,每一行就是一个节。
    Base Addr Size Type Attr Idx E Section Name Object
    节的基地址 节的大小 类型 属性 索引 节的名字 对象(节所属的文件模块)
      为什么有 3 个?因为我本身使用了自己写的分散加载文件。手动指定了三个执行域。我的分散加载文件如下
    ; *************************************************************
    ; *** Scatter-Loading Description File generated by ZCShou ***
    ; *************************************************************
    
    
    LR_IROM1 0x08010000 0x00030000  {    ; load region size_region
      ER_IROM1 0x08010000 0x00030000  {  ; load address = execution address
       *.o (RESET, +First)                ; 中断向量表
      }
    
      ER_IROM2 + 0 {                    ; 应用程序信息
       *.o (SECTION_APP_INFO, +First)
      }
    
      ER_IROM3 + 0 {                    ; 初始化相关代码+其他代码
       *(InRoot\$ \$Sections)    ; 初始化相关
       .ANY (+RO)            ; 其他所有代码
      }
    
      RW_IRAM1 0x20000000 0x00020000  {  ; 内存
       .ANY (+RW +ZI)
      }
    }
    
    在这三个执行域中,有很多类型为 PAD 的行,并且这些行没有节名字也没有所属的模块。这些其实是一些链接器自己添加的对齐。除了对齐没有其他作用。关于对齐本文之前的章节有介绍。除了 PAD 之外,剩下的就全是 Code 了。
  • Execution Region RW_IRAM1: 这个就是内存部分,存放我们的代码中用到的各种变量数据(常量数据在以上的 ER_IROM 中)。同样,该部分也有些对齐,除此之外全部是 Data、Zero、 HEAP(堆)、STACK(栈)。

Image component sizes

该部分列出了组成镜像的各部分内容的大小等详细信息。

  • 各列的具体含义如下:
    • Code (inc. data):这对应两列数据,分别表示代码占用的字节数和内联数据占用的字节数。inc. data 是内联数据(inline data)的缩写。 内联数据包括文字池和短字符串等。
    • RO Data:显示 RO 数据占用的字节数。这是 Code(inc. data)列中除去 inc. data 外的只读数据的字节数。 This is in addition to the inline data included in the Code (inc. data) column.
    • RW Data:显示 RW 数据占用的字节数。
    • ZI Data:显示 ZI 数据占用的字节数。
    • Debug:显示调试数据占用的字节数,例如,调试输入节以及符号和字符串表。
    • 最后一列:对象文件的名字。下面会有区分。
  • 特殊行的含义如下:
    • Object Totals:显示链接在一起以生成镜像的对象占用的字节数。
    • (incl. Generated):armlink 在生成镜像文件时,可能会产生一些额外数据(interworking veneers, and input sections such as region tables)。如果存在这些额外数据,那么他们就位于改行中显示。
    • Library Totals:显示已提取并作为单个对象添加到镜像的库成员占用的字节数。
    • (incl. Padding):如果需要,armlink 会插入填充以强制部分对齐。 如果 Object Totals 行包含此类数据,则会在相关的(incl. Padding)行中显示。 同样,如果 Library Totals 行包含此类数据,则会在其关联的行中显示。
    • Grand Totals:显示镜像文件的真实大小。
    • ELF Image Totals:如果使用 RW 数据压缩(默认值)来优化 ROM 大小,则最终镜像的大小会发生变化,这会反映在 --info 的输出中。 比较 Grand Totals 和 ELF Image Totals 下的字节数,以查看压缩效果。
    • ROM Totals:显示包含镜像所需的 ROM 的最小大小。 这不包括未存储在 ROM 中的 ZI 数据和调试信息。

用户模块

第一部分就是用户源码各模块的大小信息!如下图所示:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第9张图片

C 库模块

第二部分用户源码中使用的各 C 库模块的大小信息以及使用的 C 库文件名!如下图所示:
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第10张图片
这部分中,除了列出了库文件的独立单元模块的大小,还列出了我们的源码中实际使用的库文件。这个会根据我们源码中引用的库函数的不同而变化。

汇总信息

主要就是各部分数据的汇总大小,如下图所示
ARM 之十 ARMCC(Keil) map 文件(映射文件)详解_第11张图片
其中最下面的三行数据是汇总的再汇总,以方便我们的使用

  • Total RO Size:就是我们的可执行程序中常量数据(代码和只读数据)的大小。
  • Total RW Size:就是我们的可执行程序中需要占用的内存的大小。
  • Total ROM Size:就是我们的可执行程序本身的大小。这个大小就等于我们的可执行文件的大小。

  需要特殊注意的是,armlink 输出的是 .axf 文件,这个文件中包含调试信息,并不是我们需要使用的可执行文件,我们使用 fromelf 工具从中提取的文件才是真正的可执行文件。这里的汇总大小指定是实际使用的可执行文件的大小。关于这部分,参考博文ARM 之一 ELF文件、镜像(Image)文件、可执行文件、对象文件 详解。

参考

  1. ARM 的链接器用户手册:ARM® Compiler v5.06 for µVision® armlink User Guide
  2. ARM 的编译器用户手册:ARM® Compiler v5.06 for µVision® armcc User Guide

你可能感兴趣的:(ARM)