为什么我的 hello world 二进制文件大部分为零?

2023-12-09

我已经编译了

#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 is.

那为什么全是零呢?


因为对齐。

XNU 强制映射二进制文件部分的每个段都与平台的页面大小对齐。在 x86_64 上,这是 0x1000 字节,在 arm64 上,这是 0x4000 字节(即使硬件支持 0x1000)。如果某些段的数据必须与某个偏移量对齐,那么就必须有某物在填补两者之间空白的文件中 - 通常为零。

现在,如果您的二进制文件是 48KB,那么它的段可能如下所示:

LC 00: LC_SEGMENT_64  Mem: 0x000000000-0x100000000  File: Not Mapped    ---/--- __PAGEZERO
LC 01: LC_SEGMENT_64  Mem: 0x100000000-0x100004000  File: 0x0-0x4000    r-x/r-x __TEXT
LC 02: LC_SEGMENT_64  Mem: 0x100004000-0x100008000  File: 0x4000-0x8000 rw-/rw- __DATA_CONST
LC 03: LC_SEGMENT_64  Mem: 0x100008000-0x10000c000  File: 0x8000-0xc000 rw-/rw- __DATA
LC 04: LC_SEGMENT_64  Mem: 0x10000c000-0x100010000  File: 0xc000-0xc110 r--/r-- __LINKEDIT

对于 0x4000 的对齐,这已经是最小布局。但如果你使用 Intel,你可以通过传递强制链接器使用 0x1000-Wl,-segalign,0x1000给编译器。这应该会生成一个只有 12KB 左右的二进制文件:

LC 00: LC_SEGMENT_64  Mem: 0x000000000-0x100000000  File: Not Mapped    ---/--- __PAGEZERO
LC 01: LC_SEGMENT_64  Mem: 0x100000000-0x100001000  File: 0x0-0x1000    r-x/r-x __TEXT
LC 02: LC_SEGMENT_64  Mem: 0x100001000-0x100002000  File: 0x1000-0x2000 rw-/rw- __DATA_CONST
LC 03: LC_SEGMENT_64  Mem: 0x100002000-0x100003000  File: 0x2000-0x3000 rw-/rw- __DATA
LC 04: LC_SEGMENT_64  Mem: 0x100003000-0x100004000  File: 0x3000-0x3110 r--/r-- __LINKEDIT

如果您想进一步优化二进制文件,则需要删除段。通过导入和链接,您真正可以摆脱的唯一一个是__DATA_CONST,您可以通过针对 macOS Mojave(或更早版本)使用-mmacosx-version-min=10.14。这将使您剩下 8KB 多一点的空间:

LC 00: LC_SEGMENT_64  Mem: 0x000000000-0x100000000  File: Not Mapped    ---/--- __PAGEZERO
LC 01: LC_SEGMENT_64  Mem: 0x100000000-0x100001000  File: 0x0-0x1000    r-x/r-x __TEXT
LC 02: LC_SEGMENT_64  Mem: 0x100001000-0x100002000  File: 0x1000-0x2000 rw-/rw- __DATA
LC 03: LC_SEGMENT_64  Mem: 0x100002000-0x100003000  File: 0x2000-0x20f0 r--/r-- __LINKEDIT

如果您追求尽可能最小的可执行文件,您可以进一步放弃__DATA甚至可能__LINKEDIT,但是您必须大幅更改代码以仅发出原始系统调用,而不使用动态链接器等。

对于任何现实世界的应用程序,我还想说这些零实际上并不重要。给定四个映射段,它们使用的空间永远不会超过 48KB。二进制越大,零所占的百分比就越小。

至于分布,答案很明显:xz.
压缩上述二进制文件会产生:

  • 48KB 二进制文件为 776 字节。
  • 12KB 二进制文件为 736 字节。
  • 8KB 二进制文件为 684 字节。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我的 hello world 二进制文件大部分为零? 的相关文章

