STM32裸机开发(6) — Keil-MDK下散列文件的分析

STM32裸机开发(6) — Keil-MDK下散列文件的分析

一、什么是散列文件

我们可以看到,在编译过程中有多个.o文件,而最后生成的只是一个文件,那么这些文件要怎么以什么方式生成一个文件呢?说的专业一点,这个过程就是链接,而在Keil-MDK下就是使用散列文件来指导链接的。
如图所示,将【Use Memory Layout from Target Dialog】勾选上
在这里插入图片描述
然后重新编译,我们就可以在【Objects】目录下得到一个.sct文件如下所示
在这里插入图片描述

二、散列文件的格式

如下所示,一个散列文件由一个或多个Load region组成,一个Load region中含有一个或多个Execution region,一个Execution region中又含有一个或多个Input section
首先,LR_IROM1是Load region的区域名,紧接着0x08000000是其加载地址,然后0x00080000是其区域最大容量;
然后,ER_IROM1是Execution region的区域名,紧接着0x08000000是其可执行地址,也可以叫链接地址,然后0x00080000也是其区域最大容量;
在这里插入图片描述
接下来就是各种文件的链接方式了,解释如下

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

三、分析散列文件

打开uart.dis文件,可以看到有个__main,这就是keil添加的可执行代码,因为我们使用了main函数,所以这段代码被添加进去了,
在这里插入图片描述
我们将我们代码中的main改为mymain,可以看到,这段代码没有了
在这里插入图片描述
我们在main.c中添加如下所示变量定义,
在这里插入图片描述
然后编译,打开uart.dis文件,可以看到,myconst变量被链接到0x08…开头的地址,即ER_IROM1 区域,而mymydatemyzero即被链接到0x20…开头的地址,即RW_IRAM1 区域;与之相对应的,ER_IROM1 区域为该STM32的Flash地址,RW_IRAM1 区域为该STM32的RAM地址。
在这里插入图片描述
然后我们再看一下,uart.dis文件中,ER_IROM1 区域的最后一个位置0x080001ac存放的即我们定义的只读变量myconst
在这里插入图片描述
但我们使用STM32Cubeprg打开uart.hex文件可以看到,在0x080001ac后还有三个位置,而这三个位置存放的刚好就是我们定义的三个mymydatemyzero变量。
在这里插入图片描述
实际上,对于在STM32F103这类资源紧缺的单片机芯片中:

  • 代码段保存在Flash上,直接在Flash上运行(当然也可以重定位到内存里)
  • 数据段暂时先保存在Flash上,然后在使用前被复制到内存里(只读数据段不复制)

四、验证数据段的存放

修改main.c如下所示

#include "uart.h"
#include "led.h"

int mydata = 0x12315;
const int myconst = 0x22315;
int myzero = 0x0;
int my;

int mymain(void)
{
    uart_init();
    led_init();
    putstring("stm32f103zet6\r\n");
	putstring("mydata\t:");
    puthex((unsigned int)mydata);
    putstring("\r\nmyconst\t:");
    puthex((unsigned int)myconst);
	putstring("\r\nmyzero\t:");
    puthex((unsigned int)myzero);
    putstring("\r\nmy\t:");
    puthex((unsigned int)my);
    putstring("\r\n");

    while(1)
    {
		putstring("led on\r\n");
        led_on();
        delay(1000000);
		
		putstring("led off\r\n");
        led_off();
        delay(1000000);
    }
}

编译烧录运行,可以看到,只有myconst变量值是正确的,其他三个变量值都是错误的,这是因为我们并没有将那三个变量的值从Flash上复制到内存里,所以读取出来的只是上电后该RAM地址的一个随机值。
在这里插入图片描述
然后再添加一下地址的打印
在这里插入图片描述
编译烧录运行,可以看到,确实只有myconst变量值是保存在Flash的,其他三个变量值都是在内存里的

在这里插入图片描述

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

	int val = 3;
	
	putstring("val\t:");
    puthex((unsigned int)val);
	puthex((unsigned int)&val);
	putstring("\r\n");

编译烧录运行,可以看到,其地址确实在我们设置的栈中
在这里插入图片描述

五、附录

上一篇:STM32裸机开发(5) — 在Keil-MDK下编写uart串口打印程序
下一篇:STM32裸机开发(7) — 复制data段和清除BSS段(ZI段)
代码存放:https://gitee.com/william_william/stm32f103_noos/tree/master/keil-mdk/03_links

已标记关键词 清除标记
相关推荐
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质? 你是否想成为一名资深开发人员,想开发别人做不了的高性能程序? 你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹?   那么C++就是你个人能力提升,职业之路进阶的不二之选。 【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。 2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。 3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。 【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署; 2.吊打一切关于C++的笔试面试题; 3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。 【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块 基础篇 本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。 进阶篇 本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。 提升篇: 本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页