Seccion de diseño de Objetos

Para este ejemplo vamos a compilar ./main compuesta por main.c y add.c:

/*
 *     AUTHOR: Trevor Woerner
 * START DATE: 05 September 2003 - 03:26:51 PM
 *   MODIFIED: 09 September 2003 - 01:52:12 PM
 *   FILENAME: main.c
 *    PURPOSE: Simple 'main.c' with different objects to explore linking.
 *
 * Copyright (C) 2003  Trevor Woerner
 */

#include <stdio.h>

int add (int, int);
int global_val;
int gval_init = 0;

int
main (void)
{
	int local_val = 25;
	global_val = 17;

	printf ("local_val: %d    global_val: %d    gval_init: %d\n",
			local_val, global_val, gval_init);
	printf ("%d + %d = %d\n", local_val, global_val,
			add (local_val, global_val));

	return 0;
}
       
A propósito, se agregaron las variables local_val, gval_init, y global_val para que pudieramos ver cuales secciones terminan en ellas.

/*
 *     AUTHOR: Trevor Woerner
 * START DATE: 05 September 2003 - 03:28:48 PM
 *   MODIFIED: 05 September 2003 - 06:13:42 PM
 *   FILENAME: add.c
 *    PURPOSE: The 'add()' function.
 *
 * Copyright (C) 2003  Trevor Woerner
 */

int
add (int i, int j)
{
	return i+j;
}
       

La compilación es un proceso simple:

[trevor]$ gcc -c add.c
[trevor]$ gcc -c main.c
[trevor]$ gcc -o main main.o add.o
       

Aquí esta la informacion del volcado de add.o:

[trevor]$ objdump -t add.o

add.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*     00000000 add.c
00000000 l    d  .text     00000000 
00000000 l    d  .data     00000000 
00000000 l    d  .bss      00000000 
00000000 l    d  .comment  00000000 
00000000 g     F .text     0000000b add

       

Aquí esta un volcado similar de main.o:

[trevor]$ objdump -t main.o

main.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*     00000000 main.c
00000000 l    d  .text     00000000 
00000000 l    d  .data     00000000 
00000000 l    d  .bss      00000000 
00000000 l    d  .rodata   00000000 
00000000 l    d  .comment  00000000 
00000000 g     O .bss      00000004 gval_init
00000000 g     F .text     00000081 main
00000004       O *COM*     00000004 global_val
00000000         *UND*     00000000 printf
00000000         *UND*     00000000 add

       

Y aquí esta el volcado del ejecutable final usando objdump -t

[trevor]$ objdump -t main
main:     file format elf32-i386

