sábado, 3 de julio de 2010

Stack

La pila (Stack) es una región de la memoria, la cual es una estructura de datos LIFO (Ya se explicó lo que es LIFO en una entrada anterior).

Recordamos también que sobre una pila podemos aplicar 2 acciones: PUSH y POP.

La región de la pila tiene diversas misiones muy importantes para el buen funcionamiento de cualquier programa. Una de ellas es el control del programa cada vez que éste llama a una función, ya que al llamar a la función o procedimiento el programa llama a la dirección de memoria que corresponde con la función que quiere procesar en ese momento, y cuando ésta acaba, a través de la pila se devuelve el control al programa principal. Además de esto, la pila se utiliza para asignar memoria dinámica para las variables locales de las funciones, los parámetros y los valores de retorno de las mismas.

En la cabecera de la pila existe un segmento denominado SP (Stack Pointer), que es el puntero de la pila y apunta a la parte superior de la misma. La pila es ajustada automáticamente por el núcleo del sistema operativo y esto se lleva a cabo por medio de las instrucciones POP y PUSH.

La pila está dividida en segmentos, que se crean cuando se llama a una función, y se eliminan cuando dicha función termina.


Examinemos esto con un ejemplo en C;

#include <stdio.h>

void hola();
void adios();

int main(void)
{
printf("Llamamos al procedimiento hola()\n");
hola();
printf("Ahora llamamos a adiós()\n");
adios();
printf("Final del programa principal\n");
return 0;
}

void hola()
{
printf("Estamos dentro de Hola()\n");
}

void adios()
{
printf("Estamos dentro de Adiós()\n");
}

Observamos lo que pasa al usar gdb tras compilar:

Dump of assembler code for function main:
0x080483e4 <+0>: push %ebp
0x080483e5 <+1>: mov %esp,%ebp
0x080483e7 <+3>: and $0xfffffff0,%esp
0x080483ea <+6>: sub $0x10,%esp
0x080483ed <+9>: movl $0x8048510,(%esp)
0x080483f4 <+16>: call 0x8048318 <puts@plt>
0x080483f9 <+21>: call 0x8048422 <hola>
0x080483fe <+26>: movl $0x8048531,(%esp)
0x08048405 <+33>: call 0x8048318 <puts@plt>
0x0804840a <+38>: call 0x8048436 <adios>
0x0804840f <+43>: movl $0x804854b,(%esp)
0x08048416 <+50>: call 0x8048318 <puts@plt>
0x0804841b <+55>: mov $0x0,%eax
0x08048420 <+60>: leave
0x08048421 <+61>: ret
End of assembler dump.


El 1º elemento en negrita, push.

Los demás elementos en negrita, call, son llamadas a las funciones "puts" "hola" y "adios". Veamos que pasa al llamar a hola.

Dump of assembler code for function hola:
0x08048422 <+0>: push %ebp
0x08048423 <+1>: mov %esp,%ebp
0x08048425 <+3>: sub $0x18,%esp
0x08048428 <+6>: movl $0x8048568,(%esp)
0x0804842f <+13>: call 0x8048318 <puts@plt>
0x08048434 <+18>: leave
0x08048435 <+19>: ret
End of assembler dump.


Como vemos, al llamar a la función, introducimos el registro en la pila.

Ahora destacamos "leave" lo cual equivale a:

mov esp, ebp
pop ebp

Observando esto, podemos ver como usa la pila el sistema.

1 comentario: