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

ARM之ARMCC(Keil)map 文件

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
. {0 Q8 }3 V5 N: _3 Q5 F
ARMCC(Keil)map 文件6 h9 Q5 A, C( |( b4 D
  根据选择的参数不同,map 文件中的内容肯定是有变化的!下面以 Keil 中全选以上所说的参数后生成的 map 文件为例来进行说明。map 文件中,有如下图所示的五个大部分:
, X. Y4 _0 F) Q" @7 k+ W ! v7 a: `1 S( k; w/ H! L2 o9 J
9 C( `, l" d! q% o5 _' r
其中,每一部分都是对应上面的配置中的一个或者多个选项,也就是对应链接器armlink的一个或者多个参数" U( ^% V' z# @. k( `  i
% ?7 ?  g" U' h4 b$ X+ j6 M5 Y

6 ^- n$ g( s9 n' O3 ESection Cross References8 \- D$ o2 B& H! T4 [
- o  q- g, ~# f* P7 ^( |
  该部分显示了节区之间的交叉引用,指的是各个源文件生成的模块之间相互引用的关系。交叉引用中可以分为三大部分。3 B( d. w$ R' h3 q3 @
) S2 J: f7 Y: \' F
用户模块之间交叉引用
0 h. k: Z, A1 o- P. ^8 u- W# s6 }, o. `
  这部分主要就是用户自己实现的代码之间的引用关系。例如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 生成的模块。* a- U* E$ U- Q0 m
3 b0 b4 `. d+ m' ?- C- O
用户模块与 C 库交叉引用, i8 R3 E0 m. O- q+ y" Y  S
# B' ]: A: p2 O! ~  O& R$ Y: J
  这部分主要就是用户自己实现的代码中调用 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 库中。
5 b9 O" [0 Z' k0 {! Q# K* L$ |$ U, F4 ?! o9 C2 k* g6 L9 C9 Q

3 o  |* u$ T% F+ i) z  在 ARM 编译套件中,所有的 C 库由工具armar来管理,位于 ARM 编译器目录 lib 下。使用 armar 即可从指定的库文件中解压出 __main.o 等模块。至于如何操作,参见博文ARM 之九 Cortex-M/R 内核启动过程 / 程序启动流程(基于ARMCC、Keil)。
- k$ S- }4 \4 P7 s. ?& E1 M+ p  u+ y! G* @* Z3 W( K
& A  @, x1 l0 J9 K
C 库之间交叉引用
2 G8 \) R1 {1 r
7 j: w, A7 `$ y3 m9 U2 T  C 库函数之间也有互相的引用关系。用户使用的 C 库函数之间的引用关系也会显示在该部分。例如 dflt_clz.o(x$fpl$dflt) refers (Special) to usenofp.o(x$fpl$usenofp) for __I$use$fp,其中所有的函数都是 C 库中的。同样可以使用armar解压库文件来导出符号表查看各接口。
' B" k  t8 |2 R$ n; J  s9 @6 {3 e8 ]# N% G' P+ e2 l0 t3 W

! p8 J2 E4 ^) ~4 |% B- bRemoving Unused input sections from the image' K: f% @- m' M
# J/ m- e2 {- D) J
  这部分列出了链接器移除的我们源码中实际未使用的数据和函数。其中包含移除数据的大小。例如Removing flash.o(.rrx_text), (6 bytes). 表示移除flash.o中的 6 字节的数据;Removing virtualuart.o(i.VirtualUartBufClear), (92 bytes). 表示移除 virtualuart.o 中的函数 VirtualUartBufClear,共 92 字节。  @0 Y5 ~) Q: `( ]. q' a
! f# x9 y5 B1 u6 X" x# Z4 Y7 ?3 k# K; B
: m/ y8 a6 K: c
  需要注意的是,被移除的函数在调试时将无法进行调试。如果不注意,在调试时很容易造成困扰。如下图所示:
2 ^- [3 D1 X( k9 N: n4 o0 X: I; ?+ T

% B- E4 m$ b3 V' D+ ~& a- |( k4 }
" C, I8 S: B. p5 x9 G7 V1 h+ G+ w7 @) j0 E4 o6 J/ M
, L0 e7 D( j# S' l; [
Image Symbol Table+ e0 s/ \2 i5 E

# W3 J2 \1 i# t2 U4 ~符号映射表。就是每个符号(这里的符号可以指模块、变量、函数)实际的地址等信息。" J; M2 h! M7 n5 b' {
$ v' x" N8 W2 s* {' |, Y9 c1 w
. |( l3 y5 s; U3 d7 ^7 K
Local Symbols+ N4 n, W8 F7 I: F( F! N4 c

0 d: i3 f4 J, Q& y3 D8 _不知道 ARMCC 是怎么分的 Local 和 Global。
2 Z* O- f2 o' Q2 ^1 m
4 t$ G) n) `4 O+ R) U$ D. K) u- r/ q8 {  N9 z' ?5 \8 m
Global Symbols4 E+ n" D" D9 n% V4 e' R
1 Y- k. L$ P" O) o+ y
不知道 ARMCC 是怎么分的 Local 和 Global。
4 @5 l/ |8 x  A+ @% E* N7 H9 O3 h- g; n. l7 A

  G9 e8 i% n' I6 Y5 C) CMemory Map of the image
+ Y) t3 I, T0 S0 D
% S! `$ C; {8 G8 s$ v, U& ^( ~  这部分给出了镜像文件的布局。这部分与分散加载文件(Scatter File) 有密切的关系。如果使用 Keil,在 Keil 的配置界面中有如下配置:
0 k& L' k- D1 l, a- p
$ V& G# X  Q- P0 A  _. `, W% ~* I& u# [