SYMBOL TABLE:
080480f4 l    d  .interp	00000000              
08048108 l    d  .note.ABI-tag	00000000              
08048128 l    d  .hash	00000000              
08048150 l    d  .dynsym	00000000              
080481a0 l    d  .dynstr	00000000              
080481ec l    d  .gnu.version	00000000              
080481f8 l    d  .gnu.version_r	00000000              
08048218 l    d  .rel.dyn	00000000              
08048220 l    d  .rel.plt	00000000              
08048230 l    d  .init	00000000              
08048248 l    d  .plt	00000000              
08048280 l    d  .text	00000000              
08048470 l    d  .fini	00000000              
080484a0 l    d  .rodata	00000000              
08049500 l    d  .data	00000000              
0804950c l    d  .eh_frame	00000000              
08049510 l    d  .dynamic	00000000              
080495d8 l    d  .ctors	00000000              
080495e0 l    d  .dtors	00000000              
080495e8 l    d  .jcr	00000000              
080495ec l    d  .got	00000000              
08049604 l    d  .bss	00000000              
00000000 l    d  .comment	00000000              
00000000 l    d  .debug_aranges	00000000              
00000000 l    d  .debug_pubnames	00000000              
00000000 l    d  .debug_info	00000000              
00000000 l    d  .debug_abbrev	00000000              
00000000 l    d  .debug_line	00000000              
00000000 l    d  .debug_frame	00000000              
00000000 l    d  .debug_str	00000000              
00000000 l    d  *ABS*	00000000              
00000000 l    d  *ABS*	00000000              
00000000 l    d  *ABS*	00000000              
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/config.h
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              <built-in>
00000000 l    df *ABS*	00000000              abi-note.S
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/abi-tag.h
00000000 l    df *ABS*	00000000              abi-note.S
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/config.h
00000000 l    df *ABS*	00000000              abi-note.S
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/config.h
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              <built-in>
00000000 l    df *ABS*	00000000              abi-note.S
00000000 l    df *ABS*	00000000              init.c
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/crti.S
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/defs.h
00000000 l    df *ABS*	00000000              initfini.c
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/crti.S
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/config.h
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              <built-in>
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/crti.S
080482a4 l     F .text	00000000              call_gmon_start
00000000 l    df *ABS*	00000000              crtstuff.c
080495d8 l     O .ctors	00000000              __CTOR_LIST__
080495e0 l     O .dtors	00000000              __DTOR_LIST__
080495e8 l     O .jcr	00000000              __JCR_LIST__
08049508 l     O .data	00000000              p.0
08049604 l     O .bss	00000001              completed.1
080482d0 l     F .text	00000000              __do_global_dtors_aux
08048310 l     F .text	00000000              frame_dummy
00000000 l    df *ABS*	00000000              crtstuff.c
080495dc l     O .ctors	00000000              __CTOR_END__
080495e4 l     O .dtors	00000000              __DTOR_END__
0804950c l     O .eh_frame	00000000              __FRAME_END__
080495e8 l     O .jcr	00000000              __JCR_END__
08048440 l     F .text	00000000              __do_global_ctors_aux
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/crtn.S
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/defs.h
00000000 l    df *ABS*	00000000              initfini.c
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/crtn.S
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/config.h
00000000 l    df *ABS*	00000000              <command line>
00000000 l    df *ABS*	00000000              <built-in>
00000000 l    df *ABS*	00000000              /usr/src/build/231499-i386/BUILD/glibc-2.3.2-20030313/build-i386-linux/csu/crtn.S
00000000 l    df *ABS*	00000000              add.c
00000000 l    df *ABS*	00000000              main.c
08049510 g     O .dynamic	00000000              _DYNAMIC
0804960c g     O .bss	00000004              global_val
080484a0 g     O .rodata	00000004              _fp_hw
08049500 g       *ABS*	00000000              __fini_array_end
08049504 g     O .data	00000000              .hidden __dso_handle
08048404 g     F .text	00000034              __libc_csu_fini
08048230 g     F .init	00000000              _init
08048344 g     F .text	0000000b              add
08049608 g     O .bss	00000004              gval_init
08048280 g     F .text	00000000              _start
08049500 g       *ABS*	00000000              __fini_array_start
080483d4 g     F .text	00000030              __libc_csu_init
08049604 g       *ABS*	00000000              __bss_start
08048350 g     F .text	00000081              main
08048258       F *UND*	000000fb              __libc_start_main@@GLIBC_2.0
08049500 g       *ABS*	00000000              __init_array_end
08049500  w      .data	00000000              data_start
08048268       F *UND*	00000039              printf@@GLIBC_2.0
08048470 g     F .fini	00000000              _fini
08049604 g       *ABS*	00000000              _edata
080495ec g     O .got	00000000              _GLOBAL_OFFSET_TABLE_
08049610 g       *ABS*	00000000              _end
08049500 g       *ABS*	00000000              __init_array_start
080484a4 g     O .rodata	00000004              _IO_stdin_used
08049500 g       .data	00000000              __data_start
00000000  w      *UND*	00000000              _Jv_RegisterClasses
00000000  w      *UND*	00000000              __gmon_start__

       

Lo interesante para mi es como una pequeña cantidad de codigo genera tan elevado número de segmentos!. Dese cuenta como ambos archivos *.o contienen segmentos..text, .data, y .bss Cuando se combinan en el ejecutable main, este aun contiene esos segmentos (explico, no distingue de donde provienen las partes especificas, todas se combinan en un segmento mas grande con el mismo nombre).

Si queremos saber como fue usado el script del enlazador (para encontrar como ld diseña todas las secciones), todo lo que tenemos que hacer es pasarle bandera --verbose al comando ld via gcc (como esta: gcc -Wl,--verbose ...) entonces, obtendremos el script del enlazador en stderr. Aquí este el script del enlazador, que obtuve para este código; :

/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
	      "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
/* Do we need any of these for elf?
   __DYNAMIC = 0;    */
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  . = 0x08048000 + SIZEOF_HEADERS;
  .interp         : { *(.interp) }
  .hash           : { *(.hash) }
  .dynsym         : { *(.dynsym) }
  .dynstr         : { *(.dynstr) }
  .gnu.version    : { *(.gnu.version) }
  .gnu.version_d  : { *(.gnu.version_d) }
  .gnu.version_r  : { *(.gnu.version_r) }
  .rel.dyn        :
    {
      *(.rel.init)
      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
      *(.rel.fini)
      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
      *(.rel.ctors)
      *(.rel.dtors)
      *(.rel.got)
      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
    }
  .rela.dyn       :
    {
      *(.rela.init)
      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
      *(.rela.fini)
      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
      *(.rela.ctors)
      *(.rela.dtors)
      *(.rela.got)
      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
    }
  .rel.plt        : { *(.rel.plt) }
  .rela.plt       : { *(.rela.plt) }
  .init           :
  {
    KEEP (*(.init))
  } =0x90909090
  .plt            : { *(.plt) }
  .text           :
  {
    *(.text .stub .text.* .gnu.linkonce.t.*)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } =0x90909090
  .fini           :
  {
    KEEP (*(.fini))
  } =0x90909090
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
  .rodata1        : { *(.rodata1) }
  .eh_frame_hdr : { *(.eh_frame_hdr) }
  /* Adjust the address for the data segment.  We want to adjust up to
     the same address within the page on the next page up.  */
  . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1)); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000);
  /* Ensure the __preinit_array_start label is properly aligned.  We
     could instead move the label definition inside the section, but
     the linker would then create the section even if it turns out to
     be empty, which isn't pretty.  */
  . = ALIGN(32 / 8);
  PROVIDE (__preinit_array_start = .);
  .preinit_array     : { *(.preinit_array) }
  PROVIDE (__preinit_array_end = .);
  PROVIDE (__init_array_start = .);
  .init_array     : { *(.init_array) }
  PROVIDE (__init_array_end = .);
  PROVIDE (__fini_array_start = .);
  .fini_array     : { *(.fini_array) }
  PROVIDE (__fini_array_end = .);
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
  .data1          : { *(.data1) }
  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
  .eh_frame       : { KEEP (*(.eh_frame)) }
  .gcc_except_table   : { *(.gcc_except_table) }
  .dynamic        : { *(.dynamic) }
  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin*.o(.ctors))
    /* We don't want to include the .ctor section from
       from the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }
  .dtors          :
  {
    KEEP (*crtbegin*.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  }
  .jcr            : { KEEP (*(.jcr)) }
  .got            : { *(.got.plt) *(.got) }
  _edata = .;
  PROVIDE (edata = .);
  __bss_start = .;
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.  */
   . = ALIGN(32 / 8);
  }
  . = ALIGN(32 / 8);
  _end = .;
  PROVIDE (end = .);
  . = DATA_SEGMENT_END (.);
  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
}
       

