| Entendiendo el Mecanismo de Inicio (Initcall) del Kernel de Linux: Creando funciones Dinámicas de apuntadores de Llamadas a Tablas | ||
|---|---|---|
| <<< Anterior | Ejemplos Simples | Siguiente >>> |
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;
}
|
/*
* 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
|
Ahora voy a diseñar una sección .text en el archivo de salida, en este punto de la salida.
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).
Eso es seguido por todos las secciones.gnu.warning que encontre en los archivos de entrada.
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.
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
|
[trevor]$ gcc -o main add.o main.o
|
[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
|
| <<< Anterior | Inicio | Siguiente >>> |
| Ejemplos Simples | Arriba | Como Poner objetos dentro de sus propias secciones ELF |