【问题标题】:What is the minimum amount of code that gets into the .elf image进入 .elf 图像的最少代码量是多少
【发布时间】:2021-08-29 21:54:04
【问题描述】:

首先介绍一下上下文。

ESP32 使用 esp-idf 框架最新版本,并且无法将我的代码安装在默认分区的 1MB 大小限制下。我注意到一个简单的 WiFi 客户端(我的意思是非常简单,没有任何 HTTP 请求或服务器)只占用了大约 40% 的可用空间。

我在链接时想知道对于任何给定的依赖项,链接器将在输出图像文件中放置的最小代码块是多少。

它是文件级别 (xxx.o) 还是能够以某种方式变得更细化?

还有任何链接开关可以列出任何给定 .o/.a 文件的所有引用吗? (即:他们依赖它的地方)

提前致谢

亚历克斯

【问题讨论】:

    标签: gcc linker esp32 esp-idf


    【解决方案1】:

    链接器在函数/方法和变量级别是细粒度的。如果未引用函数、方法或变量,则无需将其包含在链接的二进制文件中。

    您可以使用objdump 程序自行检查(您可能需要在系统上安装它;还有其他工具可以读取可能已经安装的 .elf 二进制文件)。

    这是一个简单的程序。这是使用 Arduino 框架的 C++,但它使用与 ESP-IDF 相同的工具链,因为它是基于它构建的。我包括了 WiFi,只是给它一点重量。

    #include <Arduino.h>
    
    #include <WiFi.h>
    
    void ignore_me() {
      Serial.println("this will never happen");
      Serial.println("this code won't even be linked in");
    }
    
    void setup() {
      WiFi.begin("foo", "bar");
    }
    
    void loop() {
    }
    

    构建完成后就可以运行了

    objdump --syms firmware.elf
    

    查看符号列表。例如,我们可以这样找到setup() 函数:

    objdump --syms firmware.elf | grep setup
    

    返回:

    40120cbc l     F .flash.text    00000032 setup_tcp
    4012cd18 l     F .flash.text    00000013 __esp_stack_guard_setup
    4010a2c8 g     F .flash.text    0000007d hostapd_setup_wpa_psk
    400f8cb4 g     F .flash.text    0000032f esf_buf_setup
    400d8f18 g     F .flash.text    0000008e ieee80211_setup_basic_htrates
    400d9580 g     F .flash.text    000000da ieee80211_setup_phy_mode
    4012edd4 g     F .flash.text    00000037 esp_setup_syscall_table
    4008bb58 g     F .iram0.text    00000000 _frxt_setup_switch
    400e02cc g     F .flash.text    00000141 ieee80211_send_setup
    4013c320 g     F .flash.text    00000084 ieee80211_setup_lr_rates
    400d8e4c g     F .flash.text    000000c6 ieee80211_setup_htrates
    400d965c g     F .flash.text    00000134 ieee80211_setup_rates
    40058cc8 g       *ABS*  00000000 __swsetup_r
    400e2324 g     F .flash.text    00000101 ieee80211_setup_ratetable
    400d04a8 g     F .flash.text    0000001c _Z5setupv
    4013c3a4 g     F .flash.text    00000007 ieee80211_setup_rateset
    40026c84 g       *ABS*  00000000 lmp_setup_cmp_handler
    

    符号_Z5setupv 对应于设置功能。多余的字符是由于 C++ 添加了类型信息(例如,结尾的 v 表示它的参数是 void)。

    跑步

    objdump --syms firmware.elf | grep ignore
    

    将不返回任何内容,因为函数 ignore_me() 未包含在链接的二进制文件中。

    如果我们返回并修改setup() 以调用ignore_me() 并再次运行objdump,我们将看到如下内容:

    400d04ac g     F .flash.text    0000001a _Z9ignore_mev
    

    表示现在 ignore_me() 已包含在二进制文件中,因为它正在被调用。

    0000001a 是与符号关联的代码的大小。您可以使用objdump 的输出来查找二进制文件中最大的函数;您也许可以重写它以消除其中的一些。 (剧透:printf() 及其亲属通常很大。)

    您还可以将objdump.a.o 文件一起使用。

    【讨论】:

    • 非常感谢 romkey 的清晰透彻的解释。!!
    • @Alex - 不客气,很高兴它有帮助:) 如果它确实有帮助,接受它作为答案将帮助其他人知道它是有用的。
    【解决方案2】:

    ESP-IDF 文档中有一篇文章如何minimize the binary size 的 ESP-IDF 应用程序。如果你愿意,你可以list the size per-component 甚至每个文件。

    话虽如此,如果您使用 C++,请尽量避免使用iostream,它往往会占用大量空间。您可以改用printf()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      • 2017-06-02
      • 2013-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多