| Entendiendo el Mecanismo de Inicio (Initcall) del Kernel de Linux: Creando funciones Dinámicas de apuntadores de Llamadas a Tablas | ||
|---|---|---|
| <<< Anterior | Ejemplos Simples | Siguiente >>> |
Voy a comenzar con el código que habiamos dicho antes en la sección diseño de objetos para modificarlo un poco por eso ahora partes diferentes estaran en sus propias secciones ELF.
/*
* AUTHOR: Trevor Woerner
* START DATE: 11 September 2003 - 04:18:13 PM
* MODIFIED: 11 September 2003 - 04:24:48 PM
* FILENAME: sections.c
* PURPOSE: Sample code to demonstrate specifying the section
* in-which to place an object.
*
* Copyright (C) 2003 Trevor Woerner
*/
#include <stdio.h>
int add (int, int) __attribute__ ((section ("my_code_section")));
int global_val __attribute__ ((section ("my_data_section")));
int gval_init __attribute__ ((section ("my_data_section"))) = 29;
int add (int i, int j)
{
return i+j;
}
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;
}
|
Ahora hacemos un objdump -t y el siguiente es resultado que obtenemos (te explicare, los detalles de la salida entera. Alineada apropidamente por columnas y también las ordene para ti):
08048230 g F .init 00000000 _init
08048230 l d .init 00000000
08048248 l d .plt 00000000
08048258 F *UND* 000000fb __libc_start_main@@GLIBC_2.0
08048268 F *UND* 00000039 printf@@GLIBC_2.0
08048278 g F .text 00000000 _start
08048278 l d .text 00000000
0804829c l F .text 00000000 call_gmon_start
080482c0 l F .text 00000000 __do_global_dtors_aux
080482fc l F .text 00000000 frame_dummy
08048328 g F .text 0000006f main
08048398 g F .text 00000030 __libc_csu_init
080483c8 g F .text 00000034 __libc_csu_fini
080483fc l F .text 00000000 __do_global_ctors_aux
08048420 g *ABS* 00000000 __start_my_code_section
08048420 g F my_code_section 0000000b add
08048420 l d my_code_section 00000000
0804842b g *ABS* 00000000 __stop_my_code_section
0804842c g F .fini 00000000 _fini
0804842c l d .fini 00000000
08048460 g O .rodata 00000004 _fp_hw
08048460 l d .rodata 00000000
08048464 g O .rodata 00000004 _IO_stdin_used
080494c0 w .data 00000000 data_start
080494c0 g *ABS* 00000000 __fini_array_end
080494c0 g *ABS* 00000000 __fini_array_start
080494c0 g *ABS* 00000000 __init_array_end
080494c0 g *ABS* 00000000 __init_array_start
080494c0 g .data 00000000 __data_start
080494c0 l d .data 00000000
080494c4 g O .data 00000000 .hidden __dso_handle
080494c8 l O .data 00000000 p.0
080494cc g *ABS* 00000000 __start_my_data_section
080494cc g O my_data_section 00000004 gval_init
080494cc l d my_data_section 00000000
080494d0 g O my_data_section 00000004 global_val
080494d4 g *ABS* 00000000 __stop_my_data_section
080494d4 l O .eh_frame 00000000 __EH_FRAME_BEGIN__
080494d4 l O .eh_frame 00000000 __FRAME_END__
080494d4 l d .eh_frame 00000000
080494d8 g O .dynamic 00000000 _DYNAMIC
080494d8 l d .dynamic 00000000
080495a0 l O .ctors 00000000 __CTOR_LIST__
080495a0 l d .ctors 00000000
080495a4 l O .ctors 00000000 __CTOR_END__
080495a8 l O .dtors 00000000 __DTOR_LIST__
080495a8 l d .dtors 00000000
080495ac l O .dtors 00000000 __DTOR_END__
080495b0 l O .jcr 00000000 __JCR_END__
080495b0 l O .jcr 00000000 __JCR_LIST__
080495b0 l d .jcr 00000000
080495b4 g O .got 00000000 _GLOBAL_OFFSET_TABLE_
080495b4 l d .got 00000000
080495cc g *ABS* 00000000 __bss_start
080495cc g *ABS* 00000000 _edata
080495cc l O .bss 00000001 completed.1
080495cc l d .bss 00000000
080495d0 g *ABS* 00000000 _end
|
Corriendo el ejecutable nos da :
[trevor]$ ./sections
local_val: 25 global_val: 17 gval_init: 29
25 + 17 = 42
|
Lo primero que hay que notar es que : el ejecuable funciona!! (si!) La segunda cosa cosa que debes notar es de la existencia de nuevos nombres de secciones (my_code_section y my_data_section) En la imagen ejecutable. También debes darte cuenta que en esas secciones se encuentran objetos que hemos ubicado.
...
08048420 g *ABS* 00000000 __start_my_code_section
08048420 g F my_code_section 0000000b add
08048420 l d my_code_section 00000000
0804842b g *ABS* 00000000 __stop_my_code_section
...
080494cc g *ABS* 00000000 __start_my_data_section
080494cc g O my_data_section 00000004 gval_init
080494cc l d my_data_section 00000000
080494d0 g O my_data_section 00000004 global_val
080494d4 g *ABS* 00000000 __stop_my_data_section
...
|
Probablemente te hayas preguntado: "En la sección generada de abajo
my_data_section
Por qué esta primero el objeto gval_init ?".
Echandole un vistaso al ensamblador generado (gcc -S) nos ayudara a investigar esta pregunta
(los he re-ordenado un poco y añadido material para hacerlo mas fácil de seguir) :
.file "sections.c"
;---- SECTION my_data_section ----
.globl gval_init
.section my_data_section,"aw",@progbits
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.long 29
;---- SECTION my_code_section ----
.section my_code_section,"ax",@progbits
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
addl 8(%ebp), %eax
popl %ebp
ret
.size add, .-add
;---- SECTION .rodata ----
.section .rodata
.align 32
.LC0:
.string "local_val: %d global_val: %d gval_init: %d\n"
.LC1:
.string "%d + %d = %d\n"
;---- SECTION .text ----
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $25, -4(%ebp)
movl $17, global_val
movl gval_init, %eax
movl %eax, 12(%esp)
movl global_val, %eax
movl %eax, 8(%esp)
movl -4(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
movl global_val, %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, 12(%esp)
movl global_val, %eax
movl %eax, 8(%esp)
movl -4(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC1, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
;---- SECTION my_data_section ----
.globl global_val
.section my_data_section
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.zero 4
.ident "GCC: (GNU) 3.3"
|
Basicamente, la respuesta a la anterior pregunta "por qué gval_init terminó primero" es por que gcc los separo de esa forma. Si hacemos ambas del mismo tipo de variable global, podremos observar que gcc creara solo un segmento para ambas, y apareceran en nuestro segmento en el orden que se encontraron en el código fuente:
código:
int global_val __attribute__ ((section ("my_data_section")));
int gval_init __attribute__ ((section ("my_data_section")));
assembler: (al final del archivo)
.globl global_val
.section my_data_section,"aw",@progbits
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.zero 4
.globl gval_init
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.zero 4
objdump -t | sort:
080494cc g *ABS* 00000000 __start_my_data_section
080494cc g O my_data_section 00000004 global_val
080494cc l d my_data_section 00000000
080494d0 g O my_data_section 00000004 gval_init
080494d4 g *ABS* 00000000 __stop_my_data_section
|
code:
int gval_init __attribute__ ((section ("my_data_section")));
int global_val __attribute__ ((section ("my_data_section")));
assembler: (al final del archivo)
.globl gval_init
.section my_data_section,"aw",@progbits
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.zero 4
.globl global_val
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.zero 4
objdump -t | sort:
080494cc g *ABS* 00000000 __start_my_data_section
080494cc g O my_data_section 00000004 gval_init
080494cc l d my_data_section 00000000
080494d0 g O my_data_section 00000004 global_val
080494d4 g *ABS* 00000000 __stop_my_data_section
|
y similarmente:
code:
int global_val __attribute__ ((section ("my_data_section"))) = 27;
int gval_init __attribute__ ((section ("my_data_section"))) = 25;
assembler: (al principio del archivo)
.globl global_val
.section my_data_section,"aw",@progbits
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.long 27
.globl gval_init
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.long 25
objdump -t | sort:
080494cc g *ABS* 00000000 __start_my_data_section
080494cc g O my_data_section 00000004 global_val
080494cc l d my_data_section 00000000
080494d0 g O my_data_section 00000004 gval_init
080494d4 g *ABS* 00000000 __stop_my_data_section
|
code:
int gval_init __attribute__ ((section ("my_data_section"))) = 25;
int global_val __attribute__ ((section ("my_data_section"))) = 27;
assembler: (al principio del archivo)
.globl gval_init
.section my_data_section,"aw",@progbits
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.long 25
.globl global_val
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.long 27
objdump -t | sort:
080494cc g *ABS* 00000000 __start_my_data_section
080494cc g O my_data_section 00000004 gval_init
080494cc l d my_data_section 00000000
080494d0 g O my_data_section 00000004 global_val
080494d4 g *ABS* 00000000 __stop_my_data_section
|
| <<< Anterior | Inicio | Siguiente >>> |
| Sección de diseño de Objetos | Arriba | Como trabaja el mecanismo de Inicio (Initcall) del Kernel de Linux |