Esto puede verse un poco dificil de leer, pero no lo es. Texto con /* y */, es el mismo código en C, que indica comentarios los cuales son ignorados. Un punto por si mismo ., es el mismo que en la notación assembler, indica el valor actual de la locacion de un contador.

El inicio del archivo es un grupo de material de mantenimiento. Entonces este proporciona el comando SECTIONS el cual inidica el inicio del script que define como se van a diseñar las secciones en la salida del archivo ELF. Como ejemplo. vamos a ver las siguientes lineas de código las cuales diseñaron la parte de .text de la imagen (explico, la parte donde de ubica el código ejecutable) :

.text           :
{
  *(.text .stub .text.* .gnu.linkonce.t.*)
  /* .gnu.warning sections are handled specially by elf32.em.  */
  *(.gnu.warning)
} =0x90909090
       
El recuadro dice:

  1. Ahora voy a diseñar una sección .text en el archivo de salida, en este punto de la salida.

  2. Esta sección estara compuesta de todos las secciones .text, .stub, .text.*, y .gnu.linkonce.t.* que encontre (en ese orden) de todos los archivos de entrada que se me dieron (el * antes de la lista en parentesís indica los archivos de entrada a considerar).

  3. Eso es seguido por todos las secciones.gnu.warning que encontre en los archivos de entrada.

  4. El =0x90909090 escrito al final de las descripciones de las secciones me dice el patron de llenado a usar si hay algún espacio entre secciones (mayormente debido a constantes de alineamiento).

En la siguiente figura tengo que poner el script del enlazador en la derecha e iniciar desde la salida de objdump -t en la izquierda. Dese cuenta cuan parefecto se alinean (he añadido espacios y flechas para ayudar a la comparación). Esto pasa por que el diseño del ejecutable es controlado por el script.

Figura 1. Script del Enlazador y Comparación con objdump -t

Solo jugando y experimentando algo más, aquí esta de nuevo el objdump -t del ejecutable, sin la mayoria de "cruft", y ordenados por dirección :

[trevor]$ objdump -t main
08048110 g     F .text          00000000              _start
08048110 l    d  .text          00000000              
08048134 l     F .text          00000000              call_gmon_start
08048160 l     F .text          00000000              __do_global_dtors_aux
080481a0 l     F .text          00000000              frame_dummy
080481d4 g     F .text          00000081              main
08048258 g     F .text          0000000b              add
08048264 g     F .text          00000030              __libc_csu_init
08048294 g     F .text          00000034              __libc_csu_fini
080482d0 l     F .text          00000000              __do_global_ctors_aux
       
Si cambio la linea de compilación por la siguiente :
[trevor]$ gcc -o main add.o main.o
       
Miren como cambian de lugar en la imagen ejecutable las posiciones de las funciones main() y add() :
[trevor]$ objdump -t main
08048280 g     F .text  00000000              _start
08048280 l    d  .text  00000000              
080482a4 l     F .text  00000000              call_gmon_start
080482d0 l     F .text  00000000              __do_global_dtors_aux
08048310 l     F .text  00000000              frame_dummy
08048344 g     F .text  0000000b              add
08048350 g     F .text  00000081              main
080483d4 g     F .text  00000030              __libc_csu_init
08048404 g     F .text  00000034              __libc_csu_fini
08048440 l     F .text  00000000              __do_global_ctors_aux
       
Esto sucede por que el script del enlazador, cuando crea la sección .text , hace un comodín en todas las secciones .text y las junta en un sola seccion .text en el orden que fueron encontradas. Durante la primera compilación especificamos el orden como main.o seguido por add.o; por lo tanto los simbolos fueron ubicados en el ejecutable comenzando con los simbolos de main.o seguidos por los simbolos de add.o. En el segundo caso especificamos los achivos objeto en orden inverso, por lo tanto los simbolos fueron almacenados el ejecutable en orden inverso también.