随机推荐

  • 淘汰赛可排序绑定顺序

    这是一个问题的后续 KnockoutJS 可按字段对 observableArray 进行排序并进行条件排序 我还有两件事正在努力实现 首先 当嵌套列表项被拖动到另一个列表时 父级为空 我想删除父级 我通过创建一个 afterMove 函数
  • 何时使用MyISAM和InnoDB? [复制]

    这个问题在这里已经有答案了 MyISAM 的设计理念是 您的数据库被查询的次数远远多于其被更新的次数 因此它执行非常快的读取操作 如果您的读写 插入 更新 比率低于 15 那么最好使用 MyISAM InnoDB 使用行级锁定 具有提交 回
  • 嵌套的 For-Each 会变平吗?

    有一个对象数组 其中每个对象都有一个对象集合 其中每个对象都有一个字符串属性 当我进行嵌套迭代时 TheArray TheCollection TheProperty 看起来我最终得到的不是字符串数组的数组 而是一维字符串数组 这是设计使然
  • 正则表达式匹配最后一个字符

    我有以下几行 data text javascript base64 Ly8gSGVyZdsdsd 5 data text javascript base64 Ly8gSGVyZdsdsd 2 data text javascript ba
  • Django / vBulletin 单点登录

    在同一域上为 Django 项目和 vBulletin 板进行单点登录 SSO 的最简单方法是什么 我有一个现有的 vBulletin 用户数据库 我研究过 Django 的远程用户后端和 vBulletin 的vBSSO但我还没有找到完整
  • java中带单引号的SQL查询

    我有一个想要在 java 中运行的查询 SELECT md5 CONCAT md5 clear password salt 它让我的应用程序连接并使用与我的论坛相同的用户名 密码 它的工作但是当salt包含字符 它给出一个错误 You ha
  • 在 Flutter 中更改主图像尺寸而不触及占位符图像大小

    我有一个关于 flutter 中的图像和预加载的小问题 如何在不改变占位符大小的情况下更改图像覆盖的适合值 Widget primaryVideoImg img return Flex direction Axis horizontal c
  • 确定作为 n 的函数执行递增变量计数的语句的频率

    好吧 我是分析算法的新手 非常感谢任何可以分享如何解决此问题的有用提示 我试图确定 count 作为 n 的函数增加了多少次 我已经在 ide 中运行它 对于值 1 7 输出为 1 3 6 10 15 21 28 我只是不确定如何将其写为
  • 如何保存python IDLE的自定义首选项?

    我在不同的位置有几台计算机 虽然我没有在 IDLE 中编码 但它始终在后台运行 用于小型测试 调试和研究任务 我在家里配置了 IDLE 自定义突出显示 按键设置等 将我的设置保存到外部文件中并将这些设置安装到我正在使用的任何计算机上会非常方
  • 如何访问脚本组件内的 ssis 包变量

    如何访问我在数据流 gt 脚本组件 gt 我的 C 脚本和 SSIS 包中使用的 C 代码中的变量 我已经尝试过 但也不起作用 IDTSVariables100 varCollection null this VariableDispens
  • 如何使用printf显示off_t、nlink_t、size_t等特殊类型?

    在我的程序中 我统计他们想要的文件并将数据发送过去 统计数据的字段struct都是特殊类型 struct stat dev t st dev ID of device containing file ino t st ino inode n
  • python,从(1,n)中随机选择#k个数字,不包括列表中的数字

    对于给定的 except list 3 5 8 n 30 k 5 我想在 1 到 30 之间选择 5 k 个随机数 但我不应该在排除列表中选择数字 假设 except list n 可能很大 当不需要排除时 很容易得到k个随机样本 rand
  • CSS 链接边框样式不适用于 a:visited

    问题在于链接边框样式 我可以在悬停时更改它 但边框 visited不起作用 这是我所拥有的示例 a link color 536DFE text decoration none border bottom dashed 1px transi
  • WCF WSDL + 可空属性

    我有一个 WCF 服务扁平化 WSDL 另一端的消费者告诉我 nillable true 属性正在将它们连接起来 我尝试在服务合同中设置 EmitDefaultValue false 但我没有注意到行为有任何变化 诚然 我以前从未深入研究过
  • 如何在 UICollectionViewCell 中设置 UILabel

    我有一个带有 UIViewController 的应用程序 其中包含 UICollectionView IBOutlet UICollectionView 中的单元格是 MyCustomCell 并使用此方法设置其 UILabel void
  • .NET 的 RSS 解析器 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 对于 NET 中的 RSS
  • 如何使用 Three.js 绘制平行线?

    我对矩阵变换的概念很陌生 我尝试在正交方向上偏移一条线 我想到的是 line translate offsetPixels new THREE Vector3 1 1 0 它沿着向量中定义的轴平移一条线 所以我的问题是如何定义向量中的轴以获
  • 在不同端点上实现多个协定的服务类的 WCF 配置

    我有一个MyService类实现IService1 and IService2接口 我想在两个不同的端点上公开这两个合约 例如 IService1暴露于 Service S1 IService2暴露于 Service S2 这样的配置会是什
  • 如何在vb.net中解码url

    此行表示服务器未声明 Dim DecodedString As String server UrlDecode context Request Form DeckName 我在顶部导入了 system web 似乎无法弄清楚为什么它不起作用
  • 为什么我的 hello world 二进制文件大部分为零?

    我已经编译了 include