, N$ v! h' F4 i
9 p" ?0 X2 x; C& M这里的设置就是对应的 map 文件中的内容。如果我们在链接器的配置页面不选择 Use Memory Layout from Taget Dialog,则需要如上图自己指定一个分散加载文件。其实,如果选择 Use Memory Layout from Taget Dialog,Keil 会根据我们左边的配置自行生成一个分散加载文件来给链接器使用(这个文件就在我们的编译输出指定的目录中)。上图的示例就是没有使用Keil默认,而是通过自己指定的分散加载文件生成镜像文件。1 k  |2 X1 S' j$ U( g7 _( m
# x) [( b, Q' [; `  y% O- |# B2 g* i$ L

0 R; _: s$ ?/ w5 v7 v4 J9 L* ?  以上的 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 根据配置界面的配置,会成一个分散加载文件)。
, d) b3 T5 Y0 v9 N% T: c# I: x5 s! v# `2 b0 O) |
接下来看看 map 文件中的内容,如下图:
3 U7 i0 _# H4 h6 l9 P+ V, w% f
) }$ M. E( r2 L6 R  }6 r% n7 C # ?; {) q# i2 |8 l% f- G, d% q
' u1 p+ T. U+ o+ \' z8 m
  • 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 库代码。
    5 _: x5 ?$ B5 ]2 d4 Q

