Ir para conteúdo

Um exemplo de, talvez, o menor executável (útil) que você pode escrever em C


fredericopissarra

Posts Recomendados

Estou falando, é claro do "hello, world" que, costumeiramente, é implementado assim:

#include <stdio.h>
  
int main( void ) { puts("hello, world" ); }

Dando uma olhada nesse código depois de compilado, vemos que existe um "porrilhão" (unidade universal de grandeza) de códigos extras no executável final, que ficou com 6 KiB sem a sessão simbólica:

$ cc -O2 -s -o hello hello.c

$ ls -go hello
-rwxr-xr-x 1 6120 mar 26 11:07 hello

$ objdump -s hello

hello:     file format elf64-x86-64

Contents of section .interp:
 0238 2f6c6962 36342f6c 642d6c69 6e75782d  /lib64/ld-linux-
 0248 7838362d 36342e73 6f2e3200           x86-64.so.2.    
Contents of section .note.ABI-tag:
 0254 04000000 10000000 01000000 474e5500  ............GNU.
 0264 00000000 03000000 02000000 00000000  ................
Contents of section .note.gnu.build-id:
 0274 04000000 14000000 03000000 474e5500  ............GNU.
 0284 ce3c7d83 da8babc9 c2bf71c8 7a698b0e  .<}.......q.zi..
 0294 44ad7e60                             D.~`            
Contents of section .gnu.hash:
 0298 01000000 01000000 01000000 00000000  ................
 02a8 00000000 00000000 00000000           ............    
Contents of section .dynsym:
 02b8 00000000 00000000 00000000 00000000  ................
 02c8 00000000 00000000 3d000000 20000000  ........=... ...
 02d8 00000000 00000000 00000000 00000000  ................
 02e8 0b000000 12000000 00000000 00000000  ................
 02f8 00000000 00000000 1f000000 12000000  ................
 0308 00000000 00000000 00000000 00000000  ................
 0318 59000000 20000000 00000000 00000000  Y... ...........
 0328 00000000 00000000 68000000 20000000  ........h... ...
 0338 00000000 00000000 00000000 00000000  ................
 0348 10000000 22000000 00000000 00000000  ...."...........
 0358 00000000 00000000                    ........        
Contents of section .dynstr:
 0360 006c6962 632e736f 2e360070 75747300  .libc.so.6.puts.
 0370 5f5f6378 615f6669 6e616c69 7a65005f  __cxa_finalize._
 0380 5f6c6962 635f7374 6172745f 6d61696e  _libc_start_main
 0390 00474c49 42435f32 2e322e35 005f4954  .GLIBC_2.2.5._IT
 03a0 4d5f6465 72656769 73746572 544d436c  M_deregisterTMCl
 03b0 6f6e6554 61626c65 005f5f67 6d6f6e5f  oneTable.__gmon_
 03c0 73746172 745f5f00 5f49544d 5f726567  start__._ITM_reg
 03d0 69737465 72544d43 6c6f6e65 5461626c  isterTMCloneTabl
 03e0 6500                                 e.              
Contents of section .gnu.version:
 03e2 00000000 02000200 00000000 0200      ..............  
Contents of section .gnu.version_r:
 03f0 01000100 01000000 10000000 00000000  ................
 0400 751a6909 00000200 31000000 00000000  u.i.....1.......
Contents of section .rela.dyn:
 0410 b80d2000 00000000 08000000 00000000  .. .............
 0420 50060000 00000000 c00d2000 00000000  P......... .....
 0430 08000000 00000000 10060000 00000000  ................
 0440 08102000 00000000 08000000 00000000  .. .............
 0450 08102000 00000000 d80f2000 00000000  .. ....... .....
 0460 06000000 01000000 00000000 00000000  ................
 0470 e00f2000 00000000 06000000 03000000  .. .............
 0480 00000000 00000000 e80f2000 00000000  .......... .....
 0490 06000000 04000000 00000000 00000000  ................
 04a0 f00f2000 00000000 06000000 05000000  .. .............
 04b0 00000000 00000000 f80f2000 00000000  .......... .....
 04c0 06000000 06000000 00000000 00000000  ................
Contents of section .rela.plt:
 04d0 d00f2000 00000000 07000000 02000000  .. .............
 04e0 00000000 00000000                    ........        
Contents of section .init:
 04e8 4883ec08 488b05f5 0a200048 85c07402  H...H.... .H..t.
 04f8 ffd04883 c408c3                      ..H....         
Contents of section .plt:
 0500 ff35ba0a 2000ff25 bc0a2000 0f1f4000  .5.. ..%.. ...@.
 0510 ff25ba0a 20006800 000000e9 e0ffffff  .%.. .h.........
Contents of section .plt.got:
 0520 ff25d20a 20006690                    .%.. .f.        
Contents of section .text:
 0530 488d3dad 01000048 83ec08e8 d0ffffff  H.=....H........
 0540 31c04883 c408c366 0f1f8400 00000000  1.H....f........
 0550 31ed4989 d15e4889 e24883e4 f050544c  1.I..^H..H...PTL
 0560 8d056a01 0000488d 0df30000 00488d3d  ..j...H......H.=
 0570 bcffffff ff15660a 2000f40f 1f440000  ......f. ....D..
 0580 488d3d89 0a200055 488d0581 0a200048  H.=.. .UH.... .H
 0590 39f84889 e5741948 8b053a0a 20004885  9.H..t.H..:. .H.
 05a0 c0740d5d ffe0662e 0f1f8400 00000000  .t.]..f.........
 05b0 5dc30f1f 4000662e 0f1f8400 00000000  ]...@.f.........
 05c0 488d3d49 0a200048 8d35420a 20005548  H.=I. .H.5B. .UH
 05d0 29fe4889 e548c1fe 034889f0 48c1e83f  ).H..H...H..H..?
 05e0 4801c648 d1fe7418 488b0501 0a200048  H..H..t.H.... .H
 05f0 85c0740c 5dffe066 0f1f8400 00000000  ..t.]..f........
 0600 5dc30f1f 4000662e 0f1f8400 00000000  ]...@.f.........
 0610 803df909 20000075 2f48833d d7092000  .=.. ..u/H.=.. .
 0620 00554889 e5740c48 8b3dda09 2000e8ed  .UH..t.H.=.. ...
 0630 feffffe8 48ffffff c605d109 2000015d  ....H....... ..]
 0640 c30f1f80 00000000 f3c3660f 1f440000  ..........f..D..
 0650 554889e5 5de966ff ffff660f 1f440000  UH..].f...f..D..
 0660 41574156 4989d741 5541544c 8d254607  AWAVI..AUATL.%F.
 0670 20005548 8d2d4607 20005341 89fd4989   .UH.-F. .SA..I.
 0680 f64c29e5 4883ec08 48c1fd03 e857feff  .L).H...H....W..
 0690 ff4885ed 742031db 0f1f8400 00000000  .H..t 1.........
 06a0 4c89fa4c 89f64489 ef41ff14 dc4883c3  L..L..D..A...H..
 06b0 014839dd 75ea4883 c4085b5d 415c415d  .H9.u.H...[]A\A]
 06c0 415e415f c390662e 0f1f8400 00000000  A^A_..f.........
 06d0 f3c3                                 ..              
Contents of section .fini:
 06d4 4883ec08 4883c408 c3                 H...H....       
Contents of section .rodata:
 06e0 01000200 68656c6c 6f2c2077 6f726c64  ....hello, world
 06f0 00                                   .               
Contents of section .eh_frame_hdr:
 06f4 011b033b 38000000 06000000 0cfeffff  ...;8...........
 0704 84000000 2cfeffff ac000000 3cfeffff  ....,.......<...
 0714 c4000000 5cfeffff 54000000 6cffffff  ....\...T...l...
 0724 dc000000 dcffffff 24010000           ........$...    
Contents of section .eh_frame:
 0730 14000000 00000000 017a5200 01781001  .........zR..x..
 0740 1b0c0708 90010710 14000000 1c000000  ................
 0750 00feffff 2b000000 00000000 00000000  ....+...........
 0760 14000000 00000000 017a5200 01781001  .........zR..x..
 0770 1b0c0708 90010000 24000000 1c000000  ........$.......
 0780 80fdffff 20000000 000e1046 0e184a0f  .... ......F..J.
 0790 0b770880 003f1a3b 2a332422 00000000  .w...?.;*3$"....
 07a0 14000000 44000000 78fdffff 08000000  ....D...x.......
 07b0 00000000 00000000 14000000 5c000000  ............\...
 07c0 70fdffff 17000000 004b0e10 4b0e0800  p........K..K...
 07d0 44000000 74000000 88feffff 65000000  D...t.......e...
 07e0 00420e10 8f02420e 188e0345 0e208d04  .B....B....E. ..
 07f0 420e288c 05480e30 8606480e 3883074d  B.(..H.0..H.8..M
 0800 0e40720e 38410e30 410e2842 0e20420e  .@r.8A.0A.(B. B.
 0810 18420e10 420e0800 10000000 bc000000  .B..B...........
 0820 b0feffff 02000000 00000000 00000000  ................
Contents of section .init_array:
 200db8 50060000 00000000                    P.......        
Contents of section .fini_array:
 200dc0 10060000 00000000                    ........        
Contents of section .dynamic:
 200dc8 01000000 00000000 01000000 00000000  ................
 200dd8 0c000000 00000000 e8040000 00000000  ................
 200de8 0d000000 00000000 d4060000 00000000  ................
 200df8 19000000 00000000 b80d2000 00000000  .......... .....
 200e08 1b000000 00000000 08000000 00000000  ................
 200e18 1a000000 00000000 c00d2000 00000000  .......... .....
 200e28 1c000000 00000000 08000000 00000000  ................
 200e38 f5feff6f 00000000 98020000 00000000  ...o............
 200e48 05000000 00000000 60030000 00000000  ........`.......
 200e58 06000000 00000000 b8020000 00000000  ................
 200e68 0a000000 00000000 82000000 00000000  ................
 200e78 0b000000 00000000 18000000 00000000  ................
 200e88 15000000 00000000 00000000 00000000  ................
 200e98 03000000 00000000 b80f2000 00000000  .......... .....
 200ea8 02000000 00000000 18000000 00000000  ................
 200eb8 14000000 00000000 07000000 00000000  ................
 200ec8 17000000 00000000 d0040000 00000000  ................
 200ed8 07000000 00000000 10040000 00000000  ................
 200ee8 08000000 00000000 c0000000 00000000  ................
 200ef8 09000000 00000000 18000000 00000000  ................
 200f08 1e000000 00000000 08000000 00000000  ................
 200f18 fbffff6f 00000000 01000008 00000000  ...o............
 200f28 feffff6f 00000000 f0030000 00000000  ...o............
 200f38 ffffff6f 00000000 01000000 00000000  ...o............
 200f48 f0ffff6f 00000000 e2030000 00000000  ...o............
 200f58 f9ffff6f 00000000 03000000 00000000  ...o............
 200f68 00000000 00000000 00000000 00000000  ................
 200f78 00000000 00000000 00000000 00000000  ................
 200f88 00000000 00000000 00000000 00000000  ................
 200f98 00000000 00000000 00000000 00000000  ................
 200fa8 00000000 00000000 00000000 00000000  ................
