진실은 왜 그렇게 거짓인가?

진실은 왜 그렇게 거짓인가?

read몇 가지 공통 명령(예: truefalse.

음, 확실히 바이너리 파일입니다.

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$

그러나 가장 놀랐던 것은 그 크기였습니다. trueis 는 기본적으로 just exit 0and falseis 이기 때문에 각각 몇 바이트만 있을 것으로 예상했습니다 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$

그래서 내 질문은: 왜 그렇게 큰가요? 반환 코드 외에 실행 파일에는 무엇이 더 있습니까?

추신: 저는 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에서는 bashtrue명령 false이 쉘 내장으로 구현됩니다. 따라서 and 지시어를 사용하는 명령줄에서 사용하든 false, 쉘 스크립트에서 사용하든 기본적으로 실행 가능한 바이너리가 호출되지 않습니다.truebash

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/trueDebian 9/64비트 패키지의 바이너리에 중점을 둘 것입니다. coreutils( /usr/bin/trueRedHat 실행. 두 coreutils패키지 모두 RedHat과 Debian에서 사용되며 후자의 컴파일된 버전을 분석하고 더 많은 정보를 제공합니다.)

소스 파일에서 볼 수 있듯이 false.cEXIT_FAILURE (1)이 반환된다는 점을 제외하면 /bin/false(거의) 동일한 소스 코드로 컴파일되었으므로 이 답변은 두 바이너리 모두에 적용될 수 있습니다./bin/true

#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동일한 바이너리를 사용하거나 사용하는 것을 귀찮게 하지 않습니다 .truecoreutils

그러나 질문의 ​​진정한 의미에서 볼 때, 그렇게 단순하고 작아야 할 것이 왜 그렇게 커지는가?

부품의 실제 분포는 /bin/true26KB 바이너리로 표시되며, 메인 코드 + 데이터는 약 3KB를 차지합니다 /bin/true.

true이 유틸리티는 수년에 걸쳐 더욱 대략적인 코드를 얻었으며, 특히 --version및 에 대한 표준 지원이 두드러졌습니다 --help.

그러나 그것이 그렇게 큰 (유일한) 주된 이유는 아니지만 동적으로 링크하는 동안(공유 라이브러리를 사용하여) coreutils정적 라이브러리로 링크된 바이너리가 일반적으로 사용하는 공통 라이브러리의 일부도 포함합니다. 실행 파일을 빌드하는 데 사용되는 메타데이터는 elf오늘날 표준으로 볼 때 상대적으로 작은 파일인 바이너리의 상당 부분을 구성합니다.

나머지 대답은 /bin/true실행 가능한 바이너리의 구성을 자세히 설명하는 다음 다이어그램을 구성한 방법과 그러한 결론에 도달한 방법을 설명하기 위한 것입니다.

빈 젠 폭식 2

@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.

외부 링크가 없는 추가 기능은 다음 main()과 같습니다.

  • 프로그램 이름 설정()
  • stdout()을 닫습니다.
  • 버전 등()

따라서 내 첫 번째 의심은 부분적으로 정확했습니다. 라이브러리는 동적 라이브러리를 사용하지만 /bin/true바이너리는 엄청납니다.왜냐하면 그것은일부정적 라이브러리 포함(그러나 이것이 유일한 이유는 아닙니다).

C 코드는 일반적으로 컴파일되지 않습니다.저것이렇게 비효율적인 공간이 존재하지 않아서 처음에는 뭔가 문제가 있지 않을까 의심했습니다.

추가 공간은 바이너리 크기의 거의 90%를 차지하며 실제로는 추가 라이브러리/elf 메타데이터입니다.

함수가 어디에 있는지 확인하기 위해 바이너리를 분해/역컴파일하기 위해 Hopper를 사용하면 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

답변2

구현은 아마도 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.

문자열 데이터 외에도 바이너리에는 명령줄 플래그 등을 구문 분석하기 위한 논리도 포함되어 있습니다. 분명히 이것은 총 약 20KB의 코드를 추가합니다.

참고로 여기에서 소스 코드를 찾을 수 있습니다.http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/true.c

답변3

핵심 기능만 제거하고 어셈블러로 작성하면 더 작은 바이너리가 생성됩니다.

원래의 true/false 바이너리는 C로 작성되어 기본적으로 다양한 라이브러리 + 기호 참조를 가져옵니다. 실행해 보면 readelf -a /bin/true이는 매우 분명합니다 .

352화제거된 ELF 정적 실행 파일 바이트 수(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
$

또는 불쾌하고 영리한 접근 방식을 사용합니다.스토커), 자신만의 ELF 헤더를 생성하고 132 로 줄이세요. 127바이트. 우리는 들어가고있다코드 골프영토는 여기입니다.

$ 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
$

답변4

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

따라서 국제화를 위해 라이브러리에 바인딩하는 버전 정보가 있습니다. 이것이 대부분의 크기를 설명하며, 쉘은 대부분의 경우 최적화된 명령을 사용합니다.

관련 정보