gcc:通过 gcc 将 -nostartfiles 传递给 ld 以获得最小二进制大小
gcc: passing -nostartfiles to ld via gcc for minimal binary size
考虑以下 64 位的 gas(GNU 汇编程序)文件 linux
go.s
.global _start
.text
_start:
mov , %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
link 命令。
嗯……
所以任务:显示给出最小大小的单行 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
在 /usr/lib/gcc/x86_64-linux-gnu/8/collect2
命令(上面)中手动添加 -nostartfiles
(直接在 collect2
之后)给出 520 字节的大小。
手动添加 -nostartfiles
(直接在 collect2
之后)并删除 --build-id
得到 344 字节的大小。我们可以看到 here,-Wl,--build-id=none
应该删除构建 ID。
但是如何指示 gcc 将 -nostartfiles
传递给 ld
或 collect2
?
回复 Jester 的评论:
正在执行以下操作 (-Wl,-nostartfiles
):
gcc -Wl,-nostartfiles,--build-id=none -v -xassembler -s -static -nostartfiles -o go go.s
会在collect2
命令的末尾添加-nostartfiles
太远,结果输出二进制go
不是甚至创造。如何给出命令,以便 -nostartfiles
在 collect2 ...
命令中更早出现:我知道它有效,如果我手动将 -nostartfiles
构造为标志 开头.
正在寻找here,有人声称-Wl,-nostartfiles
不会被正确处理。但是,如果我只使用 gcc -nostartflags ...
,那么它不会传递给 linker:Maby,这是 gcc 中的错误??
也许所有的代码都被优化掉了……什么都没有留下??参见 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
Turn off page alignment of sections, and disable linking against shared libraries. If the output format supports Unix style magic numbers, mark the
output as "NMAGIC".
相关:Minimal executable size now 10x larger after linking than 2 years ago, for tiny programs?
作为 GCC 选项,-nostartfiles
告诉 gcc
前端 而不是 到 link crt*.o
文件。如果您是 运行 ld
手动,则只需省略提及它们。没有必要告诉 ld
你没有 link 什么,ld
命令本身不会 link 任何它没有明确告诉的事情。链接 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
的一部分。
(虽然当静态 linking 时,ld
不会从 libc.a
或 libgcc.a
中提取任何代码,因为你的文件没有引用任何外部符号。所以你实际上仍然使用 -nostartfiles
获得与 -nostdlib
相同的 344 字节文件。但是 -nostdlib
更准确地复制您的手动 ld
命令,不传递任何额外的文件。)
您需要 -static
才能在 -pie
是默认值的 GCC 上动态地 link。 (这也意味着 -no-pie
;默认情况下不会启用 -static-pie
。)
--nmagic
失败并显示 错误:如果您让 GCC 尝试动态 link PIE 可执行文件(即使没有共享库),PHDR 段未被 LOAD 段覆盖。
考虑以下 64 位的 gas(GNU 汇编程序)文件 linux
go.s
.global _start
.text
_start:
mov , %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
link 命令。
嗯……
所以任务:显示给出最小大小的单行 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
在 /usr/lib/gcc/x86_64-linux-gnu/8/collect2
命令(上面)中手动添加 -nostartfiles
(直接在 collect2
之后)给出 520 字节的大小。
手动添加 -nostartfiles
(直接在 collect2
之后)并删除 --build-id
得到 344 字节的大小。我们可以看到 here,-Wl,--build-id=none
应该删除构建 ID。
但是如何指示 gcc 将 -nostartfiles
传递给 ld
或 collect2
?
回复 Jester 的评论:
正在执行以下操作 (-Wl,-nostartfiles
):
gcc -Wl,-nostartfiles,--build-id=none -v -xassembler -s -static -nostartfiles -o go go.s
会在collect2
命令的末尾添加-nostartfiles
太远,结果输出二进制go
不是甚至创造。如何给出命令,以便 -nostartfiles
在 collect2 ...
命令中更早出现:我知道它有效,如果我手动将 -nostartfiles
构造为标志 开头.
正在寻找here,有人声称-Wl,-nostartfiles
不会被正确处理。但是,如果我只使用 gcc -nostartflags ...
,那么它不会传递给 linker:Maby,这是 gcc 中的错误??
也许所有的代码都被优化掉了……什么都没有留下??参见 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
Turn off page alignment of sections, and disable linking against shared libraries. If the output format supports Unix style magic numbers, mark the output as "NMAGIC".
相关:Minimal executable size now 10x larger after linking than 2 years ago, for tiny programs?
作为 GCC 选项,-nostartfiles
告诉 gcc
前端 而不是 到 link crt*.o
文件。如果您是 运行 ld
手动,则只需省略提及它们。没有必要告诉 ld
你没有 link 什么,ld
命令本身不会 link 任何它没有明确告诉的事情。链接 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
的一部分。
(虽然当静态 linking 时,ld
不会从 libc.a
或 libgcc.a
中提取任何代码,因为你的文件没有引用任何外部符号。所以你实际上仍然使用 -nostartfiles
获得与 -nostdlib
相同的 344 字节文件。但是 -nostdlib
更准确地复制您的手动 ld
命令,不传递任何额外的文件。)
您需要 -static
才能在 -pie
是默认值的 GCC 上动态地 link。 (这也意味着 -no-pie
;默认情况下不会启用 -static-pie
。)
--nmagic
失败并显示 错误:如果您让 GCC 尝试动态 link PIE 可执行文件(即使没有共享库),PHDR 段未被 LOAD 段覆盖。