ESP8266 段的概念

转载至:https://blog.csdn.net/espressif/article/details/78563811   

我们在使用ESP8266的过程中,可能会有疑问,如: 函数放在哪了? 变量放在哪了?常量放在哪了?等等

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

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

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

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

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

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

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

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

  1. MEMORY
  2. {
  3.      ...
  4.     iram1_0_seg : org = 0x40100000, len = 0x8000
  5.     ...
  6. }

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

.text & .irom0.text

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

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

  1. cd user/.output/eagle/debug/lib
  2. 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 中,我们可以看到:

 

  1. .irom0.text : ALIGN(4)
  2. {
  3.     ...
  4.    *(.literal.* .text.*)
  5.     ...

} >irom0_0_seg :irom0_0_phdr

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

  1. 40232158 g F .irom0.text 00000062 user_init

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

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

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

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

 

  1. .text 166 0

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

  1. .text : ALIGN(4)
  2.   {
  3.     ...
  4.     *(.literal .text .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
  5.     ...
  6.   } >iram1_0_seg :iram1_0_phdr 

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

  1. 40107130 g F .text 0000006e user_init

 

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

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

  1. .text : ALIGN(4)
  2. {
  3.   ...
  4. *libfreertos.a:(.literal .text .literal.* .text.*)
  5.   ...
  6. } >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 的地址,比如:

  1. 3ffe8010 g O .data 00000018 flashchip
  2. 3ffee6c8 l O .bss 00000400 recv_buf
  3. 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 段中有定义:

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

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

  1. 3ffefa20 g *ABS* 00000000 _heap_start


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值