Contents of section .got:
 200fb8 c80d2000 00000000 00000000 00000000  .. .............
 200fc8 00000000 00000000 16050000 00000000  ................
 200fd8 00000000 00000000 00000000 00000000  ................
 200fe8 00000000 00000000 00000000 00000000  ................
 200ff8 00000000 00000000                    ........        
Contents of section .data:
 201000 00000000 00000000 08102000 00000000  .......... .....
Contents of section .comment:
 0000 4743433a 20285562 756e7475 20372e33  GCC: (Ubuntu 7.3
 0010 2e302d32 37756275 6e747531 7e31382e  .0-27ubuntu1~18.
 0020 30342920 372e332e 3000               04) 7.3.0.

Reparou que a sessão .text ficou grande pacas? E, mesmo sem a declaração de variáveis globais temos uma sessão .data? E todos as outras sections, huh?

Acontece que um bom compilador C suporta dois tipos de "aplicação": hosted e freestanding. A primeira é direcionada ao sistema operacional e usa, por default, a "biblioteca padrão", ou seja, libc. A segunda "fica em pé, livre", ou seja, cria código que não usa a biblioteca padrão... No segundo caso, não podemos usar nenhuma função de libc ou qualquer biblioteca relacionada ao sistema operacional.

Eis um código (usando o macete que mostrei previamente) freestanding, do mesmo hello.c:

