Neden doğru ve yanlış bu kadar büyük?


80

Bazı ortak komutların (örneğin read) aslında Bash yerleşikleri olduğunu öğrendikten sonra (ve istemde çalıştırırken aslında sadece yerleşik yapıya yönlendiren iki satırlık bir kabuk betiği çalıştırıyorum), aynı olup olmadığını görmek istiyordum. trueve için de geçerlidir false.

Onlar kesinlikle ikili.

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$

Ancak en çok şaşırtıcı bulduğum şey onların büyüklüğü idi. Ben onları, sadece birkaç bayt her olması bekleniyor truesadece temelde exit 0ve falsebir exit 1.

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

Ancak her iki dosyanın da 28KB'den büyük olduğunu şaşırttım.

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$

Öyleyse sorum şu: Neden bu kadar büyükler? Dönüş kodundan başka bir yürütülebilir dosyada neler var?

PS: RHEL 7.4 kullanıyorum


9
Sen kullanmalıdır command -V truedeğil which. Çıktı yapacak: true is a shell builtinbash için.
meuh

32
trueve false olan her modern kabuğunda builtins ancak sistemler de bu programların doğrudan komutları çağırma (kabuk atlayarak) böylece standart bir sistemin parçası olduğu için bunları kullanabilirsiniz Bunların dış program sürümlerini içerir. whichyerleşikleri yok sayar ve yalnızca harici komutları arar, bu yüzden size yalnızca harici olanları gösterdi. Deneyin type -a trueve type -a falseonun yerine.
mtraceur

74
"Neden trueve falseher biri 29 kb? Neden ? Geri dönüş kodu dışında çalıştırılabilir olan nedir?"
David Richerby

7
Unix'in bazı eski sürümleri, true için boş bir dosyaya sahipti çünkü bu, çıkış kodunu 0 döndüren geçerli bir sh programıydı. Gerçekten de, yıllar önce gerçek bir yardımcı programın geçmişi hakkında boş bir dosyadan okuduğum bir makaleyi bulabilmeyi çok isterdim bugün olduğu canavarlık, ama bulabildiğim tek şey şuydu
Philip

9
Zorunlu - en küçük uygulama false: muppetlabs.com/~breadbox/software/tiny/teensy.html
d33tah

Yanıtlar:


117

Geçmişte /bin/trueve /bin/falsekabukta aslında senaryolar vardı.

Örneğin, bir PDP / 11 Unix Sistem 7'de:

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

Günümüzde, en azından bash, trueve falsekomutları kabuk yerleşik komutları olarak uygulanır. Bu nedenle, hem komut satırında hem de kabuk komut dosyalarında falseve trueyönergelerini kullanırken yürütülebilir bir ikili dosya varsayılan olarak çağrılmaz bash.

Gönderen bashkaynağı builtins/mkbuiltins.c:

char * posix_builtins [] =
    {
      "takma", "bg", "cd", "komut", "** yanlış **", "fc", "fg", "getopts", "iş",
      "öldür", "newgrp", "pwd", "oku", "** doğru **", "umask", "unalias", "bekle",
      (char *) NULL
    };

Ayrıca @ meuh yorumlarına göre:

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

Yani kesinlik yüksek derecede söylenebilir trueve falseyürütülebilir dosyalar için ağırlıklı mevcut diğer programlardan çağrılan .

Şu andan itibaren cevap, Debian 9/64 bit'teki pakette bulunan /bin/trueikili dosyaya odaklanacak coreutils. ( /usr/bin/trueRedHat kullanıyor. RedHat ve Debian coreutils, her iki paketi de kullanıyorlardı , ikincisinin derlenmiş halini analiz ettiler).

O kaynak dosyada görülebileceği gibi false.c, /bin/falseolarak (neredeyse) aynı kaynak kodu ile derlendi /bin/truesadece (1) yerine, bu nedenle bu cevap hem ikili için uygulanabilir EXIT_FAILURE dönen.

#define EXIT_STATUS EXIT_FAILURE
#include "true.c"

Aynı büyüklükteki her iki çalıştırılabilir tarafından da onaylanabileceği gibi:

$ 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

