我整理了
#include <stdio.h>
int main() {
printf("Hello world");
return 0;
}
字符串
在Mac上,它的大小是48k。然而,当我用xxd
查看二进制文件时,大部分看起来像这样:
...
0000b990: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000b9a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000b9b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
...
型
为什么会这样呢?otool
告诉我:
otool -L hello
hello:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.0.0)
型
所以它再次被动态链接到libSystem中,它在printf
中。
那为什么全是零
1条答案
按热度按时间cfh9epnr1#
是因为对齐。
XNU强制Map二进制部分的每个段与平台的页面大小对齐。在x86_64上,为0x 1000字节,在arm 64上,为0x 4000字节(即使在硬件将支持0x 1000的情况下)。并且如果某些段的数据必须与某个偏移对齐,那么在文件中必须有一些东西来填补中间差距--通常是零。
现在,如果您的二进制文件是48 KB,那么它的段可能看起来像这样:
字符串
对于0x 4000的对齐,这已经是最小的布局。但是如果你使用的是Intel,你可以通过将
-Wl,-segalign,0x1000
传递给编译器来强制链接器使用0x 1000。这应该会产生一个只有大约12 KB的二进制文件:型
如果你想进一步优化你的二进制文件,你需要去掉代码段。通过导入和链接,你唯一能去掉的就是
__DATA_CONST
,你可以通过在macOS莫哈韦(或更早的版本)中使用-mmacosx-version-min=10.14
来实现。这将给你留下8 KB多一点的空间:型
如果您正在努力实现尽可能小的可执行文件,则可以进一步放弃
__DATA
,甚至可能放弃__LINKEDIT
,但您必须对代码进行实质性的更改,以便仅发出原始syscalls,而不使用动态链接器等。对于任何实际应用程序,我还要说这些零实际上并不重要。给定四个Map段,它们永远不会占用超过48 KB的空间。二进制文件越大,零所占的百分比就越小。
至于分布,答案显而易见:
xz
。使用压缩上述二进制档,会产生: