GCC正在生成填充零的二进制文件 [英] GCC is generating binaries filled with zeroes

查看:65
本文介绍了GCC正在生成填充零的二进制文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图弄清楚为什么GCC生成的二进制文件如此之大.

I'm trying to figure out why the binaries generated by GCC are so large.

考虑这个空程序:

int main() {
    return 0;
}

现在,我使用 GCC 9.2.1 20190827(Red Hat 9.2.1-1) glibc 2.29 构建它,而没有任何其他参数:

Now I build it with GCC 9.2.1 20190827 (Red Hat 9.2.1-1) and glibc 2.29 without any additional parameters:

gcc -o test test.c

生成的二进制文件为21984字节(〜22 KB).用 xxd 查看生成的文件,在多个地方长期存在空字节:

The resulting binary is 21984 bytes (~22 KB). Looking at the generated file with xxd, there are long runs of null-bytes in multiple places:

00000370: 006c 6962 632e 736f 2e36 005f 5f6c 6962  .libc.so.6.__lib
00000380: 635f 7374 6172 745f 6d61 696e 0047 4c49  c_start_main.GLI
00000390: 4243 5f32 2e32 2e35 005f 5f67 6d6f 6e5f  BC_2.2.5.__gmon_
000003a0: 7374 6172 745f 5f00 0000 0200 0000 0000  start__.........
000003b0: 0100 0100 0100 0000 1000 0000 0000 0000  ................
000003c0: 751a 6909 0000 0200 1d00 0000 0000 0000  u.i.............
000003d0: f03f 4000 0000 0000 0600 0000 0100 0000  .?@.............
000003e0: 0000 0000 0000 0000 f83f 4000 0000 0000  .........?@.....
000003f0: 0600 0000 0200 0000 0000 0000 0000 0000  ................
00000400: 0000 0000 0000 0000 0000 0000 0000 0000  ................
<3040 bytes of zeroes>
00000ff0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001000: f30f 1efa 4883 ec08 488b 05e9 2f00 0048  ....H...H.../..H
<not zeroes>
00001190: f30f 1efa c300 0000 f30f 1efa 4883 ec08  ............H...
000011a0: 4883 c408 c300 0000 0000 0000 0000 0000  H...............
000011b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
<3632 bytes of zeros>
00001ff0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00002000: 0100 0200 0000 0000 0000 0000 0000 0000  ................
00002010: 011b 033b 3400 0000 0500 0000 10f0 ffff  ...;4...........
<not zeroes>
000020e0: 410e 2842 0e20 420e 1842 0e10 420e 0800  A.(B. B..B..B...
000020f0: 1000 0000 ac00 0000 98f0 ffff 0500 0000  ................
00002100: 0000 0000 0000 0000 0000 0000 0000 0000  ................
<3376 bytes of zeroes>
00002e40: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00002e50: 0011 4000 0000 0000 d010 4000 0000 0000  ..@.......@.....
...

因此,生成的二进制文件大约有10 KB或几乎一半的内容.

So the resulting binary has around 10 KB, or almost half, of nothing in it.

使用 size -A 来查看,其大小更像是程序不执行任何其他操作(而不是返回退出代码)所期望的大小:

Looking with size -A, the size is more like what one would expect from a program doing nothing else than returning an exit code:

test  :
section                 size      addr
.interp                   28   4194984
.note.ABI-tag             32   4195012
.note.gnu.build-id        36   4195044
.gnu.hash                 28   4195080
.dynsym                   72   4195112
.dynstr                   56   4195184
.gnu.version               6   4195240
.gnu.version_r            32   4195248
.rela.dyn                 48   4195280
.init                     27   4198400
.text                    373   4198432
.fini                     13   4198808
.rodata                   16   4202496
.eh_frame_hdr             52   4202512
.eh_frame                192   4202568
.init_array                8   4210256
.fini_array                8   4210264
.dynamic                 400   4210272
.got                      16   4210672
.got.plt                  24   4210688
.data                      4   4210712
.bss                       4   4210716
.comment                  44         0
.gnu.build.attributes   4472   4218912
Total                   5991

使用 GCC 9.2.0 musl 1.1.23 对PowerPC进行交叉编译时,情况更糟.二进制文件的大小增长到67872字节(〜67 KB),并且使用 xxd 进行查看,连续运行的64074字节只有零.

When cross-compiling for PowerPC using GCC 9.2.0 and musl 1.1.23 it's even worse. Size of the binary grows to 67872 bytes (~67 KB), and looking with xxd, there is a continuous run of 64074 bytes of only zeroes.

size -A 仍然报告该版本的尺寸更小:

Still, size -A reports even smaller sizes for this version:

test  :
section              size        addr
.interp                26   268435796
.note.gnu.build-id     36   268435824
.hash                  36   268435860
.dynsym                64   268435896
.dynstr                39   268435960
.rela.plt              12   268436000
.init                  28   268436012
.text                 496   268436048
.fini                  28   268436544
.eh_frame_hdr          28   268436572
.eh_frame              80   268436600
.init_array             4   268566284
.fini_array             4   268566288
.dynamic              216   268566292
.branch_lt              8   268566508
.got                   12   268566516
.plt                    4   268566528
.data                   4   268566532
.bss                   28   268566536
.comment               17           0
Total                1170

我还尝试使用我碰巧可以使用的旧版GCC编译程序: GCC 4.7.2 uClibc 1.0.12 .通过这种组合,生成的二进制文件只有4769个字节(〜4 KB),并且其中没有明显的空字节运行.

I also tried to compile the program with an old version of GCC which I happened to have handy: GCC 4.7.2 with uClibc 1.0.12. With this combination, the resulting binary is only 4769 bytes (~4 KB), and has no apparent runs of null-bytes in it.

为了确保不仅在不执行任何操作的微型程序中发生这种情况,我查看了一些与 GCC 9.2.0 musl交叉编译的真实程序1.1.23 .例如,使用 -Os 编译并剥离的tcpdump二进制文件包含一个32628字节长的连续连续的空字节.那么,为什么零试图占用我的所有磁盘空间?

Just to make sure that this doesn't only happen on tiny programs that do nothing, I looked at some real programs that I have cross-compiled with GCC 9.2.0 and musl 1.1.23. For example, tcpdump binary, compiled using -Os and stripped, contains a 32628 byte long continous run of null-bytes. So, why are zeroes trying to consume all of my disk space?

推荐答案

Florian Weimer的答案帮助了我右边方向.罪魁祸首不是-z分隔码,而是-z relro.

Answer from Florian Weimer helped me to the right direction. The culprit was not -z separate-code, but -z relro.

通过在PowerPC GCC选项中添加-Wl,-z,norelro,空程序的文件大小将从67872字节减少到3772字节!在x64上,影响较小:从21984到18584字节.在一个小型但实际上可以运行的程序上,PowerPC上的差异大约缩小了50%,而与我之前比较的tcpdump相比,它几乎减少了32 KB.

By adding -Wl,-z,norelro to PowerPC GCC options, file size for an empty program dropped from 67872 bytes to 3772 bytes! On x64 the impact was smaller: from 21984 to 18584 bytes. On a small, but actually functional, program the difference on PowerPC was around 50 % smaller, and with tcpdump, which I compared before, it's almost 32 KB.

显然,relro链接器选项创建了一个新段,该段用于重新映射全局偏移表并将其标记为只读,从而保护程序免受堆栈溢出攻击.这种解释很可能是不准确的.尝试弄清楚时,我对所读的内容不甚了解.

The relro linker option apparently creates a new segment, which is used to remap the global offset table and mark it as read-only, which protects the program from stack overflowing attack. This explanation is most likely inaccurate; I didn't understand much of what I read while trying to figure it out.

PPC的大小差异恰好是62 KB.为什么创建这么大的面积,我不知道.

The size difference on PPC is exactly 62 KB. Why such a large area is created, I have no idea.

尽管最好将该设置作为加强措施来启用,但不幸的是,我的目标板上只有11 MB的可用闪存,而且我试图在其上安装基于Linux的系统,因此每个字节都很重要,我将禁用该设置以减小二进制大小.

Although the setting would be good to be kept enabled as a hardening measure, unfortunately my target board has only 11 MB of available flash, and I'm trying to fit a Linux-based system on it, so every byte counts, and I will disable the setting to keep the binary sizes down.

这篇关于GCC正在生成填充零的二进制文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