找回密码
 注册
关于网站域名变更的通知
查看: 480|回复: 2
打印 上一主题 下一主题

ARM之ARMCC(Keil)map 文件

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-1-28 10:14 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
' K# f$ s7 o& q* X8 M
ARMCC(Keil)map 文件2 f' X- K2 U3 J/ {8 Z/ D6 i' S" P, A
  根据选择的参数不同,map 文件中的内容肯定是有变化的!下面以 Keil 中全选以上所说的参数后生成的 map 文件为例来进行说明。map 文件中,有如下图所示的五个大部分:
$ H( x5 D7 N; D( p' F( t2 M# X
1 I, g0 d$ a) J6 a4 {/ e9 t" `: y$ v& i0 }5 ]) [
其中,每一部分都是对应上面的配置中的一个或者多个选项,也就是对应链接器armlink的一个或者多个参数
8 w( R+ G  D# n: b& A
& M2 ]$ P: _% b  t& E4 r$ L# R( P1 _, `8 E' M% a
Section Cross References* ?# G/ |; \  k+ }
6 \5 t# p+ B0 A. I/ [' [0 n; e
  该部分显示了节区之间的交叉引用,指的是各个源文件生成的模块之间相互引用的关系。交叉引用中可以分为三大部分。, K- N; ]  d$ ~9 p. p) m
7 o3 T0 d' ?. V5 l1 s7 T( {9 v3 y; P
用户模块之间交叉引用+ y2 N8 u, \4 [; D
3 P/ ?) w4 p. c
  这部分主要就是用户自己实现的代码之间的引用关系。例如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 生成的模块。
