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

ARM之ARMCC(Keil)map 文件

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

1 [$ _- B3 ]6 ?% x+ c+ M" @, cARMCC(Keil)map 文件' O5 `( V0 f  J
  根据选择的参数不同,map 文件中的内容肯定是有变化的!下面以 Keil 中全选以上所说的参数后生成的 map 文件为例来进行说明。map 文件中,有如下图所示的五个大部分:
+ P5 Q6 ^, @: X5 r4 e  i
( K1 w# {4 x1 W: ~' Z1 L' n
# e& M2 `; ?- a其中,每一部分都是对应上面的配置中的一个或者多个选项,也就是对应链接器armlink的一个或者多个参数! G& p) l2 E9 _2 Q2 e' o- n+ l5 }
; |+ v: G9 L$ `

; D4 N% n5 m* _4 Q  v8 fSection Cross References
. X  \8 ~7 h# @4 |
7 n- [3 o8 C" Q% f  该部分显示了节区之间的交叉引用,指的是各个源文件生成的模块之间相互引用的关系。交叉引用中可以分为三大部分。2 W) I6 V1 j9 A6 J5 I! d6 V
$ U4 ?$ P  g% ~( T$ Y* v3 f* e1 Y
用户模块之间交叉引用
! l' ?5 n  n" W' _- e
2 I- i. z% r. `" D& h' d  这部分主要就是用户自己实现的代码之间的引用关系。例如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 生成的模块。4 ^4 {4 D& P/ ]; E( J
! Y9 Y7 h% T( R) g; E9 U1 l
用户模块与 C 库交叉引用, X# S' g4 j0 D: b

/ S2 U  s3 z6 [, a: B# R. a* d  这部分主要就是用户自己实现的代码中调用 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 库中。
/ {! h/ c& R0 \* b1 l) D" ~5 {" a( p$ Z; f
; `4 {: @4 {- S7 V6 y( M  L
  在 ARM 编译套件中,所有的 C 库由工具armar来管理,位于 ARM 编译器目录 lib 下。使用 armar 即可从指定的库文件中解压出 __main.o 等模块。至于如何操作,参见博文ARM 之九 Cortex-M/R 内核启动过程 / 程序启动流程(基于ARMCC、Keil)。/ E, W8 N) Y$ {2 t
4 b, Z) k' @+ A

9 P! ~4 y- i7 q5 P1 wC 库之间交叉引用# ?; \5 U: K% H) P9 p& s" q5 ?

" l8 P3 \. ?1 W9 A  C 库函数之间也有互相的引用关系。用户使用的 C 库函数之间的引用关系也会显示在该部分。例如 dflt_clz.o(x$fpl$dflt) refers (Special) to usenofp.o(x$fpl$usenofp) for __I$use$fp,其中所有的函数都是 C 库中的。同样可以使用armar解压库文件来导出符号表查看各接口。
# H  i9 N0 [* w: [1 j* D& D; X% x) F% V1 F
5 Q. g# X- F6 e" L
Removing Unused input sections from the image, f% y0 m/ w) s4 B- r2 i* J
# M& ^& p& n8 w! H& z: v: o  k
  这部分列出了链接器移除的我们源码中实际未使用的数据和函数。其中包含移除数据的大小。例如Removing flash.o(.rrx_text), (6 bytes). 表示移除flash.o中的 6 字节的数据;Removing virtualuart.o(i.VirtualUartBufClear), (92 bytes). 表示移除 virtualuart.o 中的函数 VirtualUartBufClear,共 92 字节。
- t* [3 P  @$ v" `
) W; O1 o+ R' T4 A3 ~9 M% J! C8 g* z
  需要注意的是,被移除的函数在调试时将无法进行调试。如果不注意,在调试时很容易造成困扰。如下图所示:& ]" S) o- c3 P5 C% P' @; q2 s2 [; x, Q9 i

* A. D- O" j" q& d3 Z& J! }2 o. Z; z3 s  A7 Z% ^
8 r, U3 z1 U, A9 D1 k
+ B) n* u7 ^" d' Z: E+ n. S6 \
* z6 ^5 a3 V& I. A
Image Symbol Table* f4 I: y2 ?" u

4 m$ ~  J  ?" r- W, l& f0 |  ^符号映射表。就是每个符号(这里的符号可以指模块、变量、函数)实际的地址等信息。
$ E- i# C* o9 U, U0 m
/ Q3 N3 ?' h- r! \/ U  d$ H& [2 ^6 K, x: I. O* K. b
Local Symbols
) |4 q; u0 S' U6 {, C% ^
* n( n, u/ j0 G# J4 _. Q不知道 ARMCC 是怎么分的 Local 和 Global。
8 F$ d# u+ v( u/ I9 o* c/ U7 M; _4 q( ?2 [/ {9 z* _

$ L$ d4 A2 @; b' R8 MGlobal Symbols. A' a9 @" m8 b2 q$ _9 n' P

. X2 E0 Y3 D+ u! T( R' S不知道 ARMCC 是怎么分的 Local 和 Global。+ I0 Z9 P* T! q
* {* J# O' X5 |  F. c
! a0 {2 ?  ?) @/ x$ c1 p
Memory Map of the image
7 D" w+ d. g2 A4 N  R' c/ d; @" [4 y/ j% O/ h+ F! g- O
  这部分给出了镜像文件的布局。这部分与分散加载文件(Scatter File) 有密切的关系。如果使用 Keil,在 Keil 的配置界面中有如下配置:' i  \; c, e" a( l$ Q5 N8 X$ q0 ?$ R
7 c7 e( x% Y; \( s! C

+ F, v2 ~! F1 F- }/ n
; J; X& G3 Z! z
% ^4 \* u4 ?6 Y7 k. ?- t这里的设置就是对应的 map 文件中的内容。如果我们在链接器的配置页面不选择 Use Memory Layout from Taget Dialog,则需要如上图自己指定一个分散加载文件。其实,如果选择 Use Memory Layout from Taget Dialog,Keil 会根据我们左边的配置自行生成一个分散加载文件来给链接器使用(这个文件就在我们的编译输出指定的目录中)。上图的示例就是没有使用Keil默认,而是通过自己指定的分散加载文件生成镜像文件。6 |# D5 U+ n3 H6 [8 w# w% m3 j6 r* @

0 |+ S3 V, A: m- r5 b
0 [1 V6 l6 h3 d9 H  以上的 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 根据配置界面的配置,会成一个分散加载文件)。
0 d6 `7 i/ F& D7 q1 {+ n9 k8 C3 g" b1 ]  e1 Y9 j
接下来看看 map 文件中的内容,如下图:. B* K$ t! s; X4 ?" J$ b& R
2 r4 u( K, A8 N% Z9 w* K
: L# T$ z7 D: Q& ?
! |* E; f% W* v
  • 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 库代码。& a0 n4 X  \& N% N9 B8 g
$ B! f  |! o4 a2 }1 T) c8 @8 b
  我们先来介绍一下每个字段的含义。首先我们要明白,每一行就是一个节。. o* j+ M9 x( R' A
' E5 [% c4 G7 T8 y3 H; z" S
[color=rgba(0, 0, 0, 0.75)]Base AddrSizeTypeAttrIdxE Section NameObject
; S: h- M7 Q% h: g3 |8 X节的基地址节的大小类型属性索引节的名字对象(节所属的文件模块)
9 L: a  W2 n# Z( |5 f& y/ `
  为什么有 3 个?因为我本身使用了自己写的分散加载文件。手动指定了三个执行域。我的分散加载文件如下:
; s* J* y! t: C$ m& i0 f. ]4 g. Z* M* m/ A) k" u5 L2 V
; *************************************************************/ c' \2 P  G; D6 I! t
; *** Scatter-Loading Description File generated by ZCShou ***
) s; O5 G8 a2 Y( F& [8 C- v; *************************************************************7 w$ `$ y# o" E% n, X1 Q/ _5 B( ^

2 \9 O- e/ k$ R6 v- d' V
- J: p+ D8 G% j$ e- gLR_IROM1 0x08010000 0x00030000  {    ; load region size_region4 r  `! E6 n' s9 d" r* t2 j- Y9 |
  ER_IROM1 0x08010000 0x00030000  {  ; load address = execution address
8 t0 o7 T* o- [2 F   *.o (RESET, +First)                ; 中断向量表) u1 X: {* ~$ [) W5 }! U! L
  }
  k' Z( |- n3 ^7 K' s6 f/ S) {6 `9 V- I' u, d5 ]
  ER_IROM2 + 0 {                    ; 应用程序信息
( o- |+ M2 S6 v: ?7 H   *.o (SECTION_APP_INFO, +First)7 Z% r! I0 u- t% ^0 G4 ~
  }" g. W* k) [. k& u; [; l

) }. Z9 h8 N! u1 D* \  ER_IROM3 + 0 {                    ; 初始化相关代码+其他代码
/ e% R* y2 r! A   *(InRoot\$ \$Sections)    ; 初始化相关
# E! b6 K5 [! L! Q0 o   .ANY (+RO)            ; 其他所有代码% z% o% V( _) [1 v- z' c, h7 S
  }
! V7 ?6 h1 e6 }! [. [$ s- A( T2 D4 e% R: B; O
  RW_IRAM1 0x20000000 0x00020000  {  ; 内存
9 K1 c4 P3 N5 W' F  C/ [8 g" x  S9 ~1 B   .ANY (+RW +ZI)/ Z- b. Z4 d/ G- w  V) B: w
  }
8 I- \+ M! s" C4 o$ A  w6 d}. `: a# M9 z: I$ d2 [) T

4 ~/ ?8 n/ w; ?! b; u' F) s$ p, T* f/ S6 W# b& G* Q
在这三个执行域中,有很多类型为 PAD 的行,并且这些行没有节名字也没有所属的模块。这些其实是一些链接器自己添加的对齐。除了对齐没有其他作用。关于对齐本文之前的章节有介绍。除了 PAD 之外,剩下的就全是 Code 了。
  F( ], x9 d# D% t3 `+ I- h# s$ g
2 T- V) L. p* \- S( D1 Z. F
  • Execution Region RW_IRAM1: 这个就是内存部分,存放我们的代码中用到的各种变量数据(常量数据在以上的 ER_IROM 中)。同样,该部分也有些对齐,除此之外全部是 Data、Zero、 HEAP(堆)、STACK(栈)。
    8 m( c0 `9 V, U7 ?

3 Z  v. h# A8 @& R! NImage component sizes
+ R) X/ w! t9 O. T+ Z: B
+ S4 ^; ~* o( o/ S) j该部分列出了组成镜像的各部分内容的大小等详细信息。
9 H7 K4 H! a; r9 P# S' k
! G0 R5 g; g  T7 z5 s
  • 各列的具体含义如下:
    4 I# r! V! f/ e' F
  • 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:显示调试数据占用的字节数,例如,调试输入节以及符号和字符串表。
  • 最后一列:对象文件的名字。下面会有区分。
    7 x* [( }( T- f- i5 o2 _8 Y
  • 特殊行的含义如下:
    0 B9 P  I: q( m4 @# b3 I
  • 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 数据和调试信息。
    ) i) D  n8 {* [" `
" `+ g  z# f  G8 C$ F- e$ }/ V: W) s

- g  `/ ?& r' V. a+ O& j

该用户从未签到

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-6-25 00:32 , Processed in 0.093750 second(s), 26 queries , Gzip On.

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

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

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