/* hello.c */

#define STDOUT_FILENO 1

// NOTA: Por algum motivo esquisito,
//       Códigos em asm diretos assim
//       não admitem a prefixação com %% para
//       os registradores. Apenas um %!
__asm__ (
  "\n"
  "# O gas precisa saber que existe um símbolo main\n"
  "# e que _start deve ser exportado para o linker.\n\t"
  ".extern main\n\t"
  ".globl _start\n"
  "\n"
  "# este é o ponto de entrada do executável\n"
  "_start:\n"
  "  call main\n"
  "  movl %eax,%edi\n"
  "  movl $60,%eax\n"
  "  syscall"
);

// Protótipo de nossa função puts()...
static void io_puts ( char *, int );

// Nossa função main().
int main ( void )
{
  io_puts ( "hello, world\n", STDOUT_FILENO );
  return 0;
}

void io_puts ( char *s, int fd )
{
  char *p;

  // Pega o ponteiro para o NUL char,
  // para calcular o tamanho da string.
  p = s;
  while ( *p )
    p++;

  // Só para garantir que strings vazias não serão impressas!
  // Acho que a syscall aceita isso se RDX for 0, mas não tenho
  // certeza.
  if ( p == s )
    return;

  // Usa a write syscall para escrever a string.
  __asm__ (
    "movl $1,%%eax\n\t"
    "syscall" :
    : "D" ( fd ), "S" ( s ), "d" ( p - s )
    : "rax"  // clobbered RAX!
  );
}