( j+ f4 G) t5 i0 T" e! l8 L
& m3 D) v0 Y2 n. V用户模块与 C 库交叉引用- S) R+ Z; _' `% i2 X' T
, ]/ R* `& \3 h/ ~' n
  这部分主要就是用户自己实现的代码中调用 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 库中。
" l1 h( L; Z! X; @' p
/ j+ q" l/ L9 \+ `4 P: a
8 H/ n% g1 m0 e2 [! x) u0 p  在 ARM 编译套件中,所有的 C 库由工具armar来管理,位于 ARM 编译器目录 lib 下。使用 armar 即可从指定的库文件中解压出 __main.o 等模块。至于如何操作,参见博文ARM 之九 Cortex-M/R 内核启动过程 / 程序启动流程(基于ARMCC、Keil)。
3 S6 g6 |6 \/ X* R2 g+ q
- z0 a2 [' l$ G% R+ n
  N( B4 S6 R- Q8 e: z& E9 K4 PC 库之间交叉引用/ Y+ k+ g9 o$ C  L/ {

+ j4 n+ h( O- o" K6 X" D/ W5 N  C 库函数之间也有互相的引用关系。用户使用的 C 库函数之间的引用关系也会显示在该部分。例如 dflt_clz.o(x$fpl$dflt) refers (Special) to usenofp.o(x$fpl$usenofp) for __I$use$fp,其中所有的函数都是 C 库中的。同样可以使用armar解压库文件来导出符号表查看各接口。* Y1 O7 N% J! W! L0 U

) @6 l7 b' p$ P5 b: M4 i5 L$ O( x5 D& j- }# ?5 \
Removing Unused input sections from the image
2 K7 I' I( W8 x( ?; w, U4 d, E. J3 Q7 W, J  ^/ G/ V! T) I' F9 G! j- w
  这部分列出了链接器移除的我们源码中实际未使用的数据和函数。其中包含移除数据的大小。例如Removing flash.o(.rrx_text), (6 bytes). 表示移除flash.o中的 6 字节的数据;Removing virtualuart.o(i.VirtualUartBufClear), (92 bytes). 表示移除 virtualuart.o 中的函数 VirtualUartBufClear,共 92 字节。
+ ]' B; O- |# m- n& u1 n* z% m8 R. C$ o$ i
3 P" R: u( L+ G. {/ m: i
  需要注意的是,被移除的函数在调试时将无法进行调试。如果不注意,在调试时很容易造成困扰。如下图所示:
2 ~  ?7 L" s" a$ ^, @( `4 ]. S" X5 c. o

5 r+ Y% }$ l4 ?
- y; \/ H* N; A' E5 f, M# J, N) y4 ~) ^

7 v4 J8 {0 \& J) }5 JImage Symbol Table
; {' y' T( J' x7 Q+ ^  T+ I7 k% ^" j, A4 ?
符号映射表。就是每个符号(这里的符号可以指模块、变量、函数)实际的地址等信息。
3 h& f, s1 k$ ^9 x8 N, p  m5 u: t9 a

) b* S' `" E8 |1 v) B! G3 @Local Symbols
7 D7 _4 O, D9 E3 z! H' A5 z* U, ~1 \8 }) M" i! @5 \" i
不知道 ARMCC 是怎么分的 Local 和 Global。
) T$ B' S/ s  B/ t7 Q" E* Z2 ]; ]  R. F$ [

* e/ i4 X7 w/ {0 F( g% I) VGlobal Symbols
1 |6 k) G( v8 _) ^3 F+ s$ v2 r  J. z3 r0 z5 W5 s! R; F1 [4 T  V
不知道 ARMCC 是怎么分的 Local 和 Global。
: f4 S* N9 K5 h( Z1 G8 I$ \  A9 Z9 ~
, V4 ?" a, D( J: n' ^+ V. Z2 Y4 X6 b3 ^; y* m2 q8 k* Q  a% w; x
Memory Map of the image
4 S5 G; v. Z+ k  ^. d! j8 S+ N8 Q5 a9 y, L! `
  这部分给出了镜像文件的布局。这部分与分散加载文件(Scatter File) 有密切的关系。如果使用 Keil,在 Keil 的配置界面中有如下配置:( O" H4 P5 U% _5 @9 C5 Z0 y

: o& N& C1 x0 G6 V( a
; W& H; E0 P) @7 X' v! Y* Z 1 ?6 X/ G# a6 M: P5 q

- w* a9 Q2 d3 |1 _这里的设置就是对应的 map 文件中的内容。如果我们在链接器的配置页面不选择 Use Memory Layout from Taget Dialog,则需要如上图自己指定一个分散加载文件。其实,如果选择 Use Memory Layout from Taget Dialog,Keil 会根据我们左边的配置自行生成一个分散加载文件来给链接器使用(这个文件就在我们的编译输出指定的目录中)。上图的示例就是没有使用Keil默认,而是通过自己指定的分散加载文件生成镜像文件。  i. t8 F% G! f! _

8 @+ s+ Q& U* }+ Y
- e0 G* ?/ h: U+ Q, Q9 w$ ?8 L) n* _  以上的 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 根据配置界面的配置,会成一个分散加载文件)。! Z; ^) h% ^% C9 G1 m! O

4 n( n9 ^: Q2 Z, x, {接下来看看 map 文件中的内容,如下图:+ `# j) [0 v7 T6 O( ?1 f

9 U# E5 z2 Z% y! V6 X. } & E# w. t  b: g+ _+ S$ T

* k1 i* j- b7 W5 y' U( N
  • 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 库代码。! n8 j! ~9 w$ ^6 {. {+ c

- z! [' D9 \$ `' ^1 P2 l  我们先来介绍一下每个字段的含义。首先我们要明白,每一行就是一个节。
- A7 \  c; n/ d/ d: [- Q! }! Q! C( ?+ _3 S( r
[color=rgba(0, 0, 0, 0.75)]Base AddrSizeTypeAttrIdxE Section NameObject
+ Z  R$ O: Z( p3 Y' ]& t6 I, B! K+ ~  s节的基地址节的大小类型属性索引节的名字对象(节所属的文件模块)

" P" S7 d1 X- r! U$ t  为什么有 3 个?因为我本身使用了自己写的分散加载文件。手动指定了三个执行域。我的分散加载文件如下:
+ ?) s* j: Y8 s& C) V  q
! T2 P9 o5 N: C& p; *************************************************************
/ P1 z  A, V6 x; R; A1 r; *** Scatter-Loading Description File generated by ZCShou ***5 Z1 K7 [2 z3 M5 _
; *************************************************************; y8 ^0 {0 H6 ~' O4 \
- x, e, }* L0 a" m4 T' p
; P7 Q7 G% K( J; V
LR_IROM1 0x08010000 0x00030000  {    ; load region size_region
6 S) J* p9 E4 T& f5 w4 ]9 Z  ER_IROM1 0x08010000 0x00030000  {  ; load address = execution address( H5 s# J7 k( I" Y6 x7 I+ p
   *.o (RESET, +First)                ; 中断向量表4 Z4 v. D, T% p/ t& i4 m
  }9 P* Q- j3 Q8 E! e

7 r' [" D$ W: ^8 P& w  ER_IROM2 + 0 {                    ; 应用程序信息) x& }; s- ^! f+ G4 U; I: h0 l
   *.o (SECTION_APP_INFO, +First)
/ W) h& a/ h4 K  }- y$ H8 C9 k1 |) U6 U

2 P, q' G8 X' H' h, i  ER_IROM3 + 0 {                    ; 初始化相关代码+其他代码& e( E: _9 l# P
   *(InRoot\$ \$Sections)    ; 初始化相关
( s. p- S2 Z4 [   .ANY (+RO)            ; 其他所有代码
5 K! N, \* W& l* d8 e6 k' @  }
8 v6 H: g( N  K# J2 G+ K. q( {/ A. K4 p. b5 q- l( v* `; Q
  RW_IRAM1 0x20000000 0x00020000  {  ; 内存
9 Q8 P; x  w% U& q   .ANY (+RW +ZI)
9 ~- H- S% [7 v  }
4 u4 p8 ~) M- S$ y2 c}
  j. p# A. z: @1 N" S# k+ }; n: b4 ]  s9 V& L2 g0 Y& Y% j. A0 H
+ h7 w. X) F1 O1 Y
在这三个执行域中,有很多类型为 PAD 的行,并且这些行没有节名字也没有所属的模块。这些其实是一些链接器自己添加的对齐。除了对齐没有其他作用。关于对齐本文之前的章节有介绍。除了 PAD 之外,剩下的就全是 Code 了。; x- p3 ?+ t6 G1 E0 p

0 j5 b+ \7 P. X1 M$ L+ u
  • Execution Region RW_IRAM1: 这个就是内存部分,存放我们的代码中用到的各种变量数据(常量数据在以上的 ER_IROM 中)。同样,该部分也有些对齐,除此之外全部是 Data、Zero、 HEAP(堆)、STACK(栈)。
    " L; ^) E/ x. G5 D6 B# t. c3 Y
5 O. j% z3 w% ~  [- `
Image component sizes3 c9 V0 U$ V  O- J

' A3 S$ a; g! h  }4 F* P该部分列出了组成镜像的各部分内容的大小等详细信息。" U9 ]$ v, ~- t
. X3 B% V: w( I, i
  • 各列的具体含义如下:
    # _% F6 B4 Z. D# t7 V
  • 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:显示调试数据占用的字节数,例如,调试输入节以及符号和字符串表。
  • 最后一列:对象文件的名字。下面会有区分。; d/ q& }7 Y2 g
  • 特殊行的含义如下:
    1 @3 O5 P, }( O
  • 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 数据和调试信息。
    6 W* m6 E6 _" p" }) m

* P$ {& g- v+ d- @) Z% w. w' G3 N& \

该用户从未签到

2#
发表于 2021-1-28 11:10 | 只看该作者
ARMCC(Keil)map 文件
  • TA的每日心情
    开心
    2022-12-26 15:46
  • 签到天数: 1 天

    [LV.1]初来乍到

    3#
    发表于 2021-1-28 11:10 | 只看该作者
    很详细,谢谢分享
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-11-24 16:54 , Processed in 0.187500 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表