Como poner objetos dentro de sus propias secciones ELF

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
...
       
Algo mas que es muy digno de notarse es el hecho de que ld ha sido suficientemente amabla de aƱadir un par de simbolos globales absolutos los cuales delimitan nuestras nuevas secciones-definidas, sin la necesidad de preguntarle a : __start_my_code_section/__stop_my_code_section y __start_my_data_section/__stop_my_data_section. Date cuenta como __start_my_code_section tiene la misma direccion de nuestra función add() y de que __start_my_data_section tiene la misma direcci&oacte;n de gval_init.

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"
       
Notese como las dos variables terminaron en diferentes secciones (pero las cuales tienen el mismo nombre). Por qué paso esto? No estoy 100% seguro por que. pero el subprograma de gcc que convierte el código C en assembler, originalmente establecio dos secciones diferentes para las dos variables, pero por que las dos secciones tenian el mismo nombre, terminaron juntas. No se por que los datos globales inicializados terminaron al comienzo y los datos no-inicializados a lo ultimo. Quizas esto es algo para explorar otro dia.

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