いくつかの一般的なコマンド(read
など)が実際にはBashビルトインであることがわかりました(そして、プロンプトで実行すると、実際にはビルトインに転送する2行のシェルスクリプトが実行されています)。同じことがtrue
とfalse
にも当てはまるかどうかを確認します。
まあ、それらは間違いなくバイナリです。
sh-4.2$ which true
/usr/bin/true
sh-4.2$ which false
/usr/bin/false
sh-4.2$ file /usr/bin/true
/usr/bin/true: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=2697339d3c19235
06e10af65aa3120b12295277e, stripped
sh-4.2$ file /usr/bin/false
/usr/bin/false: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=b160fa513fcc13
537d7293f05e40444fe5843640, stripped
sh-4.2$
しかし、私が一番驚いたのはそのサイズです。 true
は基本的にexit 0
およびfalse
はexit 1
。
sh-4.2$ true
sh-4.2$ echo $?
0
sh-4.2$ false
sh-4.2$ echo $?
1
sh-4.2$
しかし、驚いたことに、両方のファイルのサイズが28KBを超えています。
sh-4.2$ stat /usr/bin/true
File: '/usr/bin/true'
Size: 28920 Blocks: 64 IO Block: 4096 regular file
Device: fd2ch/64812d Inode: 530320 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2018-01-25 19:46:32.703463708 +0000
Modify: 2016-06-30 09:44:27.000000000 +0100
Change: 2017-12-22 09:43:17.447563336 +0000
Birth: -
sh-4.2$ stat /usr/bin/false
File: '/usr/bin/false'
Size: 28920 Blocks: 64 IO Block: 4096 regular file
Device: fd2ch/64812d Inode: 530697 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2018-01-25 20:06:27.210764704 +0000
Modify: 2016-06-30 09:44:27.000000000 +0100
Change: 2017-12-22 09:43:18.148561245 +0000
Birth: -
sh-4.2$
だから私の質問は、なぜ彼らはそんなに大きいのですか?戻りコード以外の実行可能ファイルには何がありますか?
PS:私はRHEL 7.4を使用しています
以前は、シェルの_/bin/true
_および_/bin/false
_は実際にはスクリプトでした。
たとえば、PDP/11 Unix System 7の場合:
_$ ls -la /bin/true /bin/false
-rwxr-xr-x 1 bin 7 Jun 8 1979 /bin/false
-rwxr-xr-x 1 bin 0 Jun 8 1979 /bin/true
$
$ cat /bin/false
exit 1
$
$ cat /bin/true
$
_
現在、少なくともbash
では、true
およびfalse
コマンドがシェル組み込みコマンドとして実装されています。したがって、false
コマンドラインおよびシェルスクリプト内でtrue
およびbash
ディレクティブを使用する場合、デフォルトでは実行可能なバイナリファイルは呼び出されません。
bash
sourceから、_builtins/mkbuiltins.c
_:
char * posix_builtins [] = { "エイリアス"、 "bg"、 "cd"、 "コマンド"、 "** false **"、 "fc"、 "fg"、 " getopts "、" jobs "、 " kill "、" newgrp "、" pwd "、" read "、" ** true ** "、" umask "、" unalias "、" wait "、 (char *)NULL };
@meuhのコメントによると:
_$ command -V true false
true is a Shell builtin
false is a Shell builtin
_
したがって、true
およびfalse
の実行可能ファイルは、主に他のプログラムから呼び出されるのために存在していると言えます。
これからは、Debian 9/64ビットのcoreutils
packageからの_/bin/true
_バイナリに焦点を当てます。 (_/usr/bin/true
_ RedHatの実行。RedHatとDebianは、coreutils
パッケージの両方を使用し、後者のコンパイル済みバージョンを分析して、手元に置いています)。
ソースファイル_false.c
_で確認できるように、_/bin/false
_は_/bin/true
_と(ほぼ)同じソースコードでコンパイルされ、代わりにEXIT_FAILURE(1)を返すだけなので、この答えは両方のバイナリに適用されます。
_#define EXIT_STATUS EXIT_FAILURE
#include "true.c"
_
同じサイズの両方の実行可能ファイルでも確認できるため、
_$ ls -l /bin/true /bin/false
-rwxr-xr-x 1 root root 31464 Feb 22 2017 /bin/false
-rwxr-xr-x 1 root root 31464 Feb 22 2017 /bin/true
_
悲しいかな、_why are true and false so large?
_への直接的な質問はおそらくあり得ます。なぜなら、彼らの最高のパフォーマンスを気にするという差し迫った理由がないからです。これらは、bash
のパフォーマンスに不可欠ではなく、bash
(スクリプト)で使用されなくなりました。
同様のコメントがそれらのサイズに適用されます。今日私たちが持っている種類のハードウェアでは26KBは重要ではありません。 false
を使用するディストリビューションで2回デプロイされるだけなので、スペースは通常のサーバー/デスクトップにとってもはやプレミアムではありません。また、true
とcoreutils
に同じバイナリを使用することさえもはや不要です。
しかし、本当の質問の精神で焦点を合わせると、なぜ単純で小さいはずのものが非常に大きくなるのでしょうか。
_/bin/true
_のセクションの実際の分布は、これらのグラフが示すとおりです。メインコードとデータは、26KBのバイナリのうち約3KBになり、_/bin/true
_のサイズの12%になります。
true
ユーティリティは、何年にもわたって実際に粗末なコードを取得しました。最も顕著なのは、_--version
_および_--help
_の標準サポートです。
ただし、それが非常に大きいことの(唯一の)主な理由ではなく、動的にリンクされている(共有ライブラリを使用)一方で、静的ライブラリとしてリンクされているcoreutils
バイナリによって一般的に使用される汎用ライブラリの一部を持っていること。 elf
実行可能ファイルを構築するためのメタダも、バイナリの重要な部分を占めており、今日の標準では比較的小さいファイルです。
残りの答えは、_/bin/true
_実行可能バイナリファイルの構成を詳細に示す次のグラフを作成する方法と、その結論に至る方法を説明するためのものです。
@Maksが言うように、バイナリはCからコンパイルされました。私のコメントにもあるように、coreutilsからのものであることも確認されています。作成者git https://github.com/wertarbyte/coreutils/blob/master/src/true.c を直接指します。代わりに、GNU git @Maks(同じソース、さまざまなリポジトリ-coreutils
ライブラリの完全なソースがあるため、このリポジトリが選択されました)
ここで、_/bin/true
_ binaryのさまざまなビルディングブロックを見ることができます(Debian 9-coreutils
からの64ビット):
_$ file /bin/true
/bin/true: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9ae82394864538fa7b23b7f87b259ea2a20889c4, stripped
$ size /bin/true
text data bss dec hex filename
24583 1160 416 26159 662f true
_
それらの:
24KBのうち、約1KBは58の外部関数を修正するためのものです。
それでも、残りのコード用に約23KBが残っています。実際のメインファイル-main()+ usage()コードがコンパイルされた約1KBであることを以下に示し、他の22KBが何に使用されているかを説明します。
_readelf -S true
_を使用してバイナリをさらにドリルダウンすると、バイナリは26159バイトですが、実際のコンパイル済みコードは13017バイトであり、残りはさまざまなデータ/初期化コードです。
ただし、_true.c
_はすべてではなく、そのファイルだけの場合、13KBはかなり過剰に見えます。エルフの_objdump -T true
_で見られる外部関数にリストされていないmain()
で呼び出された関数を見ることができます。次の場所にある関数:
main()
で外部的にリンクされていない追加の関数は次のとおりです。
したがって、私の最初の疑いは部分的に正しかったですが、ライブラリが動的ライブラリを使用している間、_/bin/true
_バイナリは大きいです---some静的ライブラリが含まれているため*原因)。
Cコードをコンパイルすることは、通常、そのようなスペースを考慮に入れないためにthat非効率的ではないため、私の最初の疑いは何かがおかしかったです。
バイナリのサイズのほぼ90%である追加のスペースは、実際には追加のライブラリ/ elfメタデータです。
バイナリを逆アセンブル/逆コンパイルするためにホッパーを使用して関数の場所を理解している間、true.c/usage()関数のコンパイル済みバイナリコードは実際には833バイトであり、true.c/main()関数は225バイトです。バイト、これはおよそ1KBよりわずかに少ないです。静的ライブラリに埋め込まれているバージョン関数のロジックは約1KBです。
実際にコンパイルされたmain()+ usage()+ version()+ strings + varsは、約3KBから3.5KBまでしか使用していません。
確かに皮肉なことですが、そのような小さくて控えめなユーティリティは、上で説明した理由によりサイズが大きくなっています。
関連質問: Linuxバイナリが何をしているかを理解する
_true.c
_ main()と問題のある関数呼び出し:
_int
main (int argc, char **argv)
{
/* Recognize --help or --version only if it's the only command-line
argument. */
if (argc == 2)
{
initialize_main (&argc, &argv);
set_program_name (argv[0]); <-----------
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout); <-----
if (STREQ (argv[1], "--help"))
usage (EXIT_STATUS);
if (STREQ (argv[1], "--version"))
version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS, <------
(char *) NULL);
}
exit (EXIT_STATUS);
}
_
バイナリのさまざまなセクションの小数サイズ:
_$ size -A -t true
true :
section size addr
.interp 28 568
.note.ABI-tag 32 596
.note.gnu.build-id 36 628
.gnu.hash 60 664
.dynsym 1416 728
.dynstr 676 2144
.gnu.version 118 2820
.gnu.version_r 96 2944
.rela.dyn 624 3040
.rela.plt 1104 3664
.init 23 4768
.plt 752 4800
.plt.got 8 5552
.text 13017 5568
.fini 9 18588
.rodata 3104 18624
.eh_frame_hdr 572 21728
.eh_frame 2908 22304
.init_array 8 2125160
.fini_array 8 2125168
.jcr 8 2125176
.data.rel.ro 88 2125184
.dynamic 480 2125272
.got 48 2125752
.got.plt 392 2125824
.data 128 2126240
.bss 416 2126368
.gnu_debuglink 52 0
Total 26211
_
_readelf -S true
_の出力
_$ readelf -S true
There are 30 section headers, starting at offset 0x7368:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000000254 00000254
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.build-i NOTE 0000000000000274 00000274
0000000000000024 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000298 00000298
000000000000003c 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 00000000000002d8 000002d8
0000000000000588 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000000860 00000860
00000000000002a4 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000000b04 00000b04
0000000000000076 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000000b80 00000b80
0000000000000060 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 0000000000000be0 00000be0
0000000000000270 0000000000000018 A 5 0 8
[10] .rela.plt RELA 0000000000000e50 00000e50
0000000000000450 0000000000000018 AI 5 25 8
[11] .init PROGBITS 00000000000012a0 000012a0
0000000000000017 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 00000000000012c0 000012c0
00000000000002f0 0000000000000010 AX 0 0 16
[13] .plt.got PROGBITS 00000000000015b0 000015b0
0000000000000008 0000000000000000 AX 0 0 8
[14] .text PROGBITS 00000000000015c0 000015c0
00000000000032d9 0000000000000000 AX 0 0 16
[15] .fini PROGBITS 000000000000489c 0000489c
0000000000000009 0000000000000000 AX 0 0 4
[16] .rodata PROGBITS 00000000000048c0 000048c0
0000000000000c20 0000000000000000 A 0 0 32
[17] .eh_frame_hdr PROGBITS 00000000000054e0 000054e0
000000000000023c 0000000000000000 A 0 0 4
[18] .eh_frame PROGBITS 0000000000005720 00005720
0000000000000b5c 0000000000000000 A 0 0 8
[19] .init_array INIT_ARRAY 0000000000206d68 00006d68
0000000000000008 0000000000000008 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000000206d70 00006d70
0000000000000008 0000000000000008 WA 0 0 8
[21] .jcr PROGBITS 0000000000206d78 00006d78
0000000000000008 0000000000000000 WA 0 0 8
[22] .data.rel.ro PROGBITS 0000000000206d80 00006d80
0000000000000058 0000000000000000 WA 0 0 32
[23] .dynamic DYNAMIC 0000000000206dd8 00006dd8
00000000000001e0 0000000000000010 WA 6 0 8
[24] .got PROGBITS 0000000000206fb8 00006fb8
0000000000000030 0000000000000008 WA 0 0 8
[25] .got.plt PROGBITS 0000000000207000 00007000
0000000000000188 0000000000000008 WA 0 0 8
[26] .data PROGBITS 00000000002071a0 000071a0
0000000000000080 0000000000000000 WA 0 0 32
[27] .bss NOBITS 0000000000207220 00007220
00000000000001a0 0000000000000000 WA 0 0 32
[28] .gnu_debuglink PROGBITS 0000000000000000 00007220
0000000000000034 0000000000000000 0 0 1
[29] .shstrtab STRTAB 0000000000000000 00007254
000000000000010f 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
_
_objdump -T true
_の出力(実行時に動的にリンクされる外部関数)
_$ objdump -T true
true: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __uflow
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 getenv
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 free
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 abort
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __errno_location
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strncmp
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 _exit
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __fpending
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 textdomain
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fclose
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 bindtextdomain
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 dcgettext
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __ctype_get_mb_cur_max
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strlen
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.4 __stack_chk_fail
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 mbrtowc
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strrchr
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 lseek
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 memset
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fscanf
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 close
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 memcmp
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fputs_unlocked
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 calloc
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strcmp
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fileno
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 malloc
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fflush
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 nl_langinfo
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 ungetc
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __freading
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realloc
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fdopen
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 setlocale
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3.4 __printf_chk
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 error
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 open
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fseeko
0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_atexit
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 exit
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fwrite
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3.4 __fprintf_chk
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 mbsinit
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 iswprint
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3 __ctype_b_loc
0000000000207228 g DO .bss 0000000000000008 GLIBC_2.2.5 stdout
0000000000207220 g DO .bss 0000000000000008 GLIBC_2.2.5 __progname
0000000000207230 w DO .bss 0000000000000008 GLIBC_2.2.5 program_invocation_name
0000000000207230 g DO .bss 0000000000000008 GLIBC_2.2.5 __progname_full
0000000000207220 w DO .bss 0000000000000008 GLIBC_2.2.5 program_invocation_short_name
0000000000207240 g DO .bss 0000000000000008 GLIBC_2.2.5 stderr
_
実装はおそらくGNU coreutilsから行われます。これらのバイナリはCからコンパイルされます。デフォルトのサイズより小さくするための特別な努力は行われていません。
true
の簡単な実装を自分でコンパイルしてみると、サイズが数KBになっていることに気付くでしょう。たとえば、私のシステムでは:
$ echo 'int main() { return 0; }' | gcc -xc - -o true
$ wc -c true
8136 true
もちろん、バイナリはさらに大きくなります。これは、コマンドライン引数もサポートしているためです。 /usr/bin/true --help
または/usr/bin/true --version
を実行してみてください。
バイナリには、文字列データに加えて、コマンドラインフラグなどを解析するロジックが含まれています。これにより、合計で約20 KBのコードになります。
参考までに、ここにソースコードがあります: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/true.c
それらをコア機能に分解し、アセンブラで書き込むと、はるかに小さなバイナリが生成されます。
オリジナルのtrue/falseバイナリはCで記述されており、その性質上、さまざまなライブラリ+シンボル参照を取り込みます。 readelf -a /bin/true
を実行すると、これはかなり顕著になります。
削除されたELF静的実行可能ファイルの352バイト(コードサイズのasmを最適化することで数バイトを節約する余地がある)。
$ more true.asm false.asm
::::::::::::::
true.asm
::::::::::::::
global _start
_start:
mov ebx,0
mov eax,1 ; SYS_exit from asm/unistd_32.h
int 0x80 ; The 32-bit ABI is supported in 64-bit code, in kernels compiled with IA-32 emulation
::::::::::::::
false.asm
::::::::::::::
global _start
_start:
mov ebx,1
mov eax,1
int 0x80
$ nasm -f elf64 true.asm && ld -s -o true true.o # -s means strip
$ nasm -f elf64 false.asm && ld -s -o false false.o
$ ll true false
-rwxrwxr-x. 1 steve steve 352 Jan 25 16:03 false
-rwxrwxr-x. 1 steve steve 352 Jan 25 16:03 true
$ ./true ; echo $?
0
$ ./false ; echo $?
1
$
または、少し厄介な/独創的なアプローチ(kudos to stalkr )を使用して、独自のELFヘッダーを作成し、 132 127バイト。ここに Code Golf 領域を入力します。
$ cat true2.asm
BITS 64
org 0x400000 ; _start is at 0x400080 as usual, but the ELF headers come first
ehdr: ; Elf64_Ehdr
db 0x7f, "ELF", 2, 1, 1, 0 ; e_ident
times 8 db 0
dw 2 ; e_type
dw 0x3e ; e_machine
dd 1 ; e_version
dq _start ; e_entry
dq phdr - $$ ; e_phoff
dq 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf64_Phdr
dd 1 ; p_type
dd 5 ; p_flags
dq 0 ; p_offset
dq $$ ; p_vaddr
dq $$ ; p_paddr
dq filesize ; p_filesz
dq filesize ; p_memsz
dq 0x1000 ; p_align
phdrsize equ $ - phdr
_start:
xor edi,edi ; int status = 0
; or mov dil,1 for false: high bytes are ignored.
lea eax, [rdi+60] ; rax = 60 = SYS_exit, using a 3-byte instruction: base+disp8 addressing mode
syscall ; native 64-bit system call, works without CONFIG_IA32_EMULATION
; less-golfed version:
; mov edi, 1 ; for false
; mov eax,252 ; SYS_exit_group from asm/unistd_64.h
; syscall
filesize equ $ - $$ ; used earlier in some ELF header fields
$ nasm -f bin -o true2 true2.asm
$ ll true2
-rw-r--r-- 1 peter peter 127 Jan 28 20:08 true2
$ chmod +x true2 ; ./true2 ; echo $?
0
$
l $(which true false)
-rwxr-xr-x 1 root root 27280 Mär 2 2017 /bin/false
-rwxr-xr-x 1 root root 27280 Mär 2 2017 /bin/true
私のUbuntu 16.04でもかなり大きい。全く同じサイズ?何がそんなに大きいのですか?
strings $(which true)
(抜粋:)
Usage: %s [ignored command line arguments]
or: %s OPTION
Exit with a status code indicating success.
--help display this help and exit
--version output version information and exit
NOTE: your Shell may have its own version of %s, which usually supersedes
the version described here. Please refer to your Shell's documentation
for details about the options it supports.
http://www.gnu.org/software/coreutils/
Report %s translation bugs to <http://translationproject.org/team/>
Full documentation at: <%s%s>
or available locally via: info '(coreutils) %s%s'
ああ、trueとfalseにはヘルプがあるので、試してみましょう。
true --help
true --version
#
何もない。ああ、この別の行がありました:
NOTE: your Shell may have its own version of %s, which usually supersedes
the version described here.
したがって、私のシステムでは、/ usr/bin/trueではなく、/ bin/trueです。
/bin/true --version
true (GNU coreutils) 8.25
Copyright © 2016 Free Software Foundation, Inc.
Lizenz GPLv3+: GNU GPL Version 3 oder höher <http://gnu.org/licenses/gpl.html>
Dies ist freie Software: Sie können sie ändern und weitergeben.
Es gibt keinerlei Garantien, soweit wie es das Gesetz erlaubt.
Geschrieben von Jim Meyering.
LANG=C /bin/true --version
true (GNU coreutils) 8.25
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Jim Meyering.
だから助けがあり、バージョン情報があり、国際化のためにライブラリにバインドしています。これはサイズの大部分を説明し、シェルはとにかくほとんどの場合、最適化されたコマンドを使用します。
Rui F Ribeiroが受け入れた回答は多くの優れた情報を提供しますが、一部が欠落しており、コードサイズが「ELFオーバーヘッド」などに比べて小さいという誤解を招く印象を読者に残しているように感じます。
したがって、私の最初の疑いは部分的に正しかったですが、ライブラリが動的ライブラリを使用している間、
/bin/true
バイナリは大きくなります。*some静的ライブラリが含まれているためです*それだけが原因ではありません)。
静的リンクはオブジェクトファイルの粒度で(または--gc-sections
を使用するとさらに細かく)なるため、「リンクされている」静的ライブラリについて説明しても意味がありません。リンクされる唯一の部分は使用されるものであり、ここでのコードサイズは、実際に(不当に)coreutilsバージョンのtrue
によって使用されるコードです。 true.c
に表示されるものとは別にカウントしても意味がありません。
バイナリのサイズのほぼ90%である追加のスペースは、実際には追加のライブラリ/ elfメタデータです。
ELFメタデータは、ほぼ完全に動的リンクに必要なテーブルであり、サイズの90%にはほど遠いものです。以下は、関連するsize -A
出力の行です。
section size addr .interp 28 568 .gnu.hash 60 664 .dynsym 1416 728 .dynstr 676 2144 .gnu.version 118 2820 .gnu.version_r 96 2944 .rela.dyn 624 3040 .rela.plt 1104 3664 .plt 752 4800 .plt.got 8 5552 .dynamic 480 2125272 .got 48 2125752 .got.plt 392 2125824
合計で約5.5k、つまり動的シンボルあたり平均約100バイトです(一部はシンボル単位ではないためかなり公平ではありませんが、多少意味のある数値です)。
Ruiの答えがカバーしなかったサイズへの1つの大きな貢献者は次のとおりです。
.eh_frame_hdr 572 21728 .eh_frame 2908 22304
この3.5kは、C++例外処理、内省的バックトレースなどのDWARFアンワインドテーブルです。これらはtrue
には完全に役に立ちませんが、非常に冗長な名前のオプションで明示的に省略しない限り、すべての出力にGCCポリシーによって含まれます-fno-asynchronous-unwind-tables
。これの背後にある動機は Stack Overflowでの私による回答 で説明されています。
だから私は最終的な内訳を次のように説明します:
特に、ダイナミックリンクライブラリから必要なコードの量が十分に少ない場合、スタティックリンクはダイナミックリンクよりも小さい可能性があります。