分析ELF二进制文件以最小化其大小

时间:2014-08-26 19:29:40

标签: gcc linker arm v8 elf

我正在使用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

3 个答案:

答案 0 :(得分:6)

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

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

链接器映射将包含许多部分。第一部分"归档成员包括因为文件(符号)"有助于确定导致对象链接到可执行文件的原因,但不是那么多的东西会膨胀可执行文件的大小。一旦你想出来,它变成了一个错误的库,你可以回到这一部分。 "分配公共符号","废弃输入部分","内存配置"部分可能不会非常有用。

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

现在,您必须浏览每个链接对象文件的跟踪,并将其符号添加到可执行文件的每个部分。因为它只是一个" Hello World"问题不应该太糟糕。跳到您已确定为问题的部分。现在扫描对象列表,看看是否可以找到大量不明显必需的目标文件被链接的位置或者地址突然大量跳跃的位置。后者应该相对容易发现,但前者很难识别。如果为静态链接的" Hello World"生成链接器映射可能会有所帮助。在您的本机平台上编程,以查看它链接的库例程。

我的猜测是你的问题会显示为地址的大幅跳跃,或者显然不应该被链接的某个文件。所以不要被问题的冗长所拖延。地图文件。 C ++符号也应该被解码,因此它不会像nm一样糟糕。 (虽然您可以nm使用-C选项对名称进行解码。)

答案 1 :(得分:0)

我不知道ARM,所以你可能无法使用pmap ....对不起,如果这不能为你飞。 Gnu发行版通常具有pmap命令。

重写&编译你好世界继续运行(内存驻留),直到你点击返回,一个fgets调用将起作用。

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

pmap -d pid

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

答案 2 :(得分:0)

它也可能值得启用链接器垃圾收集,假设工具链支持它,默认情况下它尚未启用,并且链接描述文件正确写入。请参阅https://sourceware.org/binutils/docs/ld/Options.html#index-g_t_002d_002dgc_002dsections-173