为什么/ usr / bin / test 4kib小于/ usr / bin / [?

2021-04-06 11:13:14

$ ls -lh / usr / bin / {test,[} - rwxr-xr-x 1根目录59k 9月5日2019年9月5日' / usr / bin / [' -rwxr-xr-x 1根root 55K 9月5日2019年9月3日/ usr / bin / test

[和测试应该是彼此的别名,但他们的GNU Coreutils二进制文件之间存在4kib差异。为什么?

首先,对于任何人惊讶:是的,有一个/ usr / bin / [。我在这个主题上有一个以前的帖子,但这是一个快速回顾:

如果[-e / etc / passwd]编写;然后..那括号不是shell语法,但只是一个常规命令,名称有趣。它是由/ usr / bin / [,或(更可能)shell内置的服务。这解释了很多令人惊讶的行为,例如为什么它是惊人的空间敏感:[1 = 2]不比LS-L / TMP更有效。

无论如何,为什么有大小差异?我们可以比较Objdump输出来查看数据的位置。这是objdump -h / usr / bin / [:

大小offset15的.text 00006e82 0000000000002640 0000000000002640 00002640 2 ** 416调用.fini 0000000D 00000000000094c4 00000000000094c4 000094c4 2 ** 217 .RODATA 00001e4c 000000000000a000 000000000000a000 0000a000 2 ** 5

15的.text 000068a2 0000000000002640 0000000000002640 00002640 2 ** 416调用.fini 0000000D 0000000000008ee4 0000000000008ee4 00008ee4 2 ** 217 .RODATA 00001aec 0000000000009000 0000000000009000 00009000 2 ** 5

我们可以看到.text段(编译的可执行代码) - 是1504字节越大,而.rodata(常量值和字符串)是864字节更大。

最重要的是,提高.Text段的大小导致它从8000s到9000s,交叉0x1000(4096)页面尺寸边界,因此将所有其他段转化为4096字节。这是我们看到的大小差异。

[和测试之间的唯一标称差异是[需要a]作为最终论点。检查这将是一个非常小的代码量,所以那些〜1500字节用于什么?

由于它很难检查被剥离的二进制文件,因此我构建了自己的Coreutils副本,并将每个函数与每个函数进行比较:

$ diff -u<(nm -s - 仅限于仅SRC / [|切割'' -F 2-)<(nm -s-dedefined-only src / test | Cut -d'' -f 2 - )--- / dev / fd / 63 2021-02-02 20:21:35.337942508 -0800 +++ / dev / fd / 62 2021-02- 02 20:21:21 0000000000000022Ťlocale_charset 0000000000000014Ť__lstat0000000000000014吨LSTAT-0000000000000188 t主+ 00000000000000d1 t主000000000000000bŤmake_timespec 0000000000000004 d NSLOTS0000000000000022吨one_argument @@ -142,16 +141,10 @@ 0000000000000032Ťumaxtostr0000000000000013吨unary_advance 00000000000004e5吨unary_operator-00000000000003d2Ť USAGE + 0000000000000428 T 000000000000000D2D T VASNPRINTF 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000AE T VERSION_ETC-00000000000000000000000000000000000000000000000000AE T VERSION_ETC-000000000000AB T Version_etc_ar-000000000000 00042bŤversion_etc_arn-000000000000002fřversion_etc_copyright-000000000000007aŤversion_etc_va 000000000000001cřwide_null_string.2840 0000000000000078Ťx2nrealloc 000000000000000eŤx2realloc

这些是260行相当详细阐述,国际化的,格式化构成输出的数据。它们一起考虑BC<< " IBase = 16; 7a + 2f + 42b + 18 + ab + 8 + 99" = 1592字节。

这是什么意思?简单的。这是我们支付额外的4KB:

$ / usr / bin / [--version [(gnu coreutils)8.30copyright(c)2018 Free Software Foundation,Inc.License GPLV3 +:GNU GPL版本3或更高版本3或更高版本< https://gnu.org/licenses/gpl。 HTML>。这是免费软件:您可以自由地更改和重新分发。没有保修,在法律允许的范围内。由Kevin Braunsdorf和Matthew Bradburn写道。 [ - version缺少最终],因此调用无效,因此定义了结果。 GNU可以自由地让它输出版本信息。 同时,/ usr / bin / test --version是一个有效的调用,并且POSIX要求它只是在第一个参数(--version)是非空字符串时返回成功。 注意:[授予--help和--version选项,但测试不为。最终处理每个其他非空字符串的每一个。 (练习:在Help和-version时,在POSIX的情况下,有什么影响?)