GNU/Linux >> Linux の 問題 >  >> Linux

Linux –なぜ真と偽はそれほど大きいのですか?

いくつかの一般的なコマンド( 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 として、それぞれ数バイトであると予想しました 基本的にはexit0です および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:私はRHEL7.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から ソース、 builtins / mkbuiltins.c

char *posix_builtins[] =
    {
      "alias", "bg", "cd", "command", "**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 実行可能ファイルは、主に他のプログラムから呼び出されるために存在します 。

今後、答えは / bin / trueに焦点を当てます coreutilsからのバイナリ Debian9/64ビットのパッケージ。 ( / 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

残念ながら、答えに対する直接の質問は、なぜ真と偽がそれほど大きいのですか? 彼らの最高のパフォーマンスを気にする緊急の理由がもうないので、そうかもしれません。 bashには必須ではありません パフォーマンス、 bashでは使用されなくなりました (スクリプト)。

同様のコメントがそれらのサイズにも当てはまります。現在使用している種類のハードウェアの26KBは重要ではありません。通常のサーバー/デスクトップのスペースはもはや貴重ではなく、 falseに同じバイナリを使用する必要もありません。 およびtrue coreutilsを使用してディストリビューションに2回デプロイされただけなので 。

しかし、焦点を当てると、質問の本当の精神で、なぜこれほど単純で小さいはずの何かがこれほど大きくなるのでしょうか。

/ bin / trueのセクションの実際の分布 これらのチャートが示すように;メインのコード+データは26KBのバイナリのうち約3KBになり、 / bin / true のサイズの12%になります。 。

true ユーティリティは、実際に何年にもわたってより多くの重要なコードを取得しました。特に、-versionの標準サポートです。 および--help

ただし、これが非常に大きいことの(唯一の)主な理由ではなく、動的にリンクされている間(共有ライブラリを使用)、 coreutilsで一般的に使用される汎用ライブラリの一部もあります。 静的ライブラリとしてリンクされたバイナリ。 elfを構築するためのメタダ 実行可能ファイルもバイナリのかなりの部分を占めており、今日の標準では比較的小さなファイルです。

残りの答えは、 / bin / trueの構成を詳細に示す次のグラフを作成する方法を説明するためのものです。 実行可能バイナリファイルと、その結論に到達した方法。

関連:_roffを使用して単語に下線を付けますか?

@Maksが言うように、バイナリはCからコンパイルされました。私のコメントにもあるように、それはcoreutilsからのものであることも確認されています。 @Maks(同じソース、異なるリポジトリ–このリポジトリ)のようなgnu gitではなく、作成者githttps://github.com/wertarbyte/coreutils/blob/master/src/true.cを直接指し示しています。 coreutilsの完全なソースがあるために選択されました ライブラリ)

/ bin / trueのさまざまな構成要素を確認できます ここではバイナリ(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です
  • bss(初期化されていないデータ)0.5KB

24KBのうち、約1KBは58の外部機能を修正するためのものです。

それでも、残りのコードには約23KBが残ります。以下に、実際のメインファイル– main()+ using()コードが約1KBコンパイルされていることを示し、他の22KBが何に使用されているかを説明します。

readelf -S trueを使用してバイナリをさらにドリルダウンする 、バイナリが26159バイトであるのに対し、実際にコンパイルされたコードは13017バイトであり、残りはさまざまなデータ/初期化コードであることがわかります。

ただし、 true.c 全体像ではなく、そのファイルだけの場合、13KBはかなり過剰に見えます。 main()で呼び出された関数を見ることができます objdump -T trueを使用してelfに表示される外部関数にリストされていないもの;に存在する関数:

  • 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()で外部的にリンクされていない追加の関数 は:

  • set_program_name()
  • close_stdout()
  • version_etc()

したがって、私の最初の疑惑は部分的に正しかったのですが、ライブラリがダイナミックライブラリを使用している間、 / bin / true バイナリは大きい*いくつかあるため それに含まれている静的ライブラリ*(ただし、それだけが原因ではありません)。

Cコードのコンパイルは、通常、ではありません。 そのようなスペースを考慮に入れていないのは非効率的であるため、私の最初の疑惑は何かが間違っていました。

バイナリのサイズのほぼ90%である余分なスペースは、実際には余分なライブラリ/elfメタデータです。

ホッパーを使用してバイナリを逆アセンブル/逆コンパイルして関数の場所を理解している間、true.c / using()関数のコンパイル済みバイナリコードは実際には833バイトであり、true.c / main()関数のコンパイル済みバイナリコードは225であることがわかります。バイト。これは約1KBよりわずかに少ないです。静的ライブラリに埋め込まれているバージョン関数のロジックは約1KBです。

実際にコンパイルされたmain()+ using()+ 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

Linux
  1. 私の公共図書館がLinuxとオープンソースを選ぶ理由

  2. Linux –なぜSuだけでなくSuを使用するのですか?

  3. x86 と x86_64 の Linux システムコール番号が異なるのはなぜですか?

  1. findおよびduコマンドを使用してLinuxで大きなファイルを検索する方法

  2. Linux – Linuxのハイメモリとローメモリとは何ですか?

  3. Linux –異なるLinux / UNIXカーネルは交換可能ですか?

  1. Windows、Mac OS X、Linux はどの言語で書かれていますか?

  2. Windows および Linux のディレクトリ名で禁止されている文字は何ですか?

  3. Linux の Makefile はなぜ便利なのですか?