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

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

[复制链接]
STMCU小助手 发布时间:2022-8-25 22:24
一、什么是散列文件
我们可以看到,在编译过程中有多个.o文件,而最后生成的只是一个文件,那么这些文件要怎么以什么方式生成一个文件呢?说的专业一点,这个过程就是链接,而在Keil-MDK下就是使用散列文件来指导链接的。
如图所示,将【Use Memory Layout from Target Dialog】勾选上
20210122222156842.png

然后重新编译,我们就可以在【Objects】目录下得到一个.sct文件如下所示

20210122222813727.png

二、散列文件的格式
如下所示,一个散列文件由一个或多个Load region组成,一个Load region中含有一个或多个Execution region,一个Execution region中又含有一个或多个Input section。
首先,LR_IROM1是Load region的区域名,紧接着0x08000000是其加载地址,然后0x00080000是其区域最大容量;
然后,ER_IROM1是Execution region的区域名,紧接着0x08000000是其可执行地址,也可以叫链接地址,然后0x00080000也是其区域最大容量;

20210122223601774.png

接下来就是各种文件的链接方式了,解释如下

  1. LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  2.   ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
  3.    *.o (RESET, +First)        ;所有的.o文件里的RESET段抽取出来放在最开始的位置
  4.    *(InRoot$Sections)        ;所有的文件包括库,keil添加的可执行文件,看不到源码
  5.    .ANY (+RO)                        ;等同于*,优先级比*低,这里表示所有的只读数据段
  6.    .ANY (+XO)                        ;这里表示所有的只可执行段
  7.   }
  8.   RW_IRAM1 0x20000000 0x00010000  {  ; RW data
  9.    .ANY (+RW +ZI)                ;所有的可读可写数据段
  10.   }
  11. }
复制代码

三、分析散列文件
打开uart.dis文件,可以看到有个__main,这就是keil添加的可执行代码,因为我们使用了main函数,所以这段代码被添加进去了,

20210122230653690.png

我们将我们代码中的main改为mymain,可以看到,这段代码没有了

20210122230903230.png

我们在main.c中添加如下所示变量定义,

20210122232752834.png

然后编译,打开uart.dis文件,可以看到,myconst变量被链接到0x08…开头的地址,即ER_IROM1 区域,而my、mydate和myzero即被链接到0x20…开头的地址,即RW_IRAM1 区域;与之相对应的,ER_IROM1 区域为该STM32的Flash地址,RW_IRAM1 区域为该STM32的RAM地址。

20210122232630534.png

然后我们再看一下,uart.dis文件中,ER_IROM1 区域的最后一个位置0x080001ac存放的即我们定义的只读变量myconst

2021012223364651.png

但我们使用STM32Cubeprg打开uart.hex文件可以看到,在0x080001ac后还有三个位置,而这三个位置存放的刚好就是我们定义的三个my、mydate和myzero变量。

20210122233907273.png

实际上,对于在STM32F103这类资源紧缺的单片机芯片中:
代码段保存在Flash上,直接在Flash上运行(当然也可以重定位到内存里)
数据段暂时先保存在Flash上,然后在使用前被复制到内存里(只读数据段不复制)

四、验证数据段的存放
修改main.c如下所示

  1. #include "uart.h"
  2. #include "led.h"

  3. int mydata = 0x12315;
  4. const int myconst = 0x22315;
  5. int myzero = 0x0;
  6. int my;

  7. int mymain(void)
  8. {
  9.     uart_init();
  10.     led_init();
  11.     putstring("stm32f103zet6\r\n");
  12.         putstring("mydata\t:");
  13.     puthex((unsigned int)mydata);
  14.     putstring("\r\nmyconst\t:");
  15.     puthex((unsigned int)myconst);
  16.         putstring("\r\nmyzero\t:");
  17.     puthex((unsigned int)myzero);
  18.     putstring("\r\nmy\t:");
  19.     puthex((unsigned int)my);
  20.     putstring("\r\n");

  21.     while(1)
  22.     {
  23.                 putstring("led on\r\n");
  24.         led_on();
  25.         delay(1000000);
  26.                
  27.                 putstring("led off\r\n");
  28.         led_off();
  29.         delay(1000000);
  30.     }
  31. }
复制代码

编译烧录运行,可以看到,只有myconst变量值是正确的,其他三个变量值都是错误的,这是因为我们并没有将那三个变量的值从Flash上复制到内存里,所以读取出来的只是上电后该RAM地址的一个随机值。

20210122234846541.png

然后再添加一下地址的打印

20210124120309831.png

编译烧录运行,可以看到,确实只有myconst变量值是保存在Flash的,其他三个变量值都是在内存里的

20210124120255715.png

另外我们也可以顺便看一下栈地址,在mymain函数里定义一个变量并打印其地址

  1.         int val = 3;
  2.         
  3.         putstring("val\t:");
  4.     puthex((unsigned int)val);
  5.         puthex((unsigned int)&val);
  6.         putstring("\r\n");
复制代码

编译烧录运行,可以看到,其地址确实在我们设置的栈中

2021012412092622.png

————————————————
转载:Willliam_william


收藏 评论0 发布时间:2022-8-25 22:24

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版