5 [* v0 a- {) D5 K4 \( ~7 G5 A5 v) {  我们先来介绍一下每个字段的含义。首先我们要明白,每一行就是一个节。4 M. V9 p! G  `# L" Z, T4 ]- [

& \# f2 S8 F/ Z4 c- _0 X: S1 z+ a* L[color=rgba(0, 0, 0, 0.75)]Base AddrSizeTypeAttrIdxE Section NameObject
: w4 `2 B3 |4 z0 f+ B+ D, R节的基地址节的大小类型属性索引节的名字对象(节所属的文件模块)

" H- j5 i# u* s: Q  为什么有 3 个?因为我本身使用了自己写的分散加载文件。手动指定了三个执行域。我的分散加载文件如下:6 _% s/ F. f6 O  ^5 w, N& Y
" @% p2 Q3 _) R9 I. k1 W$ Z
; *************************************************************2 `8 c. D' O" O
; *** Scatter-Loading Description File generated by ZCShou ***2 a9 J( {% }$ i! B
; *************************************************************
$ b7 Z, D5 h# F0 l- M
. k/ u5 s; ^9 L6 m0 k" z( Q9 g  e% z* H5 }9 f9 w4 l
LR_IROM1 0x08010000 0x00030000  {    ; load region size_region, X0 @" x* d% b* I. S, d8 Q; n
  ER_IROM1 0x08010000 0x00030000  {  ; load address = execution address
7 @% R+ E! j- y0 w7 h   *.o (RESET, +First)                ; 中断向量表- r# a! c- B) p
  }
  x7 z6 a( d( E6 s4 n" W' l5 K: D" ~7 M* Y
  ER_IROM2 + 0 {                    ; 应用程序信息
) a* V( T9 y  K' ~   *.o (SECTION_APP_INFO, +First)2 X: T8 I7 N  K0 z8 Z
  }
8 i* W1 v" X% Y: i! q) e4 ^7 P# d5 G! A: s3 o4 n) i  t
  ER_IROM3 + 0 {                    ; 初始化相关代码+其他代码
- s0 I7 U2 \1 o6 B7 {4 w/ m   *(InRoot\$ \$Sections)    ; 初始化相关& j8 s$ ], n4 k0 {7 q8 U
   .ANY (+RO)            ; 其他所有代码2 d" d' m7 X1 |+ Y# o& \
  }
5 R& \, I0 t, L7 g3 w. A4 g& Z6 e, V1 |3 ~, z
  RW_IRAM1 0x20000000 0x00020000  {  ; 内存( t. z% I, V# Y! w7 g3 D* Q
   .ANY (+RW +ZI)
2 X1 b2 O8 y$ ?) A  }
! P: P7 X+ V5 a9 o2 G}
: j+ }# C9 `/ Q1 H; @7 y/ V" L1 _- V9 T' D( z# |

- n# h( H7 H# \) n8 C6 x: a在这三个执行域中,有很多类型为 PAD 的行,并且这些行没有节名字也没有所属的模块。这些其实是一些链接器自己添加的对齐。除了对齐没有其他作用。关于对齐本文之前的章节有介绍。除了 PAD 之外,剩下的就全是 Code 了。, e& ~/ W- X1 ]! U: q
: T% X% ]9 b2 ^
  • Execution Region RW_IRAM1: 这个就是内存部分,存放我们的代码中用到的各种变量数据(常量数据在以上的 ER_IROM 中)。同样,该部分也有些对齐,除此之外全部是 Data、Zero、 HEAP(堆)、STACK(栈)。( H; ^" `2 i: a2 n$ o4 Y% c
- H' m' D9 g, W& n( z! u, o
Image component sizes
! m% n$ ?; ]4 H9 \* y( H
) b# z( d+ s. j6 y1 A% k1 b该部分列出了组成镜像的各部分内容的大小等详细信息。
# y9 ?; {- C. P4 b
  q- M$ e6 {4 D$ v) Z: |5 Z
  • 各列的具体含义如下:  `, q' m6 e' w# T5 R- n
  • 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:显示调试数据占用的字节数,例如,调试输入节以及符号和字符串表。
  • 最后一列:对象文件的名字。下面会有区分。
    / @- G, b; g+ t( U+ ?0 |& X
  • 特殊行的含义如下:( g+ p9 H1 X9 D) L
  • 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 数据和调试信息。
    + ?. Q. U: Z7 ^$ [- _
6 D+ Q: F% J( Q5 {; f; C
: X7 U5 ~' h) Z6 K9 m

该用户从未签到

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 17:11 , Processed in 0.203125 second(s), 27 queries , Gzip On.

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

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

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