AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 419697
Accepted
Kidburla
Kidburla
Asked: 2018-01-26 12:14:47 +0800 CST2018-01-26 12:14:47 +0800 CST 2018-01-26 12:14:47 +0800 CST

Por que verdadeiro e falso são tão grandes?

  • 772

Depois de descobrir que vários comandos comuns (como read) são na verdade internos do Bash (e ao executá-los no prompt, na verdade, estou executando um script de shell de duas linhas que apenas encaminha para o interno), eu estava procurando ver se o mesmo é verdadeiro para truee false.

Bem, eles são definitivamente binários.

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$

No entanto, o que mais me surpreendeu foi o tamanho. Eu esperava que eles tivessem apenas alguns bytes cada, pois trueé basicamente apenas exit 0e falseé exit 1.

sh-4.2$ true
sh-4.2$ echo $?
0
sh-4.2$ false
sh-4.2$ echo $?
1
sh-4.2$

No entanto, descobri, para minha surpresa, que ambos os arquivos têm mais de 28 KB de tamanho.

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$

Então, minha pergunta é: por que eles são tão grandes? O que há no executável além do código de retorno?

PS: Estou usando o RHEL 7.4

linux reverse-engineering
  • 5 5 respostas
  • 25560 Views

5 respostas

  • Voted
  1. Best Answer
    Rui F Ribeiro
    2018-01-26T12:50:28+08:002018-01-26T12:50:28+08:00

    No passado, /bin/truee /bin/falseno shell, havia realmente scripts.

    Por exemplo, em um 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
    $  
    

    Atualmente, pelo menos no bash, os comandos truee falsesão implementados como comandos internos do shell. Portanto, nenhum arquivo binário executável é invocado por padrão, tanto ao usar as diretivas falsee na linha de comando quanto dentro de scripts de shell.truebash

    Da bashfonte builtins/mkbuiltins.c,:

    char *posix_builtins[] =
        {
          "alias", "bg", "cd", "command", "**false**", "fc", "fg", "getopts", "jobs",
          "kill", "newgrp", "pwd", "read", "**true**", "umask", "unalias", "wait",
          (char *)NULO
        };
    

    Também pelos comentários do @meuh:

    $ command -V true false
    true is a shell builtin
    false is a shell builtin
    

    Portanto, pode-se dizer com alto grau de certeza que os arquivos truee falseexecutáveis ​​existem principalmente para serem chamados de outros programas .

    A partir de agora, a resposta se concentrará no /bin/truebinário do coreutilspacote em Debian 9/64 bits. ( /usr/bin/truerodando RedHat. RedHat e Debian usam ambos o coreutilspacote, analisamos a versão compilada deste último tendo mais em mãos).

    Como pode ser visto no arquivo fonte false.c, /bin/falseé compilado com (quase) o mesmo código fonte que /bin/true, apenas retornando EXIT_FAILURE (1), então esta resposta pode ser aplicada para ambos os binários.

    #define EXIT_STATUS EXIT_FAILURE
    #include "true.c"
    

    Como também pode ser confirmado por ambos os executáveis ​​com o mesmo tamanho:

    $ 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
    

    Infelizmente, a pergunta direta para a resposta why are true and false so large?poderia ser, porque não há mais razões tão prementes para se preocupar com seu desempenho superior. Eles não são essenciais para o bashdesempenho, não sendo mais usados ​​por bash(scripts).

    Comentários semelhantes se aplicam ao seu tamanho, 26 KB para o tipo de hardware que temos hoje em dia é insignificante. O espaço não é mais premium para o servidor/desktop típico, e eles nem se preocupam mais em usar o mesmo binário para falsee true, pois ele é implantado apenas duas vezes em distribuições usando coreutils.

    Focalizando, porém, no verdadeiro espírito da questão, por que algo que deveria ser tão simples e pequeno, se torna tão grande?

    A distribuição real das seções de /bin/trueé como mostram esses gráficos; o código principal + dados equivale a aproximadamente 3 KB de um binário de 26 KB, o que equivale a 12% do tamanho de /bin/true.

    O trueutilitário obteve de fato mais código cruft ao longo dos anos, principalmente o suporte padrão para --versione --help.

    No entanto, essa não é a (única) principal justificativa para ser tão grande, mas sim, ao mesmo tempo em que é vinculado dinamicamente (usando bibliotecas compartilhadas), também possui parte de uma biblioteca genérica comumente usada por coreutilsbinários vinculados como uma biblioteca estática. A metada para a construção de um elfarquivo executável também representa uma parte significativa do binário, sendo um arquivo relativamente pequeno para os padrões atuais.

    O restante da resposta é para explicar como construímos os gráficos a seguir detalhando a composição do /bin/truearquivo binário executável e como chegamos a essa conclusão.

    bintrue bintrue2

    Como diz @Maks, o binário foi compilado de C; de acordo com meu comentário também, também está confirmado que é do coreutils. Estamos apontando diretamente para o(s) autor(es) git https://github.com/wertarbyte/coreutils/blob/master/src/true.c , em vez do gnu git como @Maks (mesmas fontes, repositórios diferentes - este repositório foi selecionado, pois possui o código-fonte completo das coreutilsbibliotecas)

    Podemos ver os vários blocos de construção do /bin/truebinário aqui (Debian 9 - 64 bits de 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
    

    Daqueles:

    • texto (geralmente código) é de cerca de 24 KB
    • dados (variáveis ​​inicializadas, principalmente strings) estão em torno de 1KB
    • bss (dados não inicializados) 0,5 KB

    Dos 24KB, cerca de 1KB é para fixar as 58 funções externas.

    Isso ainda deixa cerca de 23 KB para o restante do código. Mostraremos abaixo que o arquivo principal real - código main()+usage() tem cerca de 1KB compilado e explicamos para que os outros 22KB são usados.

    Aprofundando o binário com readelf -S true, podemos ver que, embora o binário seja de 26159 bytes, o código compilado real é de 13017 bytes e o restante é um código de dados/inicialização variado.

    No entanto, true.cnão é toda a história e 13 KB parece muito excessivo se fosse apenas esse arquivo; podemos ver as funções chamadas main()que não estão listadas nas funções externas vistas no elf com objdump -T true; funções que estão presentes em:

    • 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

    Essas funções extras não vinculadas externamente main()são:

    • set_program_name()
    • close_stdout()
    • versão_etc()

    Portanto, minha primeira suspeita estava parcialmente correta, embora a biblioteca esteja usando bibliotecas dinâmicas, o /bin/truebinário é grande *porque possui algumas bibliotecas estáticas incluídas* (mas essa não é a única causa).

    A compilação do código C geralmente não é tão ineficiente por ter esse espaço não contabilizado, portanto, minha suspeita inicial de que algo estava errado.

    O espaço extra, quase 90% do tamanho do binário, é de fato bibliotecas extras/metadados elf.

    Ao usar o Hopper para desmontar/descompilar o binário para entender onde estão as funções, pode-se ver que o código binário compilado da função true.c/usage() é na verdade 833 bytes e da função true.c/main() é 225 bytes, que é aproximadamente um pouco menos de 1 KB. A lógica das funções de versão, que está escondida nas bibliotecas estáticas, é de cerca de 1KB.

    O main()+usage()+version()+strings+vars compilado real está usando apenas cerca de 3KB a 3,5KB.

    É realmente irônico que essas pequenas e humildes utilidades tenham se tornado maiores pelas razões explicadas acima.

    pergunta relacionada: Entendendo o que um binário do Linux está fazendo

    true.cmain () com as chamadas de função ofensivas:

    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);
    }
    

    O tamanho decimal das várias seções do binário:

    $ 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
    

    Saída dereadelf -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)
    

    Saída de objdump -T true(funções externas vinculadas dinamicamente em tempo de execução)

    $ 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
    
    • 153
  2. Maks Verver
    2018-01-26T12:29:47+08:002018-01-26T12:29:47+08:00

    A implementação provavelmente vem do GNU coreutils. Esses binários são compilados de C; nenhum esforço particular foi feito para torná-los menores do que são por padrão.

    Você pode tentar compilar a implementação trivial de truesi mesmo e notará que já tem alguns KB de tamanho. Por exemplo, no meu sistema:

    $ echo 'int main() { return 0; }' | gcc -xc - -o true
    $ wc -c true
    8136 true
    

    Claro, seus binários são ainda maiores. Isso porque eles também suportam argumentos de linha de comando. Tente executar /usr/bin/true --helpou /usr/bin/true --version.

    Além dos dados de string, o binário inclui lógica para analisar sinalizadores de linha de comando, etc. Isso soma cerca de 20 KB de código, aparentemente.

    Para referência, você pode encontrar o código-fonte aqui: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/true.c

    • 37
  3. steve
    2018-01-26T13:05:30+08:002018-01-26T13:05:30+08:00

    Stripping them down to core functionality and writing in assembler yields far smaller binaries.

    Original true/false binaries are written in C, which by its nature pulls in various library + symbol references. If you run readelf -a /bin/true this is quite noticeable.

    352 bytes for a stripped ELF static executable (with room to save a couple bytes by optimizing the asm for code-size).

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

    Or, with a bit of a nasty/ingenious approach (kudos to stalkr), create your own ELF headers, getting it down to 132 127 bytes. We're entering Code Golf territory here.

    $ 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
    $
    
    • 26
  4. user unknown
    2018-02-15T05:22:56+08:002018-02-15T05:22:56+08:00
    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
    

    Pretty big on my Ubuntu 16.04 too. exactly the same size? What makes them so big?

    strings $(which true)
    

    (excerpt:)

    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'
    

    Ah, there is help for true and false, so let's try it:

    true --help 
    true --version
    #
    

    Nothing. Ah, there was this other line:

    NOTE: your shell may have its own version of %s, which usually supersedes
        the version described here.
    

    So on my system, it's /bin/true, not /usr/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.
    

    So there is help, there is version information, binding to a library for internationalization. This explains much of the size, and the shell uses its optimized command anyway and most of the time.

    • 2
  5. R.. GitHub STOP HELPING ICE
    2020-01-14T18:50:36+08:002020-01-14T18:50:36+08:00

    The accepted answer by Rui F Ribeiro gives a lot of good information, but it's missing some and I feel like it leaves the reader with a misleading impression that the code size is small relative to "ELF overhead" and similar.

    So my first suspicion was partly correct, whilst the library is using dynamic libraries, the /bin/true binary is big *because it has some static libraries included with it* (but that is not the only cause).

    Static linking is at object file granularity (or even finer with --gc-sections), so it doesn't make sense to talk about a static library being "linked in"; the only part linked in is what's used, and the code size here is code that's actually (gratuitously) used by the coreutils version of true. It does not make sense to count it separately from what appears in true.c.

    The extra space, almost 90% of the size of the binary, is indeed extra libraries/elf metadata.

    The ELF metadata is pretty much entirely tables necessary for dynamic linking, and is nowhere near 90% of the size. These are the lines from size -A output relevant to it:

    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
    

    for a total of around 5.5k, or an average of about 100 bytes per dynamic symbol (not quite fair because some aren't on a per-symbol basis, but it's a somewhat meaningful figure).

    One large contributor to size that Rui's answer didn't cover is:

    .eh_frame_hdr          572     21728
    .eh_frame             2908     22304
    

    This 3.5k is DWARF unwind tables for C++ exception handling, introspective backtrace, etc. They're completely useless for true, but included by GCC policy in all output unless you explicitly omit them with a very verbosely-named option -fno-asynchronous-unwind-tables. The motivations behind this are explained in an answer by me on Stack Overflow.

    So I would describe the final breakdown as:

    • 16k of program code and read-only (shareable) data
    • 5.5k of dynamic linking glue
    • 3.5k of unwind tables
    • <1k misc

    Em particular, é notável que, se a quantidade de código necessária de bibliotecas com links dinâmicos fosse suficientemente pequena, o link estático poderia ser menor do que o link dinâmico.

    • 2

relate perguntas

  • Existe uma maneira de fazer ls mostrar arquivos ocultos apenas para determinados diretórios?

  • Inicie/pare o serviço systemd usando o atalho de teclado [fechado]

  • Necessidade de algumas chamadas de sistema

  • astyle não altera a formatação do arquivo de origem

  • Passe o sistema de arquivos raiz por rótulo para o kernel do Linux

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve