嵌入式软件面试之程序在存储器中的分布

Hi, 大家好,今天阿目分享的是一个嵌入式软件面试的常见问题,内存分布或者说程序在内存中的布局,我们写的程序是按照怎么的准则放在内存中的?

一般有操作系统的嵌入式设备,都会有一个Bootloader, 它负责在上电后初始化外设和系统配置,并把操作系统的代码从硬盘搬运到内存上,然后跳到操作系统的入口函数开始执行。因此,这种设计架构就会把程序放在内存,那么是遵循怎样的原则呢?相信大家一定看到过这样的内存分布图:

嵌入式软件面试之程序在存储器中的分布_第1张图片

其中常见的各个段的解析:

  1. 栈区(stack):
    用来存储函数调用时的临时信息的结构,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等。

  2. 堆区(heap):
    一般由程序员分配、和释放,用来存储程序运行时分配的变量。

  3. 全局区(静态区static):
    存放全局变量、静态数据。程序结束后由系统释放。全局区分为已初始化全局区(data)和未初始化全局区(bss)。

  4. 代码区(.text):
    存放函数体(类成员函数、静态函数和全局函数)的二进制代码。

  5. 内核区

    用于有操作系统的设计,用于存放操作系统代码,并会受到访问保护

需要注意的是上图中的分区,并不是固定的,也就是说每个软件设计者都可以灵活的安排这些区域的地址范围。这些都是在编译的链接脚本中可以指定地址范围的。

下面阿目还是以STM32的keil工程为例,为大家介绍,STM32工程配置的内存分布,该工程是基于STM32F103芯片,且不带操作系统。所以分区中就不需要考虑操作系统的部分了,那么具体有哪些分区呢?我们可以通过编译的map文件查看:

嵌入式软件面试之程序在存储器中的分布_第2张图片

上图就是map文件中的关于编译后的程序的地址分配信息,可以看到从1331行开始列出了地址信息,它属于哪个段呢?可以看关键字“Type”一列写的“Data”且属性列写的RO(read only的意思),所以0x0800_0000地址处放的就是一个只读变量,属于.data段;1332行“Type”一列写的“Code”,就是代码段(.text)的内容,它的地址是0x0800_00ec,其他行以此类推。

这里需要注意的是,STM32单片机运行时,代码段(.text)并不是在内存中的(启动模式设置为从Flash启动的情况),不像上面说的有些带有操作系统的设计方式,直接把所有代码放在内存中(因为一般这种设备内存会比较大),但是单片机芯片一般内存都比较小且执行效率要求没有那么高,所以为了节省成本会把程序放在Flash中,在执行过程中从Flash中取指令执行,所以这里的地址是从0x0800_0000开始的。

如果Flash的大小是10KB,那么这里代码段的地址空间可以理解为0x0800_0000~0x0800_2800, 一般不会把Flash空间全部当作用户的代码存放空间,因为芯片厂商一般会保存自家芯片的一些参数到Flash中,所以会占用一些空间。

嵌入式软件面试之程序在存储器中的分布_第3张图片

上面就是需要放在RAM中的.data段了,上期也有讲到,.data段在没有启动时是放在Flash中保存的,在启动后,将他们搬运到ram中,所以这里map文件列出了两个地址一个是 Exec Addr(执行地址), 一个是Load Addr(加载地址), 执行地址就是RAM的地址,加载地址就是这个变量存放在Flash中的地址。

1426行的一个数据它在RAM中的地址就是0x2000_0000,RW表示可读可写;1437行写出了STACK(栈空间)的地址,0x2000_0058,大小是0x400,也就是1KB,即stack空间的地址范围为:0x2000_0058 ~0x2000_0457。

这里的.data段的空间其实并没有明确规定,它只是在编译时由编译器安排的,程序中有几个全局变量或者静态变量就安排几个地址,并没有指定这个空间的结束地址。

ending~~

你可能感兴趣的:(面试,职场和发展,c++,嵌入式硬件,mcu)