如何解决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
传递给 ld
或 collect2
?
回应小丑的评论:
执行以下操作 (-Wl,-nostartfiles
):
gcc -Wl,-nostartfiles,--build-id=none -v -xassembler -s -static -nostartfiles -o go go.s
将在 -nostartfiles
命令的末尾添加 collect2
,结果甚至不会创建输出二进制文件 go
。如何给出命令,以便 -nostartfiles
在 collect2 ...
命令中更早出现:我知道它有效,如果我在开始时手动构造 -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.a
或 libgcc.a
中提取任何代码,因为您的文件没有引用任何外部符号。因此您实际上仍然获得相同的 344 字节文件使用 -nostartfiles
作为 -nostdlib
。但 -nostdlib
更准确地复制您的手动 ld
命令,而不传递任何额外的文件。)
在默认 -static
的 GCC 上,您需要 -pie
才能不动态链接。 (这也意味着 -no-pie
;-static-pie
不会默认启用。)
如果您让 GCC 尝试动态链接 PIE 可执行文件(即使没有共享库),--nmagic
会因错误:PHDR 段未包含在 LOAD 段中而失败。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。