ESP8266 基础篇:段的概念

大家在使用 esp8266 的过程中,可能会有如下疑问,比如:函数放在那儿了?变量放在哪儿了?常量放在哪儿了?等等

本文以 esp8266 rtos sdk 为例,进行分析,esp8266 nonos sdk 有些许差异,希望在阅读完本文之后,可以旁通。阅读前本文前,先阅读《esp8266 内存分布》

我们先来看看编译生成的 *.dump 文件吧,比如 bin/upgrade/user1.1024.new.2.dump。

以下以 rtos 的 openssl_demo 为例,打开 dump 文件,我们可以看到如下信息:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000076a1  40100000  40100000  00001ad4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .irom0.text   00053778  40201010  40201010  00009180  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .data         000008ac  3ffe8000  3ffe8000  000000e0  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  3 .rodata       00001144  3ffe88b0  3ffe88b0  00000990  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .bss          00006fc8  3ffe99f8  3ffe99f8  00001ad8  2**4
                  ALLOC

如果之前未接触过 gcc,那可能会有这样的疑问:为什么这些段,比如 .text 会被放在特定的地址?这个其实是链接器干的事情,在链接的环节中,链接器会读取 ld 目录下的特定 *.ld 文件,从而将特定 attribute 属性的函数、变量等放在了特定的位置。

打开 ld/eagle.app.v6.common.ld,可以看到类似如下信息:

.text : ALIGN(4)
{
    ...
} >iram1_0_seg :iram1_0_phdr

简单说,就是将 .text 段放到 iram1_0_seg 里,结合 ld/eagle.app.v6.ld,可以看到如下信息:

MEMORY
{
  ...
  iram1_0_seg : org = 0x40100000, len = 0x8000
  ...
}

这样我们就该知道为什么 .text 段会位于 0x40100000 开始的位置了。ld 的事说来话长,想详细了解的,可以看看博友们关于 ld 的文章:)

以下简要介绍 esp8266 sdk 中各个段的意义。

.text & .irom0.text

均是用来存放程序执行代码的区域,.text 段位于 iRAM 空间,.irom0.text 段会被映射到 cache 空间。

在编译选项 -ffunction-sections 打开的情况下,函数的默认属性为 *.text.*,我们可以通过如下方法查看:

cd user/.output/eagle/debug/lib
xtensa-lx106-elf-size -A libuser.a

我们会看到如下信息:

.text.user_init                    174      0

user_init 函数的属性为 .text.user_init,在 rtos sdk 的 ld/eagle.app.v6.common.ld 中,我们可以看到:

.irom0.text : ALIGN(4)
  {
    ...
    *(.literal.* .text.*)
    ...
  } >irom0_0_seg :irom0_0_phdr

*.text.* 属性的函数,将会被放到 .irom0.text 段中,通过 dump 文件,我们可以看到:

40232158 g     F .irom0.text    00000062 user_init

链接到 .irom0.text 段的函数会位于 spi flash,将通过 cache 预取。

我们也可以通过 IRAM_ATTR 强制将函数的属性改为 .text。IRAM_ATTR 的定义如下:

#define IRAM_ATTR           __attribute__((section(".text")))

在 openssl_demo 中,给 user_init 函数加上 IRAM_ATTR 后,重新编译,通过 xtensa-lx106-elf-size 命令,已经找不到 .text.user_init 了,但是可以发现 .text 变大了:

.text                              166      0

我们再来看看 ld/eagle.app.v6.common.ld 文件,

.text : ALIGN(4)
  {
    ...
    *(.literal .text .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
    ...
  } >iram1_0_seg :iram1_0_phdr

通过 dump 文件,我们可以看到:

40107130 g     F .text  0000006e user_init

user_init 函数已经位于 .text 段内,将在系统启动时,被 bootloader 加载到 iRAM 空间。

我们还可以通过修改 ld 文件,强制将某些库中的某些属性的函数放在某个段中,比如:

.text : ALIGN(4)
{
    ...
    *libfreertos.a:(.literal .text .literal.* .text.*)
    ...
} >iram1_0_seg :iram1_0_phdr

FreeRTOS 中的所有函数,将被强制放在 .text 段中,即均在 iRAM 中运行。

.data & .rodata & .bss

.data 段通常是用来存放程序中已初始化的全局变量的一块内存区域,属于静态内存分配。

.bss 段通常是指用来存放程序中未初始化的全局变量的一块内存区域。属于静态内存分配。

.rodata 段通常是指用来存放程序中常量的一块内存区域。属于静态内存分配。

查看 ld/eagle.app.v6.common.ld,可以看到 .data、.bss、.rodata 段均 >dram0_0_seg,因此都在 dRAM 内。

在 .dump 文件内,我们可以看到不是 static 的 .data、.bss、.rodata 的地址,比如:

3ffe8010 g     O .data  00000018 flashchip
3ffee6c8 l     O .bss   00000400 recv_buf
3ffe8a38 g     O .rodata        00000004 ip_addr_any

.rodata 数据在整个程序运行过程中均不会改变,比如 const 的常量、字符串等,因此放在 dRAM 中是很浪费的,所以我们有其他方法来做这部分优化,以释放更多的 dRAM 空间。

heap

用于存放程序运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。为什么说他是大小是动态的,因为这完全取决于 .data、.bss、.rodata 的大小。

在 ld/eagle.app.v6.common.ld 中,决定了 .data、.rodata、.bss 在 dRAM 中的依次分布,可以通过 *.dump 查看。

heap 区的起始地址,在 .bss 段中有定义:

.bss ALIGN(8) (NOLOAD) : ALIGN(4)
{
    ...
    _heap_start = ABSOLUTE(.);
  } >dram0_0_seg :dram0_0_bss_phdr

通过 *.dump 文件,可以看到:

3ffefa20 g       *ABS*  00000000 _heap_start

因此,实际 heap 空间为 0x3ffefa20 ~ 0x3fffffff。

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值