ESP8266 基础篇:RTOS SDK 内存优化方法

阅读本文前,建议先阅读《esp8266 内存分布》《esp8266 段的概念》

通过《esp8266 段的概念》,我们已经知道 .rodata 会占用 dRAM 的空间,从而减小实际可用的 heap 空间大小。因此我们当前的优化目标就是减小 .rodata 的使用量。

os_printf

为了减小打印字符串所占用的 dRAM 空间,在 sdk 中一直存在着一个看上去有些奇怪的打印宏 os_printf,我们来看看它是怎么定义的:

#define os_printf(fmt, ...) do {    \
        static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt;  \
        printf(flash_str, ##__VA_ARGS__);   \
    } while(0)

首先是 ICACHE_RODATA_ATTR 的定义,如下:

#define ICACHE_RODATA_ATTR  __attribute__((section(".irom.text")))

再在 ld/eagle.app.v6.common.ld 中看看 .irom.text 被放在哪儿了:

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

ok,os_printf 里就是把打印的字符串,通过 .irom.text 这个 attribute 强制放到 .irom0.text 段,从而节省了部分 dRAM 空间。

下面我们就来找找,这个字符串具体在哪,还是以 rtos 的 openssl_demo 为例,编译完之后:

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

我们会看到如下信息:

.irom.text                          48      0

通过以下命令:

xtensa-lx106-elf-objdump -s -j .irom.text libuser.a

可看到具体的 .irom.text:

Contents of section .irom.text:
 0000 53444b20 76657273 696f6e3a 25732025  SDK version:%s %
 0010 640a0000 73746120 676f7420 6970202c  d...sta got ip ,
 0020 20637265 61742074 61736b20 25640a00   creat task %d..

结合 user_main.c 看一看,清晰了。我们再通过 *.dump,可以找到这段字符串的具体位置:

402295b0 63206970 210a0000 53444b20 76657273  c ip!...SDK vers
402295c0 696f6e3a 25732025 640a0000 73746120  ion:%s %d...sta
402295d0 676f7420 6970202c 20637265 61742074  got ip , creat t
402295e0 61736b20 25640a00 7461736b 20657869  ask %d..task exi

ld 文件的修改

esp8266 rtos sdkcommit:17c49717 开始,支持将 rodata 放在 spi flash 中,从而增加可使用的 dRAM 空间,即可增加应用可使用的 heap 空间。这是咋实现的?细心的同学可能在提交中发现 ld/eagle.app.v6.common.ld 中的 .irom0.text 段变了。但这次提交也不仅仅只是修改了 ld,在 sdk 中也做了相应的修改,从而实现了该功能。

.irom0.text : ALIGN(4)
{
    _irom0_text_start = ABSOLUTE(.);
    *libuser.a:(.rodata.* .rodata)
    *libcirom.a:(.rodata.* .rodata)
    *libmbedtls.a:(.rodata.* .rodata)
    *libssl.a:(.rodata.* .rodata)
    *libopenssl.a:(.rodata.* .rodata)
    *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
    *(.literal.* .text.*)
    _irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr

多了些 *libuser.a:(.rodata.* .rodata) 这样的行,干啥滴?其实就是把如 libuser.a 中的所有 .rodata.* 和 .rodata 放到 .irom0.text 段里。

实验一下,我们先把这些行删除,编译后,查看 *.dump 文件,.rodata 信息是这样的:

1 .irom0.text   0005375c  40201010  40201010  00009170  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
3 .rodata       00001138  3ffe88b0  3ffe88b0  00000990  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

.rodata 占用了 0x1138 字节。

恢复,编译后查看 *.dump 文件,.rodata 信息是这样的:

1 .irom0.text   000546ec  40201010  40201010  000081e0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
3 .rodata       000001a8  3ffe88b0  3ffe88b0  00000990  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

.rodata 占用了 0x1a8 字节,相较之前的,节省了约 4KB 空间。对比 .irom0.text,则增加了约 4KB 空间。

当前 ld 文件中仅将部分库中的 .rodata 置于 .irom0.text 段,如果用户需要将其他库中的 .rodata 置于 .irom0.text 段,可以通过修改 ld 文件来实现。

例如 rtos 的 openssl_demo 中,programs 中的 .rodata 默认并未被放在 .irom0.text 中,可以在 ld 文件中添加如下行:

*openssl_demo.a:(.rodata.* .rodata)

为啥是这个名字的库,结合 openssl_demo/programs/Makefile 看,如果你要修改,还得具体看实际情况了。

重新编译后,查看 *.dump 文件:

1 .irom0.text   000546fc  40201010  40201010  000081d0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
3 .rodata       00000190  3ffe88b0  3ffe88b0  00000990  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

结合上面的数据,.rodata 近一步减小。

注意:
我们不建议将 sdk 中的其他库加入进来。

总结

rtos sdk 在 commit 17c49717 之后,可以通过修改 ld 文件的方法将特定库中的 .rodata 数据置于 spi flash,在这个库中可以直接使用 printf 来进行打印。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值