如何分析固件映像的大小?

时间:2017-09-25 15:59:39

标签: c++ g++ embedded firmware

我们目前正在使用他们的ESP-IDF框架基于流行的ESP32芯片开发IoT产品的固件,该框架使用GCC / G ++构建二进制文件 - 名为xtensa的工具链(https://github.com/icamgo/xtensa-toolchain )。

最近,我注意到二进制大小相当大(只有1 MB)并且决定看一看并尝试减少它。 NDEBUG已定义,-Os已启用且输出为strip ped。

基本上,工具链会生成.elf文件,因此我查看了其内容:

nm -S -C --size-sort <my-app>.elf

六个最大的函数(大小为6 kB-12 kB)是:

4011b24c 0000187b T __ssvfscanf_r
400f9f38 00001ffa T _svfiprintf_r
400f2aa4 000020fe T _vfiprintf_r
4012005c 000030d2 T _svfwprintf_r
400ef4d8 000030de T _svfprintf_r
400f50dc 000031e6 T _vfprintf_r

因此,我的固件映像中最大的功能是vfprintf和朋友,单独添加大约60 kB的二进制大小。他们为什么这么大?如何减小它们的大小或摆脱它们(我根本不需要vfprintf,因为我在微控制器上没有文件系统)?

还有其他减少二进制大小的技术吗?我将如何处理我的任务?

编辑(澄清优化原因):

ESP32有不同版本,最高 16 MB的闪存。我们使用的那个有4 MB。其中1 MB用于存储固定服务器证书,可信URL配置选项。而且,由于我们需要OTA更新功能,因此我们需要保留与应用程序映像所使用的相同数量的闪存,以用于新版本。这为我们的应用程序映像留下了1.5 MB的闪存,这与我们当前的1 MB相差不远。因此,我认为在问题阻止我们引入新功能之前考虑缩小尺寸是合理的。

我确实意识到60 kB的不需要的vfprintf()函数只占1 MB的一小部分,但我们确实需要很多实际有用的库(用于加密的mbedtls,一个完整的IP堆栈,一个瘦Web服务器,。 ..)。我无法摆脱这些,所以我想通过删除我没有任何用处的函数来尽可能地减小的大小

2 个答案:

答案 0 :(得分:3)

考虑到各个功能的大小并不是一种合理的方法。单个“微小”函数可能在其调用图中具有数百个同样微小的依赖关系,这些依赖关系构成了一个巨大的块。例如,以下内容:

int main()
{
    for(;;)
    {
        do_statemachine() ;
    }

    return 0 ;
}

main()会很小,但最终导致所有应用程序的其余部分被链接,因为do_statemachine()所做的任何事情都可以任何大小。您需要考虑函数的总大小和所有其依赖项。

同样,存储在ROM中的静态或常量数据初始化程序的总大小也需要考虑。

您应该使用链接器生成地图文件和调用图 - 这比在事件发生后使用nm更有用。

关于你问题中的特定符号,你必须问自己你在stdio中调用了什么?例如,printf需要流访问(对于stdout),格式说明符解析和可变参数遍历 - 即vfprintf提供的 all 。如果不是这样,你就会有重复的代码,虽然你可能会链接更少的函数,但它们都非常大并且可能表现出不同的行为。您在链接中具有“文件”导向功能的事实不是特定问题; stdio在流而不是文件上运行 - “文件”是概念性的,而不是物理的。如果您还没有将库连接到文件系统(或者如果工具中没有提供),则不会包含文件系统代码。低级别流访问由低级I / O功能执行,这些功能可能支持也可能不支持文件访问。

另一种可能性是库缺乏粒度 - 如果所有这些函数都在同一个对象模块中定义,则链接器别无选择,只能将它们全部链接,即使它们未被引用。这可以解释为什么链接中有整数,浮点和宽字符版本。

答案 1 :(得分:2)

那些符号出现的地方有更多您不需要的 wchar 相关符号。 您可以通过使用

构建 ESP32 工具链来摆脱这些符号
-fdata-sections -ffunction-sections 

为 newlib 启用。还要在 libstdc++ 上设置标志 --disable-wchar_t。然后使用 -Wl,--gc-sections 删除这些部分。

您也可以尝试使用 -flto 它应该为您做同样的事情 - 但我在使用 lto 构建 newlib 和 libstdc++ 时遇到了问题。似乎 libstdc++ 的构建工具在 newlib 档案中存在问题。 尽管如此,lto 是您在可能的情况下应该更喜欢的,因为它还可以很好地检测和 ODR 违规或其他可能隐藏的错误代码。