【问题标题】:Analyzing an ELF binary to minimize its size分析 ELF 二进制文件以最小化其大小
【发布时间】:2014-08-26 19:29:39
【问题描述】:

我正在使用 GCC arm-gnueabi 交叉编译器将 V8 项目交叉编译到嵌入式 ARM 目标。我成功地交叉编译了 V8 库本身,作为冒烟测试,我想将它链接到 Google 的 hello world 示例并在 ARM 板上运行它。

库本身的时钟超过 1.2 MB:

v8 % find out/arm.release/obj.target/ -name '*.a' -exec du -h {} + 
1.2M    out/arm.release/obj.target/tools/gyp/libv8_base.a
12K     out/arm.release/obj.target/tools/gyp/libv8_libbase.a
4.0K    out/arm.release/obj.target/tools/gyp/libv8_libplatform.a
4.0K    out/arm.release/obj.target/tools/gyp/libv8_snapshot.a
4.0K    out/arm.release/obj.target/tools/gyp/libv8_nosnapshot.a
4.0K    out/arm.release/obj.target/third_party/icu/libicudata.a
164K    out/arm.release/obj.target/third_party/icu/libicuuc.a
336K    out/arm.release/obj.target/third_party/icu/libicui18n.

然而,当我构建和链接时

arm-linux-gnueabi-g++ -pthread -Iv8/include hi.cpp -Os -o hi_v8 -Wl,--start-group v8/out/arm.release/obj.target/{tools/gyp/libv8_{base,libbase,snapshot},third_party/icu/libicu{uc,i18n,data}}.a -Wl,--end-group

我得到一个 20 MB 的可执行文件。剥离它只会让我减少到 17 MB

什么是链接在气球文件大小这么多?我怎样才能避免它?我可以使用哪些工具来诊断问题?这个尺寸在我定位的平台上可能有问题。

我查看了readelf --sections,但它只是告诉我.text 部分的整体大小,这并不是特别有用。我还查看了建议 here 并尝试使用 nm,但它太具体 - 我只是一堆名称混乱的符号,如 _ZN2v88internal11FLAG_log_gcE。

【问题讨论】:

  • 尝试不同的工具链(如 Linaro 的)来解决工具链问题。

标签: gcc linker arm v8 elf


【解决方案1】:

首先,如果您还没有,请使用size -A hi_v8 确定哪个或哪些部分比您预期的要大。它并不总是文本部分。

接下来将-Wl,-Map,hi_v8.map 添加到g++ 命令行。这将在文件hi_v8.map 中生成一个链接器映射。该文件的内容将非常冗长,但它将显示每个目标文件对可执行文件中每个部分的贡献。

链接器映射将包含多个部分。第一部分“由于文件(符号)而包含的存档成员”有助于确定导致对象链接到可执行文件的原因,但不知道是什么增加了可执行文件的大小。一旦你弄清楚了,它变成了一个错误的库,你可以回到这个部分。 “分配常用符号”、“丢弃的输入部分”、“内存配置”部分可能不会很有帮助。

“链接器脚本和内存映射”部分是您要集中注意力的地方。它本质上是用于生成可执行文件的链接描述文件的跟踪。首先检查开头的LOAD 语句,它们显示可执行文件链接的每个文件。检查是否有任何您不希望看到的文件,但是这里会提到库,即使它们的目标文件都没有链接到可执行文件中。

现在您将不得不遍历每个链接目标文件的跟踪,以及添加到可执行文件每个部分的符号。由于这只是一个“Hello World”问题,它应该不会太糟糕。跳到您确定为问题的部分。现在扫描对象列表,看看是否可以找到链接大量不明显必要的对象文件的位置,或者地址突然大量跳转的位置。后者应该相对容易发现,但前者可能很难识别。如果您在本地平台上为静态链接的“Hello World”程序生成链接器映射,以查看它链接的库例程类型,这可能会有所帮助。

我的猜测是,您的问题将显示为地址中的一个大跳转,或者一些显然不应该链接的文件。所以不要被地图文件的冗长推迟。 C++ 符号也应该被解构,所以它不会像nm 那样糟糕。 (尽管您可以使用 -C 选项来获取 nm 来破解名称。)

【讨论】:

  • 问题是那些库是“瘦”档案,只是指向别处的目标文件(见stackoverflow.com/questions/25554621/…)。无论如何,我选择您的答案是因为您提供了出色的调试建议。谢谢!
【解决方案2】:

我不了解 ARM,因此您可能无法使用 pmap.... 对不起,如果这不能为您服务。 Gnu 发行版通常有 pmap 命令。

重写和编译 hello world 以保持运行(内存驻留)直到您点击返回,fgets 调用将起作用。

接下来,在单独的窗口中,执行

pmap -d pid

其中 pid 是 hello world 进程的 pid。 pmap -d 显示每个链接对象的大小。

【讨论】:

    【解决方案3】:

    还可能值得启用链接器垃圾收集,假设工具链支持它,默认情况下尚未启用它,并且链接器脚本编写正确。见https://sourceware.org/binutils/docs/ld/Options.html#index-g_t_002d_002dgc_002dsections-173。

    【讨论】:

      猜你喜欢
      • 2020-10-01
      • 2013-02-25
      • 1970-01-01
      • 2010-10-03
      • 2010-10-31
      • 1970-01-01
      • 2022-10-13
      • 2021-07-20
      • 2011-10-27
      相关资源
      最近更新 更多