Ne yazık ki, cevabı doğrudan soru why are true and false so large?olabilir, çünkü artık onların en iyi performanslarına dikkat etmek için çok önemli nedenler yok. bashPerformans için zorunlu değillerdir, artık bash(scripting) tarafından kullanılmamaktadırlar .

Boyutları için de benzer yorumlar geçerli, bugünlerde sahip olduğumuz donanım için 26KB önemsiz. Alan artık tipik sunucu / masaüstü için üstün değil falseve truedağıtımlarda iki kez kullanıldıklarında aynı ikiliyi kullanmak için daha fazla zahmet etmiyorlar coreutils.

Bununla birlikte, sorunun gerçek ruhuna odaklanmak, neden bu kadar basit ve küçük olması gereken bir şeyi bu kadar büyütüyor?

Bölümlerin gerçek dağılımı /bin/truebu çizelgelerin gösterdiği gibidir; ana kod + veri, büyüklüğünün% 12'si olan 26 KB'lik bir ikiliden kabaca 3KB'ye çıkar /bin/true.

Bu truehizmet programı yıllar içinde gerçekten daha fazla güvenlik koduna sahip, özellikle de --versionve --help.

Bununla birlikte, bunun çok büyük olmasının (sadece) ana gerekçesi olmadığı, aksine dinamik bir şekilde bağlanırken (paylaşılan kütüphaneleri kullanarak), ayrıca coreutilsstatik bir kütüphane olarak bağlanmış ikili dosyalar tarafından kullanılan genel bir kütüphanenin bir parçası olması . elfYürütülebilir bir dosya oluşturmak için kullanılan meta veri, günümüzün standartlarına göre nispeten küçük bir dosya olması nedeniyle, ikili dosyanın önemli bir bölümünü oluşturur.

Cevabın geri kalan kısmı, /bin/trueçalıştırılabilir ikili dosyanın kompozisyonunu ve bu sonuca nasıl vardığımızı detaylandıran aşağıdaki tabloları nasıl oluşturmamız gerektiğini açıklamak içindir .

bintrue bintrue2

@Maks'in dediği gibi, ikili C'den derlenmiştir; Benim yorumuma göre, aynı zamanda coreutils'ten olduğu da doğrulandı. Gnu git yerine @Maks (aynı kaynaklar, farklı depolar - bu depo - dir ), yazar (lar) git https://github.com/wertarbyte/coreutils/blob/master/src/true.c adresini işaret ediyoruz. coreutilskütüphanelerin tam kaynağına sahip olması nedeniyle seçildi )

İkilinin çeşitli yapı taşlarını /bin/trueburada görebiliriz (Debian 9 - 64 bit arası 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

Bunların:

  • metin (genellikle kod) 24KB civarındadır
  • veri (ilklendirilen değişkenler, çoğunlukla dizeler) 1 KB civarındadır.
  • bss (başlatılmamış veri) 0.5KB

24KB'nin 1KB civarında, 58 harici fonksiyonunu düzeltmek için.

Bu hala kodun geri kalanı için kabaca 23KB civarında kalıyor. Asıl ana dosyanın - main () + use () kodunun 1 KB civarında derlendiğini ve diğer 22KB'nin ne için kullanıldığını açıkladığını göstereceğiz.

İle ikili altındaki delme readelf -S true, biz ikili 26159 bayt iken, fiili derlenmiş kod 13017 bayt olduğunu görebilir ve geri kalan çeşitli veri / başlatma kodudur.

Ancak, true.ctüm hikaye değil ve sadece dosya olsaydı 13KB oldukça fazla görünüyor; main()elf'te görülen harici işlevlerde listelenmeyen işlevleri görebilirsiniz objdump -T true; mevcut fonksiyonlar:

Dışarıdan bağlı olmayan bu ekstra fonksiyonlar main()şunlardır:

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

Bu yüzden ilk şüphem kısmen doğruydu, kütüphane dinamik kütüphaneleri kullanırken, /bin/trueikilik büyük * çünkü içerdiği bazı statik kütüphaneler var * (ancak bu tek neden değil).

C kodu derleniyor genellikle değil o nedenle benim ilk şüphe şey yanlış, akıbeti böyle bir alan olması için verimsiz.

İkilinin büyüklüğünün neredeyse% 90'ı kadar olan ekstra alan gerçekten de ekstra kütüphaneler / elf meta verileridir.

İşlevlerin nerede olduğunu anlamak için ikiliyi sökmek / açmak için Hopper kullanılırken, true.c / use () işlevinin derlenmiş ikili kodunun aslında 833 bayt ve true.c / main () işlevinin 225 olduğu görülebilir. yaklaşık 1 KB'den biraz daha az olan bayt. Statik kütüphanelere gömülmüş olan sürüm fonksiyonlarının mantığı 1 KB civarındadır.

Gerçek derlenmiş main () + use () + version () + string + vars sadece 3KB ila 3.5KB civarındadır.

Gerçekten de ironiktir, böyle küçük ve mütevazi kuruluşlar yukarıda açıklanan nedenlerden dolayı büyüklük kazanmıştır.

ilgili soru: Bir Linux binasının ne yaptığını anlamak

true.c main () rahatsız edici işlev çağrılarıyla:

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

İkilinin çeşitli bölümlerinin ondalık büyüklüğü:

$ 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

Çıktısı 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)

