martes, 20 de abril de 2010

Position Independent Code

El position independent code o código no dependiente de posición es aquel que se puede reubicar en memoria y aún así seguirá funcionando correctamente.

Por defecto, en Mac el código producido por gcc es PIC, pero se puede forzar a que produzca código no PIC con la opción -fno-pic.
Si tomamos por ejemplo el siguiente código en C.

#include<stdio.h>

void func(){
printf("Hello again\n");
}

int main(){
printf("Hello world\n");
func();

return 0;
}

Y lo compilamos como no PIC con la siguiente instrucción.

gcc -fno-pic -S program.c -o nopic.asm

Se obtiene.

.cstring
LC0:
.ascii "Hello again\0"
.text
.globl _func
_func:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $LC0, (%esp)
call _puts
leave
ret
.cstring
LC1:
.ascii "Hello world\0"
.text
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $LC1, (%esp)
call _puts
call _func
movl $0, %eax
leave
ret
.subsections_via_symbols

Se puede ver que la cadena almacenada en la línea 3 se referencia en la línea 10 de forma absoluta. Si cambia la ubicación del programa en memoria LC0 seguirá referenciando a la misma posición, pero allí ya no estará la cadena que se esperaba.

Por el contrario, si dejamos al compilador con las opciones por defecto, producirá código PIC, quedando de la siguiente forma.


.cstring
LC0:
.ascii "Hello again\0"
.text
.globl _func
_func:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call L3
"L00000000001$pb":
L3:
popl %ebx
leal LC0-"L00000000001$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub
addl $20, %esp
popl %ebx
leave
ret
.cstring
LC1:
.ascii "Hello world\0"
.text
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call L6
"L00000000002$pb":
L6:
popl %ebx
leal LC1-"L00000000002$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub
call _func
movl $0, %eax
addl $20, %esp
popl %ebx
leave
ret
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_puts$stub:
.indirect_symbol _puts
hlt ; hlt ; hlt ; hlt ; hlt
.subsections_via_symbols

En esta ocasión se puede ver que en la línea 15 se carga la cadena, pero de forma relativa, usando la diferencia entre la posición actual y la de la cadena. Además, se puede ver que hay unas nuevas directivas al incluir la función puts.

¿Por qué puede preferirse la generación de código no PIC? Pues observando los ejemplos se puede ver que generar código no dependiente de la posición del programa requiere más instrucciones en ensamblador y por tanto mayor tiempo a la hora de ejecutarse.

0 comentarios: