你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F1系列之Keil-MDK下散列文件的分析

[复制链接]
STMCU小助手 发布时间:2022-8-25 22:24
一、什么是散列文件
# u: T, _6 Z9 t# C0 H8 z我们可以看到,在编译过程中有多个.o文件,而最后生成的只是一个文件,那么这些文件要怎么以什么方式生成一个文件呢?说的专业一点,这个过程就是链接,而在Keil-MDK下就是使用散列文件来指导链接的。4 ]/ ^: F% V% m# K  i
如图所示,将【Use Memory Layout from Target Dialog】勾选上
2 Y& y3 U: Y: H 20210122222156842.png
! _+ N) J! `5 |! j4 j+ S
2 m( \3 C1 p, P' {9 p# T% M. u1 e然后重新编译,我们就可以在【Objects】目录下得到一个.sct文件如下所示! {+ \4 H6 d8 c$ H

) [" g0 N: `0 ^; Q! D 20210122222813727.png 7 k# u$ n0 M0 o- {# r
4 J' u4 n2 J. ]0 i
二、散列文件的格式
, F- ?- R' @( O如下所示,一个散列文件由一个或多个Load region组成,一个Load region中含有一个或多个Execution region,一个Execution region中又含有一个或多个Input section。
: {4 V% a) C4 }3 u9 z) J首先,LR_IROM1是Load region的区域名,紧接着0x08000000是其加载地址,然后0x00080000是其区域最大容量;
* h  {9 r' z5 ]* x然后,ER_IROM1是Execution region的区域名,紧接着0x08000000是其可执行地址,也可以叫链接地址,然后0x00080000也是其区域最大容量;% H& J( b- k4 Q' m: h8 v

( j9 r( e: W( ~4 [. v 20210122223601774.png 6 O* I' \6 g0 ]
$ ?7 C3 q8 t7 U) T, t$ ?. A
接下来就是各种文件的链接方式了,解释如下- n4 r& A/ T0 E' b, }( I" R# G9 l3 C

2 |# U( M6 v1 y  _4 `
  1. LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
    6 N1 h. }' V$ ^) m4 o, k) D
  2.   ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address9 {$ W7 d* R, |9 k; h; G
  3.    *.o (RESET, +First)        ;所有的.o文件里的RESET段抽取出来放在最开始的位置
    7 w! v$ [% i1 `
  4.    *(InRoot$Sections)        ;所有的文件包括库,keil添加的可执行文件,看不到源码0 Y2 v; s/ k8 ?, \2 x( a6 |7 l
  5.    .ANY (+RO)                        ;等同于*,优先级比*低,这里表示所有的只读数据段
    7 f6 Y% {, K7 k& c1 m8 w6 ]% g
  6.    .ANY (+XO)                        ;这里表示所有的只可执行段
    ' U0 r& e- y# v8 W  E& ~9 R, o
  7.   }0 X! R5 p3 Z3 `; P: i4 R
  8.   RW_IRAM1 0x20000000 0x00010000  {  ; RW data
      p% m( c  N' M/ \
  9.    .ANY (+RW +ZI)                ;所有的可读可写数据段
    ) l1 H: J; H. A7 H" X# f
  10.   }1 r/ A4 y0 P/ {! Z! M$ a
  11. }
复制代码
8 _- a( i) Z! h- F
三、分析散列文件$ G' a+ L+ F; W  |4 j0 O
打开uart.dis文件,可以看到有个__main,这就是keil添加的可执行代码,因为我们使用了main函数,所以这段代码被添加进去了,0 V6 [. m# i: E( Q% {+ ]. y

* l6 g$ [( E3 ]4 s, v 20210122230653690.png
! N5 K% {( I+ x$ v( n
% f- g8 M* d6 E# E- _' B; C( @我们将我们代码中的main改为mymain,可以看到,这段代码没有了% _4 b3 Z- q( ^

9 V  ~7 p- c6 p* p* l- b6 K 20210122230903230.png 6 b% ]3 E3 e" M$ A' \2 q+ B
4 C. X7 _) u+ B- _6 n
我们在main.c中添加如下所示变量定义,) p! N% P, J1 a* b9 h, w. i* |

' u) ]. Q2 r; z- S  {6 L# `7 y1 Q 20210122232752834.png
3 w: h, @' A; c' o, l! L6 E9 o* ~; k3 f, _2 w: D
然后编译,打开uart.dis文件,可以看到,myconst变量被链接到0x08…开头的地址,即ER_IROM1 区域,而my、mydate和myzero即被链接到0x20…开头的地址,即RW_IRAM1 区域;与之相对应的,ER_IROM1 区域为该STM32的Flash地址,RW_IRAM1 区域为该STM32的RAM地址。  V! P! L5 H+ W2 c, t

5 I( I  t5 G. w& V; f# ? 20210122232630534.png
5 m! D1 X- ~8 F. p* k# l; Z" j* B+ I. V# \
然后我们再看一下,uart.dis文件中,ER_IROM1 区域的最后一个位置0x080001ac存放的即我们定义的只读变量myconst
4 q# |" ~: l! h  |4 ^- J8 o' ~
" D; |/ ^* P9 {# `4 P- [ 2021012223364651.png
) L9 z2 E1 m; B( e. G2 U5 C. k: E$ t/ f8 N* q7 }
但我们使用STM32Cubeprg打开uart.hex文件可以看到,在0x080001ac后还有三个位置,而这三个位置存放的刚好就是我们定义的三个my、mydate和myzero变量。% q1 Z  |9 r9 {' |' `

8 ]/ m$ D9 w1 _' `% t 20210122233907273.png
4 j* E# h- @; g2 `8 X, B( C9 t9 P! G! K+ j6 k! G# P
实际上,对于在STM32F103这类资源紧缺的单片机芯片中:
5 b9 \3 L2 q4 {7 r1 d代码段保存在Flash上,直接在Flash上运行(当然也可以重定位到内存里)/ x! K& f6 P4 M$ ~, c! f7 u& d# J$ `
数据段暂时先保存在Flash上,然后在使用前被复制到内存里(只读数据段不复制)
; W* o; N9 q. }$ O8 u2 w
- B9 f( H  M& |! H1 Y3 ^四、验证数据段的存放6 C9 B7 X) L& K7 ?2 q
修改main.c如下所示
) V. D8 J% s  F* v6 F# A& `1 m+ P3 r9 L. V; Z9 z
  1. #include "uart.h"
    1 i! ~4 k9 j- ~$ X0 ]* i  b% `8 o) I3 T: ^
  2. #include "led.h"( h9 s$ ?8 ]. ?7 H5 R

  3. 4 }+ E6 g* g: c! M
  4. int mydata = 0x12315;1 M4 c! @& U3 A* C9 O
  5. const int myconst = 0x22315;- w/ P4 C( i9 D  U! Q' a
  6. int myzero = 0x0;
    9 u- z+ v+ A8 [; ]9 T
  7. int my;' u  n& J+ Q1 p1 n7 w2 }+ P
  8. ' K  _: J9 a+ D* d) b3 ~% S
  9. int mymain(void)) v( I2 M% t# B3 C, ~  f( H) F
  10. {6 ?/ }9 I% L2 Y2 Y% Y* X+ g
  11.     uart_init();
    : G$ {3 h3 S( T& v6 E. n- O
  12.     led_init();# B& x; G- d! U; P% X5 D
  13.     putstring("stm32f103zet6\r\n");, N! y. N9 y5 |; A
  14.         putstring("mydata\t:");
    3 |* W5 G2 C; K. b' F5 z- S8 j
  15.     puthex((unsigned int)mydata);) N" f" C3 w! J# ^: T2 N  E+ N# d1 d
  16.     putstring("\r\nmyconst\t:");
    % a8 ^6 h/ h; Q; j
  17.     puthex((unsigned int)myconst);
    + j5 i8 U+ Z. d% ~. L- ^# K
  18.         putstring("\r\nmyzero\t:");: ]$ l- c2 m4 L9 z, D+ O  X
  19.     puthex((unsigned int)myzero);
    , l/ O" D! l: k* H+ X
  20.     putstring("\r\nmy\t:");9 N1 B  Y+ E- w7 o- R% `
  21.     puthex((unsigned int)my);
    2 l$ f1 C, K) k  e2 |8 s
  22.     putstring("\r\n");
    1 o8 \0 h1 I9 M8 Z
  23. % M* M$ }7 r  O" T. n
  24.     while(1)
    # q, p4 R/ i. ~- Q
  25.     {2 m9 V  Q0 ]# B
  26.                 putstring("led on\r\n");
    8 B* h' G! R/ b  i' e3 o$ d
  27.         led_on();% t9 q1 n' l# M: @5 x0 a8 n
  28.         delay(1000000);  N# o+ M3 b) M3 n) i  ~
  29.                
    ! n7 D, ^6 h$ y, Y0 ~* h
  30.                 putstring("led off\r\n");0 L+ T* G! f" }. q) i0 J
  31.         led_off();2 i0 M' S- y+ j2 V% H
  32.         delay(1000000);
    " b* k2 f) Q0 Z) o! P9 V* C( m; u
  33.     }0 v& ?$ E: Z' O/ Z9 R: F9 h
  34. }
复制代码

/ p5 ]9 n  v( y- y# O编译烧录运行,可以看到,只有myconst变量值是正确的,其他三个变量值都是错误的,这是因为我们并没有将那三个变量的值从Flash上复制到内存里,所以读取出来的只是上电后该RAM地址的一个随机值。
# Q0 y8 p5 s) |) v/ b6 Q" Y7 }7 d+ D4 u6 E* j# ]
20210122234846541.png
. k4 P# N. x) h0 _' Q
1 P0 J6 q7 T1 W+ v; Z' m然后再添加一下地址的打印! F; c/ K$ W8 F5 [0 q) N2 V
  H8 J+ s$ |5 K! r/ S& @% F7 N4 O
20210124120309831.png
0 E5 ]6 g- j6 q% J
* ?% U& k1 b' z6 {" o. f1 W编译烧录运行,可以看到,确实只有myconst变量值是保存在Flash的,其他三个变量值都是在内存里的7 t- Z3 W) ~! I2 J7 ]0 k: I! }3 ?
( M) C2 k8 _+ F" P4 E2 U
20210124120255715.png ' q7 K; y- \/ I8 S& }& \

1 y- ~6 C2 L3 C+ P另外我们也可以顺便看一下栈地址,在mymain函数里定义一个变量并打印其地址
' s7 R: _. v  F
7 N! e3 g" l; t  H$ C
  1.         int val = 3;
    4 P8 d) [8 t8 H3 O
  2.         ; b  m. r% e5 y, f/ x+ r% l) O& d8 n
  3.         putstring("val\t:");
    2 E. {6 @. V( C3 z
  4.     puthex((unsigned int)val);
    ; h; }' ]) D6 N2 b
  5.         puthex((unsigned int)&val);7 u( M, X1 f5 F3 h# u
  6.         putstring("\r\n");
复制代码

8 D+ H$ v7 J: @0 |5 X8 n# H* U; E编译烧录运行,可以看到,其地址确实在我们设置的栈中+ P# e9 N( l* [

" P  {' D: I6 G; } 2021012412092622.png
# S2 ?# G/ l# I- L( e- R7 M& g4 V& R/ C* }! j
————————————————
, H! W! g' ?& ^5 G  R7 {转载:Willliam_william
! y% U  F* d) p' ]% [2 g: y: J( L) V' B' z7 ]% |4 d
, U) X$ c6 ~- U0 N6 S$ @: n5 @
收藏 评论0 发布时间:2022-8-25 22:24

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版