Çıkışı objdump -T true(çalışma zamanında dinamik olarak bağlı harici fonksiyonlar)

$ 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

5
Son zamanlarda 64kB + 2kB mikrokontrolcüsü ile programlama yapmış, 28kB kadar küçük görünmüyor ..
Barleyman

1
@Barleyman, OpenWRT, yocto, uClinux, uclib, busybox, microcoreutils ve bu tür ortamlar için diğer çözümlere sahiptir. Gönderiyi endişelerinizle düzenledi.
Rui F Ribeiro,

4
@Barleyman: İkili çalıştırılabilir boyut için optimizasyon yapıyorsanız , çalıştırılabilir kodu (4 x86 talimatı) ELF program başlığının içine yerleştirerek (herhangi bir komut satırı seçeneği için desteklemeden!) 45 baytlık x86 ELF çalıştırılabilir trueveya uygulayabilirsiniz . . Linux için Gerçekten Teensy ELF Yürütülebilirlerini Oluşturma Üzerine Bir Kasırga Eğitimi . (Ya da Linux ELF yükleyici uygulama detaylarına bağlı kalmaktan kaçınmak istiyorsanız biraz daha büyük: P)false
Peter Cordes

3
Gerçekten değil, hayır. Örneğin, Yocto 64kB'nin üzerinde yığın ve sınır olan bir megabayttan daha azına tıkılıp kalabiliyor. Bu tür bir cihazda rudimenter işlem / bellek yönetimi ile bir tür RTOS kullanabilirsiniz, ancak bunlar bile çok ağır olabilir. Basit bir işbirlikçi çok iş parçacıklı bir sistem yazdım ve kodun üzerine yazılmasını önlemek için yerleşik bellek korumasını kullandım. Hepsi şu an firmware’in 55kB’lık bir miktar tükettiğini, bu nedenle ek yük için fazla yer olmadığını söyledi. O
devasa 2kB

2
@PeterCordes elbette, ancak Linux uygun hale gelmeden önce birkaç kaynak daha fazla kaynağa ihtiyacınız var. Buna değer, C ++, o ortamda da gerçekten çalışmıyor. Zaten standart kütüphaneler değil. Iostream 200kB civarında.
Barleyman

34

Uygulama muhtemelen GNU coreutils'ten geliyor. Bu ikili dosyalar C'den derlenir; varsayılan olarak olduklarından daha küçük olmaları için özel bir çaba gösterilmemiştir.

trueKendinizin önemsiz uygulamasını derlemeye çalışabilirsiniz ve bunun zaten birkaç KB boyutunda olduğunu fark edeceksiniz. Örneğin, sistemimde:

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

Elbette, ikili dosyalarınız daha da büyük. Çünkü onlar komut satırı argümanlarını da destekliyorlar. /usr/bin/true --helpVeya çalışmayı deneyin /usr/bin/true --version.

Dize verilerine ek olarak, ikili komut satırı bayraklarını vb. Ayrıştırmak için mantık içerir. Görünüşe göre yaklaşık 20 KB kod ekler.

Başvuru için kaynak kodunu burada bulabilirsiniz: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/true.c


2
Bilginize ben onların hata izci bu coreutils uygulamaları hakkında şikayetçi oldu, ama şansı onu tamir için lists.gnu.org/archive/html/bug-coreutils/2016-03/msg00040.html
rudimeier

