Efecto de los enlaces estáticos y dinámicos en la dirección de inicio

Efecto de los enlaces estáticos y dinámicos en la dirección de inicio

Tengo un programa C simple. Corro:

$ gcc Q1.c -Wall -save-temps -o Q1

Luego inspecciono el ejecutable generado:

$  objdump -f Q1
Q1:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x080483b0

Luego lo compilo con enlaces estáticos:

$ gcc Q1.c -Wall -save-temps -static -o Q1

e inspeccionar el archivo nuevamente:

$ objdump -f Q1
Q1:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048e08

¿Qué efecto tienen los enlaces estáticos y dinámicos en la dirección de inicio del programa? La dirección inicial es la dirección de main(), ¿verdad?

Respuesta1

La dirección inicial es la dirección de main(), ¿verdad?

Realmente no: el inicio de un programa no es realmente main()... De forma predeterminada, GCC producirá ejecutables cuya dirección inicial corresponde al _startsímbolo. Puedes verlo haciendo un objdump --disassemble Q1. Aquí está el resultado de un programa mío simple que solo funciona return 0;en main():

0000000000400e30 <_start>:
  400e30:       31 ed                   xor    %ebp,%ebp
  400e32:       49 89 d1                mov    %rdx,%r9
  400e35:       5e                      pop    %rsi
  400e36:       48 89 e2                mov    %rsp,%rdx
  400e39:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  400e3d:       50                      push   %rax
  400e3e:       54                      push   %rsp
  400e3f:       49 c7 c0 a0 15 40 00    mov    $0x4015a0,%r8
  400e46:       48 c7 c1 10 15 40 00    mov    $0x401510,%rcx
  400e4d:       48 c7 c7 40 0f 40 00    mov    $0x400f40,%rdi
  400e54:       e8 f7 00 00 00          callq  400f50 <__libc_start_main>
  400e59:       f4                      hlt    
  400e5a:       66 90                   xchg   %ax,%ax
  400e5c:       0f 1f 40 00             nopl   0x0(%rax)

Como puede ver en la dirección 400e54, _start()a su vez invoca __libc_start_main, que inicializa lo necesario (pthreads, atexit,...) y finalmente llama main()con los argumentos apropiados (argc, argv y env).

Bien, pero ¿qué tiene que ver con el cambio de dirección inicial?

Cuando pides gccvincular estáticamente, significa que toda la inicialización que mencioné anteriormente debe realizarse utilizando funciones que están en el ejecutable. Y, de hecho, si observa los tamaños de ambos ejecutables, encontrará que la versión estática es mucho más grande. En mi prueba, la versión estática es de 800K mientras que la versión compartida es de solo 6K.

Las funciones adicionales se colocan antes _start(), de ahí el cambio en la dirección inicial. Aquí está el diseño del ejecutable estático start():

000000000049e960 r translit_from_tbl
0000000000400a76 t _i18n_number_rewrite
0000000000400bc0 t fini
0000000000400bd0 t init_cacheinfo
0000000000400e30 T _start
0000000000400e60 t deregister_tm_clones
0000000000400e90 t register_tm_clones
0000000000400ed0 t __do_global_dtors_aux

Y aquí está el diseño del ejecutable compartido:

00000000004003c0 T _start
00000000004003f0 t deregister_tm_clones
00000000004004b0 T main
00000000004004c0 T __libc_csu_init
00000000006008a0 B _end
0000000000400370 T _init

Como resultado, obtengo direcciones de inicio ligeramente diferentes: 0x400e30 en el caso estático y 0x4003c0 en el caso compartido.

información relacionada