【发布时间】:2018-03-06 16:11:30
【问题描述】:
我们目前正在使用他们的 ESP-IDF 框架为基于流行的 ESP32 芯片的 IoT 产品开发固件,该框架使用名为 xtensa (https://github.com/icamgo/xtensa-toolchain) 的 GCC/G++ 工具链构建二进制文件。
最近,我注意到二进制文件的大小变得相当大(接近 1 MB),因此决定查看一下并尝试减小它。 NDEBUG 已定义,-Os 已启用,输出为 stripped。
基本上,工具链会生成一个.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 服务器、. ..)。我无法摆脱这些,所以我想通过删除我没有任何用处的函数来尽可能和可行地减小大小。
【问题讨论】:
-
??所以你有 12kiB 的不需要的代码,但你的固件还不到 1MiB? ~990kiB 刚刚“发生”在数千个微小的函数中,全部由你编写,或者我们应该如何理解它?您是否彻底检查了链接图,这是怎么回事? (谷歌给了我一些相关的文章,实际上专注于嵌入式,只是不同的平台embeddedrelated.com/showarticle/900.php)......减少二进制大小的技术=减少代码。例如,第一个计算器确实使用它自己的解释器来适应可用的 ROM (2kiB IIRC)。然后你又有 1+Mi ... :-o
-
如果它是物联网,它可能应该允许安全 [数字签名] 补丁、一些恢复模式/恢复出厂设置、一些加固的 TCP/IP 堆栈(可能是 IPv6 之一)等等......然后1MiB 可能不是那么多,我希望更像 10-100MiB 大小。
-
你可能不需要
vfprintfbytprintf可能是用它实现的。printf是对 stdio 流上的fprintf的调用,而后者又是对vfprintf的调用。剥离符号会减小 目标代码 而不是二进制文件的大小。 strip 删除的符号信息仅由开发主机调试器使用,而不是二进制映像的一部分。您应该指示链接器输出映射文件,而不是对 .elf 文件进行逆向工程。如果你的图像真的是 1Mb,那么 60kb 就是 6%——这真的是你的问题吗?数据常量或初始化器呢? -
ESP32 有 16Mb 的闪存;也许您过早地担心这个问题?
-
@old_timer : 资源有限!?我的梦想是 16Mb!