7
Argümanların mantığı değil, C etkisiz değil ... satır içi kütüphaneler / ev tutma görevleri. Kanlı ayrıntılar için cevabımı inceleyin.
Rui F Ribeiro

8
Bu, yanıltıcıdır, çünkü derlenmiş makine kodunun (C'den veya başka bir şekilde) büyük miktarda yer kapladığını gösterir - gerçek boyut ek yükünün, derleyici tarafından derlenen satırlarca sıralanan büyük miktarlarda standart C kitaplığı / çalışma zamanı kazan plakasıyla ilgisi vardır C kütüphanesiyle birlikte çalışmak için (glibc, sisteminizin muhtemelen başka bir şey kullandığını duymadığınız sürece) ve daha az bir ölçüde ELF başlıkları / meta verilerini (çoğu kesinlikle gerekli olmayan ancak yeterince değerli kabul edilen) varsayılan yapılara dahil etmek için).
mtraceur

2
Her iki fonksiyondaki gerçek main () + use () + karakter dizileri 20 KB değil 2KB civarındadır.
Rui F Ribeiro,

2
--Jversion / version işlevlerinde 1JdeBP mantığı 1KB, --usage / - help 833 bytes, main () 225 bytes ve binary'nin tüm statik verileri 1KB
Rui F Ribeiro

25

Onları çekirdek işlevsellikten çıkarmak ve assembler'da yazmak çok daha küçük ikili dosyalar üretir.

Orijinal doğru / yanlış ikili dosyalar, doğası gereği çeşitli kütüphane + sembol referanslarını çeken C dilinde yazılmıştır. Eğer çalıştırırsanız readelf -a /bin/truebu oldukça belirgindir.

Soyulmuş bir ELF statik çalıştırılabilir için 352 bayt (kod boyutu için asm optimize ederek bir kaç bayt kurtarmak için oda ile).

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

Veya, biraz kötü / ustaca bir yaklaşımla ( stalkr için şerefli ), kendi ELF başlıklarınızı yaratıp 132 127 bayta indirgeyin . Burada Code Golf bölgesine giriyoruz .

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

2
Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
terdon

2
Ayrıca bu mükemmel yazıyı
görün

3
Sıradışı ancak desteklenenint 0x80 64 bitlik bir yürütülebilir dosyada 32 bit ABI'yi kullanıyorsunuz . Kullanmak size hiçbir şey kazandırmaz. Yüksek baytlar yok sayılır, bu nedenle 2 bayt kullanabilirsiniz . Ya da elbette sıfır için . Tamsayı kayıtları inits sıfıra Linux, bu yüzden olabilir sadece 1 = __NR_exit (i386 ABI) alır. syscallebxmov bl,1xor ebx,ebxinc eax
Peter Cordes,

1
64-bit ABI'yi kullanmak için golflü örneğinizdeki kodu güncelledim ve 127 byte'a düşürdüm true. (Ben az 128 bayt yönetmek için kolay bir yol göremiyorum false32 bit ABI kullanarak veya Linux süreç başlangıçta kayıtlarını sıfırlar, böylece gerçeği yararlanarak dışındaki olsa, mov al,252(2 bayt) çalışır. push imm8/ pop rdiOlur leaayar yapmak yerine de çalışır edi=1, ancak hala 32-bit ABI’yi mov bl,1REX öneki olmadan yenemedik
Peter Cordes 0

2
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

Benim de 16.04 Ubuntu'mda oldukça büyük. tam olarak aynı boyutta? Onları bu kadar büyük yapan ne?

strings $(which true)

(alıntı:)

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, doğru ve yanlış için yardım var, hadi deneyelim:

true --help 
true --version
#

Hiçbir şey değil. Ah, şu diğer satır vardı:

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

Yani sistemimde, / bin / true, / usr / bin / true değil

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

Yani yardım var, versiyon bilgisi var, uluslararasılaştırma için bir kütüphaneye bağlanıyor. Bu, büyüklüğün çoğunu açıklar ve kabuk yine de çoğu zaman optimize edilmiş komutunu kullanır.


Statik kütüphaneler ve elf metadası için ikili boyutun yarısı dahil. Cevabımı gör.
Rui F Ribeiro,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.