微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

gcc:通过 gcc 将 -nostartfiles 传递给 ld 以获得最小的二进制大小

如何解决gcc:通过 gcc 将 -nostartfiles 传递给 ld 以获得最小的二进制大小

考虑以下用于 64 位 linux 的 gas(GNU 汇编程序)文件

go.s

        .global _start
        .text

_start:
        mov     $60,%rax               # system call 60 is exit
        xor     %rdi,%rdi              # we want return code 0
        syscall  

现在编译:

rm -f go go.o
as -o go.o go.s
ld -o go -s -nostartfiles go.o
ls -l go                                            # -> 344 bytes

我们得到了一个 344 字节的超小尺寸。

太好了!使用 gcc 和单独的 ld 命令:

# gcc with separate link
rm -f go go.o
gcc -xassembler -c go.s
ld -s -nostartfiles -o go go.o
ls -l go                                            # -> 344 bytes

但是如何只使用一个 gcc 命令就能获得这么小的尺寸

# single gcc command                                                                                                                                                                     
rm -f go go.o
gcc -xassembler -s -static -nostartfiles -o go go.s
ls -l go                                            # -> 4400 bytes  too big!!!

该死的 4400 字节!哪一行 gcc 调用将给出 344 个字节?

使用 -v 标志运行上述单行...

gcc -v -xassembler -s -static -nostartfiles -o go go.s

... 表明 -nostartfiles 不会传递给 collect2 链接命令。

嗯...

任务:向我展示给出最小尺寸的单行 gcc 调用

谢谢。


尝试使用 -v 标志:

gcc -v -xassembler -s -static -nostartfiles -o go go.s

执行以下操作:

as -v --64 -o go.o go.s

# will give 4400 bytes
/usr/lib/gcc/x86_64-linux-gnu/8/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id -m elf_x86_64 --hash-style=gnu -static -o go -s -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/8/../../.. go.o --start-group -lgcc -lgcc_eh -lc --end-group

-nostartfiles 命令(上面)中手动添加 collect2(直接在 /usr/lib/gcc/x86_64-linux-gnu/8/collect2 之后)得到 520 字节的大小。

手动添加 -nostartfiles(直接在 collect2 之后)并删除 --build-id 会得到 344 字节的大小。正如我们所看到的 here-Wl,--build-id=none 应该删除构建 ID。

但是如何指示 gcc 将 -nostartfiles 传递给 ldcollect2


回应小丑的评论

执行以下操作 (-Wl,-nostartfiles):

gcc -Wl,-nostartfiles,--build-id=none -v -xassembler -s -static -nostartfiles -o go go.s

将在 -nostartfiles 命令的末尾添加 collect2 ,结果甚至不会创建输出二进制文件 go。如何给出命令,以便 -nostartfilescollect2 ... 命令中更早出现:我知道它有效,如果我在开始时手动构造 -nostartfiles 作为标志

看看 here,有人声称 -Wl,-nostartfiles 不会被正确处理。但是如果我只使用 gcc -nostartflags ...,那么它不会传递给链接器: Maby 这是 gcc 中的一个错误??

Maby 所有代码都被优化掉了……什么都不留下??见here

解决方法

-nostartfiles 不是 ld 选项。 它解析为 ld -n -o startfiles

我尝试了您的命令,但它们没有创建名为 go 的文件,而是创建了名为 startfiles 的可执行文件。

$ cat > go.s
  paste + control-d
$ as -o go.o go.s
$ ld -o go -s -nostartfiles go.o
$ ll go
ls: cannot access 'go': No such file or directory
$ ll -clrt
-rw-r--r-- 1 peter peter  193 May 13 11:33 go.s
-rw-r--r-- 1 peter peter  704 May 13 11:33 go.o
-rwxr-xr-x 1 peter peter  344 May 13 11:33 startfiles

您的 go 必须是从您的 ld -s -nostartfiles -o go go.o 中遗留下来的,其中 -o go 是命令行上 -o 的最后一个实例,未被 -o startfiles 覆盖.


使二进制文件变小的选项是 ld -n

-n
--nmagic
关闭部分的页面对齐,并禁用针对共享库的链接。如果输出格式支持 Unix 样式的幻数,请标记 输出为“NMAGIC”。

相关:Minimal executable size now 10x larger after linking than 2 years ago,for tiny programs?


作为 GCC 选项,-nostartfiles 告诉 gcc 前端 not 链接 crt*.o 文件。如果您手动运行 ld,则只需省略提及它们。无需告诉 ld 您未链接的内容,ld 命令本身不会链接任何未明确告知的内容。链接 CRT 文件和 libc / libgcc 是 gcc 默认值,而不是 ld

$ gcc -s -nostdlib -static  -Wl,--nmagic,--build-id=none go.s
$ ll a.out 
-rwxr-xr-x 1 peter peter 344 May 13 12:35 a.out

您希望 -nostdlib 省略库以及 CRT 启动文件。
-nostartfiles 只是 -nostdlib 功能的一个子集。
(虽然在静态链接时,ld 不会从 libc.alibgcc.a 中提取任何代码,因为您的文件没有引用任何外部符号。因此您实际上仍然获得相同的 344 字节文件使用 -nostartfiles 作为 -nostdlib。但 -nostdlib 更准确地复制您的手动 ld 命令,而不传递任何额外的文件。)

在默认 -static 的 GCC 上,您需要 -pie 才能不动态链接。 (这也意味着 -no-pie-static-pie 不会默认启用。)
如果您让 GCC 尝试动态链接 PIE 可执行文件(即使没有共享库),--nmagic 会因错误:PHDR 段未包含在 LOAD 段中而失败。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。