과거 /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
$
요즘, 최소한의 bash
의 true
와 false
명령은 쉘 내장 명령으로 구현됩니다. 따라서 명령 행과 쉘 스크립트 에서 false
and true
지시문을 사용할 때 기본적으로 실행 가능한 2 진 파일이 호출되지 않습니다 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
실행 파일이 주로 존재하는 다른 프로그램에서 호출되는 .
이제부터는 데비안 9/64 비트 패키지 의 /bin/true
바이너리에 초점을 맞출 것 coreutils
입니다. ( /usr/bin/true
RedHat을 실행 중입니다. RedHat과 Debian은 두 coreutils
패키지를 모두 사용하고, 패키지 패키지를 더 많이 사용하고 있습니다.
이 소스 파일에서 볼 수 있듯이 false.c
, /bin/false
같은 (거의) 동일한 소스 코드로 컴파일 /bin/true
단지 (1) 대신에, 그래서이 답변이 모두 바이너리 적용 할 수 있습니다 EXIT_FAILURE를 반환.
#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
그리고 true
그것은 단지 사용하는 배포판에 두 번 배포로 coreutils
.
그러나 질문의 실제 정신에 초점을 맞추면 왜 그렇게 단순하고 작아야하는 것이 그렇게 커 집니까?
섹션의 실제 분포는 /bin/true
이 차트가 보여주는 것과 같습니다. 주요 코드 + 데이터는 26KB 바이너리 중 약 3KB에 해당하며 크기는 12 %입니다 /bin/true
.
이 true
유틸리티는 수년 동안 더 많은 비밀 코드, 특히 --version
and에 대한 표준 지원을 받았습니다 --help
.
그러나 그것이 공유 라이브러리를 사용하여 동적으로 링크되는 동안 coreutils
정적 라이브러리로 연결된 바이너리에 의해 일반적으로 사용되는 일반 라이브러리의 일부를 갖는 것은 그것이 유일한 큰 정당화가 아니라 오히려 그렇습니다 . elf
실행 파일을 만들기위한 메타 데이터 는 바이너리의 상당 부분을 차지하며 오늘날 표준에 따라 상대적으로 작은 파일입니다.
나머지 대답은 /bin/true
실행 가능한 이진 파일 의 구성을 자세히 설명하는 다음 차트를 작성하는 방법과 그 결론에 도달 한 방법을 설명하기위한 것입니다.
@Maks가 말했듯이 바이너리는 C에서 컴파일되었습니다. 내 의견에 따르면 coreutils에서도 확인되었습니다. 우리는 @Maks (같은 소스, 다른 저장소-이 저장소와 같은 gnu git 대신 저자 git https://github.com/wertarbyte/coreutils/blob/master/src/true.c를 직접 가리키고 있습니다. coreutils
라이브러리 의 전체 소스가 있으므로 선택되었습니다 )
/bin/true
여기서 바이너리 의 다양한 빌딩 블록을 볼 수 있습니다 (에서 데비안 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()
엘프에서 볼 수있는 외부 함수에는없는 함수를 호출 할 수있다 objdump -T true
. 존재하는 기능 :
외부 적으로 연결되지 않은 추가 기능 main()
은 다음 과 같습니다.
- set_program_name ()
- close_stdout ()
- version_etc ()
그래서 내 첫 번째 의혹은 라이브러리는 동적 라이브러리를 사용하고있는 동안은, 부분적으로 정확했다 /bin/true
가 있기 때문에 바이너리 * 큰 일부 정적 라이브러리는 *이 포함 (하지만 그 유일한 원인이 아니다).
C 코드를 컴파일하는 것은 일반적으로 이러한 공간을 고려할 때 비효율적 이지 않으므로 초기 의심이 잘못되었습니다.
이진 크기의 거의 90 % 인 추가 공간은 실제로 추가 라이브러리 / 엘프 메타 데이터입니다.
바이너리를 디스 어셈블 / 디 컴파일하기 위해 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
command -V true
하지 않아야which
합니다.true is a shell builtin
bash 용으로 출력됩니다 .