Agora é só questão de compilar e linkar, com algum cuidado. Eis o Makefile:

# Makefile
CFLAGS=-O2 -ffreestanding

# A cópia de apenas as sessões .text e .rodata é
# específica para este código. Você pode ter que copiar
# .data, .bss e outras sessões, dependendo do seu código.
_hello: hello.o
	ld -nostdlib -o $@ $^
	objcopy -j .text -j .rodata $@ hello
	rm $@

hello.o: hello.c

Note a opção -ffreestanding para o compilador C e a opção -nostdlib para o linker. Aqui, também, observe que nosso código não usa nenhuma variável global e, por isso, não tem uma sessão .data, mas a string "hello, world\n" é uma constante, literal, que é colocada em .rodata... Então, das poucas sessões contidas no arquivo ELF, copiei apenas a .text e .rodata e eliminei todo o resto:

$ make
cc -O2 -ffreestanding -c -o hello.o hello.c
ld -nostdlib -o _hello hello.o
objcopy -j .text -j .rodata _hello hello
rm _hello

$ objdump -s hello

hello:     file format elf64-x86-64

Contents of section .text:
 4000b0 488d3537 00000048 89f2660f 1f440000  H.57...H..f..D..
 4000c0 4883c201 803a0075 f74839f2 740f4829  H....:.u.H9.t.H)
 4000d0 f2bf0100 0000b801 0000000f 0531c0c3  .............1..
 4000e0 e8cbffff ff89c7b8 3c000000 0f05      ........<.....  
Contents of section .rodata:
 4000ee 68656c6c 6f2c2077 6f726c64 0a00      hello, world..
 
$ ./hello
hello, world

O novo arquivo tem, exatamente 816 bytes, sendo que as duas sessões, juntas, têm apenas 84 bytes!

Link para o comentário
Compartilhar em outros sites

  • 4 semanas depois...

Que legal! Ficou muito bom, parabéns! ?

Tem um trabalho similar (usado /NODEFAULTLIB no linker da Microsoft) pra executáveis PE, mas o texto não sugere implementar uma puts() não: só foca no tamanho do executável mesmo.

https://webserver2.tecgraf.puc-rio.br/~ismael/Cursos/YC++/apostilas/win32_xcoff_pe/tyne-example/Tiny PE.htm

Link para o comentário
Compartilhar em outros sites

  • 1 mês depois...
  • 10 meses depois...

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...