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

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

[复制链接]
STMCU小助手 发布时间:2022-8-25 22:24
一、什么是散列文件
" `' z" `+ T' s" R3 _2 b) |3 _我们可以看到,在编译过程中有多个.o文件,而最后生成的只是一个文件,那么这些文件要怎么以什么方式生成一个文件呢?说的专业一点,这个过程就是链接,而在Keil-MDK下就是使用散列文件来指导链接的。! ~0 T' k  S. |# R2 s' H5 c$ ^, M' S
如图所示,将【Use Memory Layout from Target Dialog】勾选上
6 y9 _3 X+ b5 J' o9 ~% s 20210122222156842.png
$ A2 ~4 y% _8 C! [) n( r2 F0 M$ ^9 T- S  c$ M
然后重新编译,我们就可以在【Objects】目录下得到一个.sct文件如下所示
: u* L2 b0 n, c; ~2 [- H9 p4 D6 c
20210122222813727.png
; E* B4 e" H2 z/ M0 t: V
+ g" i7 D1 ]( r9 {( ~( Q二、散列文件的格式( s3 v: Y% P8 `, d/ Z
如下所示,一个散列文件由一个或多个Load region组成,一个Load region中含有一个或多个Execution region,一个Execution region中又含有一个或多个Input section。8 R8 _$ u8 I* j" d: |3 z  A: c
首先,LR_IROM1是Load region的区域名,紧接着0x08000000是其加载地址,然后0x00080000是其区域最大容量;8 }+ C- y) B0 N2 |5 i% Q
然后,ER_IROM1是Execution region的区域名,紧接着0x08000000是其可执行地址,也可以叫链接地址,然后0x00080000也是其区域最大容量;1 L3 Q+ ]/ e/ `8 m, A5 h

# E- M) a/ B; K5 b3 N 20210122223601774.png
, ?2 ]0 C+ |" x) t
2 |: b5 i5 ~4 g8 o# Z6 Z# _$ @  ?* u接下来就是各种文件的链接方式了,解释如下7 o; g% s  B8 ~* [5 Z* ^2 y, n% G
0 z3 j& L( t( l! v' ^. ~# l
  1. LR_IROM1 0x08000000 0x00080000  {    ; load region size_region9 T3 ^9 F. r5 A" R' m& Z1 L
  2.   ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address# n( {& I% X8 ?2 `$ Y
  3.    *.o (RESET, +First)        ;所有的.o文件里的RESET段抽取出来放在最开始的位置
    8 b$ G: n: Q! D6 t. U
  4.    *(InRoot$Sections)        ;所有的文件包括库,keil添加的可执行文件,看不到源码1 L7 |3 L3 q/ p! P$ R$ P( d
  5.    .ANY (+RO)                        ;等同于*,优先级比*低,这里表示所有的只读数据段
    $ T9 J5 E4 d* V7 A: m9 ^8 Y0 x; p
  6.    .ANY (+XO)                        ;这里表示所有的只可执行段" ?! c+ t3 p" s6 ^% U4 e8 n/ P
  7.   }
    2 G: _0 F- A8 H6 p- x/ L
  8.   RW_IRAM1 0x20000000 0x00010000  {  ; RW data5 o4 r8 g2 ^& }1 E9 @) \
  9.    .ANY (+RW +ZI)                ;所有的可读可写数据段" f, B! z3 n8 Q, M0 ~1 c
  10.   }
    3 u8 `9 k$ S0 e+ h  M
  11. }
复制代码

$ u* Z# C6 ~. Q- i* W三、分析散列文件
: G8 q/ r* s4 f  f3 j7 X) D  \* ?打开uart.dis文件,可以看到有个__main,这就是keil添加的可执行代码,因为我们使用了main函数,所以这段代码被添加进去了,8 ?- |  ]) U) ]& o7 R- ^6 n
0 x' H  j. n* H; k: r; e1 K
20210122230653690.png
4 c1 t" C3 P4 s5 H4 [/ y. V: ^' G
我们将我们代码中的main改为mymain,可以看到,这段代码没有了
2 i0 j# W' i0 }) A4 m& t- n8 k7 Z7 ^# R) v
20210122230903230.png
# C2 W/ L$ c8 D' i
8 G" G! Y1 u3 q我们在main.c中添加如下所示变量定义,: l3 N: W0 N6 ^; \  b

: K+ S) J4 v0 M1 t8 Z2 D( }1 D3 c5 V 20210122232752834.png
' t0 N3 X8 `  z# N$ O$ a* }0 E6 M- b7 w3 r! I
然后编译,打开uart.dis文件,可以看到,myconst变量被链接到0x08…开头的地址,即ER_IROM1 区域,而my、mydate和myzero即被链接到0x20…开头的地址,即RW_IRAM1 区域;与之相对应的,ER_IROM1 区域为该STM32的Flash地址,RW_IRAM1 区域为该STM32的RAM地址。
- a8 m& h+ e/ b7 q5 ?% E
9 a- J9 A( K% P  {: p. w9 s 20210122232630534.png / H4 h) T# [1 }9 ~& d% X0 ^. r

/ B, d6 K7 R1 q6 T9 n然后我们再看一下,uart.dis文件中,ER_IROM1 区域的最后一个位置0x080001ac存放的即我们定义的只读变量myconst
: z, t. e1 l( d- I  n/ L! k
' {- d, T( s" `& u; k. C 2021012223364651.png - s" f' L- s  E

; e: p) z* m! z3 N但我们使用STM32Cubeprg打开uart.hex文件可以看到,在0x080001ac后还有三个位置,而这三个位置存放的刚好就是我们定义的三个my、mydate和myzero变量。
; r" b6 y( C' ]% b: W
4 G/ t6 K  q) }, M+ ^ 20210122233907273.png & t1 [, {9 J+ L" O& A7 y

/ P7 W9 m/ d" X实际上,对于在STM32F103这类资源紧缺的单片机芯片中:' L% |0 e: ~0 a3 G& S( h
代码段保存在Flash上,直接在Flash上运行(当然也可以重定位到内存里)3 c$ f8 O' x& A
数据段暂时先保存在Flash上,然后在使用前被复制到内存里(只读数据段不复制)* `) p( c3 H# J* o5 m
3 ~( t# B: e1 ^0 i5 t" P6 z# }) P
四、验证数据段的存放
9 j6 c& a; S7 W; A4 G4 }修改main.c如下所示
& h4 R! t- `, \
0 ~- M* f7 Z  n5 s: D
  1. #include "uart.h"
    2 N. W+ P, S& j& _
  2. #include "led.h"
    ! J" U6 N7 t! T+ E1 o

  3. 8 X, P) D  U9 y
  4. int mydata = 0x12315;
    ' W: e% l1 N+ ?
  5. const int myconst = 0x22315;5 F4 q/ w7 m. m" ^
  6. int myzero = 0x0;' Z+ `8 Q4 \; E8 L5 |' o' R  Z8 M
  7. int my;. }8 D# p$ `. p

  8. 8 V8 q$ |$ C1 Z+ d+ I9 R9 ^' O
  9. int mymain(void)
    , ~+ \: |7 J) |. v3 z3 u
  10. {
    3 A$ P. H7 y5 _' F  C
  11.     uart_init();0 y' p' F9 {9 N/ z+ {
  12.     led_init();9 ]  B- {/ S9 l% e, P8 Q4 A
  13.     putstring("stm32f103zet6\r\n");* }6 N9 G* p$ P& Q5 _2 A
  14.         putstring("mydata\t:");/ X& Q3 u' h: M1 w( N5 m1 F
  15.     puthex((unsigned int)mydata);( H4 I* b1 `4 [/ p
  16.     putstring("\r\nmyconst\t:");
    & j% ^- f/ M0 T! Q1 J1 K% H
  17.     puthex((unsigned int)myconst);2 q, [5 a( m2 i# w
  18.         putstring("\r\nmyzero\t:");
    $ [4 b7 d7 c  N2 r* W* h, |
  19.     puthex((unsigned int)myzero);
    ( I( O: {6 U$ P. b
  20.     putstring("\r\nmy\t:");
    ; D" \1 }. }; T5 @% u
  21.     puthex((unsigned int)my);
    1 _6 C2 Y+ H& J! v  r% m+ s& h2 [
  22.     putstring("\r\n");
    . u6 E* i5 C1 v! }7 `2 `

  23. ' [5 r/ a3 U" m
  24.     while(1)9 W9 r4 f5 X& E  h* \
  25.     {. [% Z# j1 G2 M% y6 H# E( _
  26.                 putstring("led on\r\n");
    6 [6 k/ S! ^5 z- G3 I
  27.         led_on();# Y5 F( M* r/ }1 N8 S
  28.         delay(1000000);; ^! K  H1 y2 F6 X4 |! \. @
  29.                 ' }4 h. [% s6 @' ?9 |1 t
  30.                 putstring("led off\r\n");
    ( r5 ^: B! e& q3 F& q) q: s" r
  31.         led_off();
    & [- x4 r  h1 N# C9 B( O# k- j5 U" {
  32.         delay(1000000);3 O3 j" P5 W$ S# T2 b& R3 Q
  33.     }
    9 s/ N. B5 h! U- _; ?: g: L2 P; {
  34. }
复制代码

! @: A; j! K2 ?% a' g, ^7 J编译烧录运行,可以看到,只有myconst变量值是正确的,其他三个变量值都是错误的,这是因为我们并没有将那三个变量的值从Flash上复制到内存里,所以读取出来的只是上电后该RAM地址的一个随机值。+ M( S9 E: I/ W) @8 o) i! E) j
3 w4 V$ E7 j  y6 O
20210122234846541.png
" `7 y" L8 ^; h
- X9 e' x9 w$ E& K% P8 k. W7 x然后再添加一下地址的打印' s  @, C1 b+ S/ j" u1 Z
. r& T  X7 ]$ U6 h; w: Z7 G, y( o
20210124120309831.png
' D6 y' |. b, O1 u# R- l+ X
. r/ a+ L5 ^8 d2 o, Q! R! Z" F# [编译烧录运行,可以看到,确实只有myconst变量值是保存在Flash的,其他三个变量值都是在内存里的& [% D: Y: [: d* H& C
' p# z) |$ J( D8 [
20210124120255715.png
( S$ b# [  H# S/ u8 @- `: V/ G
7 s' @4 V3 p5 u2 T* {# g1 ]另外我们也可以顺便看一下栈地址,在mymain函数里定义一个变量并打印其地址9 e  k4 r$ l6 ^7 x  r6 \4 s
0 H' x$ `* Y8 o) p3 u) G8 a2 O1 w9 C4 B
  1.         int val = 3;' {3 m7 {: J# C+ H0 W# z, K
  2.         : r8 v" [- q& m. ^* G- T2 |
  3.         putstring("val\t:");3 E6 F+ B0 B4 k2 z0 m" ?
  4.     puthex((unsigned int)val);
    : _9 I- F7 |# z
  5.         puthex((unsigned int)&val);# d6 r/ M6 P; h& B6 D* K% ]
  6.         putstring("\r\n");
复制代码

, Y9 a' R! ^! U3 T. Z编译烧录运行,可以看到,其地址确实在我们设置的栈中% N9 r# p. _( A$ l4 R, P$ R

; I  w& f# q( T: _ 2021012412092622.png % {6 y% e7 i1 I# f: e* C4 Z

6 w1 P, c7 v: n0 p) x8 s————————————————1 S% ]' G  w7 v) q$ w& F! e, i
转载:Willliam_william$ ?: V% [2 s: G4 h- N. v- j

2 b; _0 F! {+ A$ D5 u" \% M9 U2 S9 k  \$ l4 e
赞 收藏 评论0 发布时间:2022-8-25 22:24

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版