read
いくつかの共通コマンド(例: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
isは基本的にjust exit 0
and false
isなので、それぞれ数バイトしかないと予想しました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を使用しています。
ベストアンサー1
過去には実際に/bin/true
シェル/bin/false
にスクリプトがありました。
たとえば、PDP/11 Unixシステム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
$
最近では、少なくともLinuxでは、bash
コマンドはtrue
シェルfalse
組み込みで実装されています。したがって、andディレクティブを使用するコマンドラインで使用してもfalse
、シェルスクリプトで使用しても、デフォルトで実行可能なバイナリは呼び出されません。true
bash
bash
ソースからbuiltins/mkbuiltins.c
:
文字 *posix_buildins[] = { 「エイリアス」、「bg」、「cd」、「コマンド」、「間違った","fc","fg","getopts","作業", 「殺す」、「newgrp」、「pwd」、「読む」、本物","umask","unalias","ちょっと待って", (文字*)NULL };
@meuhコメントも参照してください。
$ command -V true false
true is a shell builtin
false is a shell builtin
true
したがって、実行可能false
ファイルが主に存在することは非常に確実であると言えます。他のプログラムから呼び出された。
これからの答えは、/bin/true
Debian 9/64ビットパッケージのバイナリに焦点を当てます。coreutils
(/usr/bin/true
RedHatの実行。両方の coreutils
パッケージはRedHatとDebianで使用され、後者のコンパイル済みバージョンを分析し、より多くの情報を提供します。)
ソースファイルに示すように、false.c
EXIT_FAILURE(1)が返されることを除いて/bin/false
(ほぼ)同じソースコードにコンパイルされているため、この答えは両方のバイナリに適用できます。/bin/true
#define EXIT_STATUS EXIT_FAILURE
#include "true.c"
これは、同じサイズの2つの実行可能ファイルを使用して確認することもできるためです。
$ 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
ああ、質問に直接答えてください。「なぜ真実は偽ですか?」おそらくそうです。もはや最高の成果に関心を持つ緊急の理由がないからです。パフォーマンスには必要なく、bash
スクリプトでは使用されなくなりましたbash
。
サイズにも同様のコメントが適用されます。現在保有しているハードウェアでは26KBが非常に小さいです。一般的なサーバー/デスクトップの場合、スペースはもはや重要ではなく、使用されているディストリビューションに2回配布されているため、同じfalse
バイナリを使用または使用するのは面倒ではありません。true
coreutils
しかし、質問の本当の意味で見ると、なぜそれが単純で小さくなければならないのがなぜそれほど大きくなるのですか?
部品の実際の分布は/bin/true
26KBバイナリで表され、メインコード+データは約3KBを占めます/bin/true
。
true
このユーティリティは長年にわたってよりおおよそのコードを得ており、特におよび標準的な--version
サポートが際立っています--help
。
しかし、それがそれほど大きな(唯一の)主な理由ではありませんが、動的にリンクしている間(共有ライブラリを使用して)静的ライブラリにリンクされたバイナリがcoreutils
通常使用する共通ライブラリの一部も含まれます。実行可能ファイルを構築するために使用されるメタデータは、elf
今日標準として見ると、比較的小さなファイルであるバイナリの大部分を構成します。
残りの答えは、/bin/true
実行可能なバイナリの構成を詳しく説明する次の図を構成した方法と、そのような結論に達した方法を説明するためのものです。
@Maksが言ったように、バイナリは私の意見に基づいてCでコンパイルされ、coreutilsでも確認されました。私達は著者gitを直接指す。https://github.com/wertarbyte/coreutils/blob/master/src/true.c、@Maksのようなgnu gitの代わりに(同じソース、他のリポジトリ - このリポジトリはcoreutils
ライブラリの完全なソースコードを持っているので選択されました)
ここでは、バイナリのさまざまなコンポーネントを見ることができます/bin/true
(Debian 9 - 64ビットcoreutils
)。
$ 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です。
- bss(初期化されていないデータ) 0.5KB
24KBのうち約1KBが58の外部機能を変更するために使用されます。
残りのコードにはまだ約23KBが残っています。以下に実際のメインファイルを示します。 main()+usage() コードのコンパイルされたサイズは約 1KB で、残りの 22KB の目的を説明します。
バイナリを詳しく見ると、readelf -S true
バイナリは26159バイトですが、実際にコンパイルされたコードは13017バイトで、残りはさまざまなデータ/初期化コードであることがわかります。
しかし、true.c
それはすべてではありません。そのファイルなら、13KBはやや大きいようです。呼び出される関数がmain()
elf の外部関数にリストされていないことがわかりますobjdump -T true
。
- https://github.com/coreutils/gnulib/blob/master/lib/progname.c
- https://github.com/coreutils/gnulib/blob/master/lib/closeout.c
- https://github.com/coreutils/gnulib/blob/master/lib/version-etc.c
外部リンクを持たない追加機能は次main()
のとおりです。
- プログラム名の設定()
- stdout() を閉じます。
- バージョンなど()
したがって、私の最初の疑いは部分的に正確でした。ライブラリは動的ライブラリを使用しますが、/bin/true
バイナリは膨大です。なぜなら一部静的ライブラリを含む(しかし、これが唯一の理由ではありません)。
Cコードは通常コンパイルされません。それこのように非効率的な空間が存在しなかったので、最初は何か問題がないかと疑いました。
追加スペースはバイナリサイズのほぼ90%を占め、実際には追加のライブラリ/ elfメタデータです。
関数がどこにあるかを確認するためにバイナリを分解/逆コンパイルするためにHopperを使用すると、true.c/usage()関数用にコンパイルされたバイナリコードは実際には833バイトですが、true.c/main()関数はコンパイルされますバイナリコードは225バイトで、約1KBよりわずかに小さいです。バージョン機能のロジックは、約1KBサイズの静的ライブラリに隠されています。
実際にコンパイルされた main()+usage()+version()+strings+vars は約 3 KB から 3.5 KB だけを使用します。
このように小さく、目立たない電力会社が上記のような理由でますます大きくなるのは確かに皮肉です。
関連質問: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