Anda di halaman 1dari 10

Generacin de cdigo para funciones

Ejemplo introductorio: escritura de funciones en NASM


cdigo equivalente
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Ejemplo introductorio: escritura de funciones en NASM
cdigo equivalente cero(); end ret main: call _cero add esp, 0
Marina de la Cruz Alfonso Ortega

En estas transparencias pondremos una subrutina ASPLE y la generacin de

En estas transparencias pondremos una subrutina ASPLE y la generacin de

function int cero() begin return 0 end

_cero: push ebp mov ebp, esp sub esp, 0 push dword 0 pop eax mov esp, ebp pop ebp ret

begin

Prcticas de compiladores 2004-2005

Prcticas de compiladores 2004-2005

Generacin de cdigo para funciones


Condiciones para subrutinas recursivas y reentrantes
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: conceptos preliminares
Marina de la Cruz Alfonso Ortega

Una subrutina reentrante [deMiguel01] es aqulla que puede ser llamada dessde
varios puntos simultneamente sin modificar su comportamiento Una subrutina recursiva es aqulla que puede llamarse a s misma, por lo tanto, una subrutina recursiva necesariamente tiene que ser reentrante. Las condiciones para que una subrutina sea recursiva y reentrante son las mismas. Las condiciones necesarias para que una subrutina sea recursiva y reentrante tiene que ver con que los datos utilizados por ellas no estn contenidos en posiciones fijas de memoria. Por lo tanto es suficiente con utilizar la pila para almacenar datos globales, locales y parmetros.

Para llamar a una subrutina se cumple los que se conoce como convenio de
llamadas que debe ser especificado explcitamente al disear el compilador.

El convenio de llamadas tiene que dar respuesta a las siguientes preguntas:


Cmo se comunican los argumentos desde el programa llamante a la funcin llamada? Cmo se comunican los resultados desde la funcin llamada hasta el programa llamante?

Se recomienda utilizar el siguiente convenio de llamadas:


Para comunicar los argumentos desde el programa llamante a la funcin llamada:
Se utilizar la pila El programa llamante dejar en la pila los argumentos de la llamada en el mismo orden en el que sern utilizados Si la funcin est codificada correctamente, tras terminar su ejecucin, dejar la pila en el mismo estado en el que la encontr Tras la llamada, el programa llamante tiene la responsabilidad de eliminar de la pila

Para comunicar los resultados desde la funcin llamada:


Se utilizar el registro extendido eax.

Prcticas de compiladores 2004-2005

Prcticas de compiladores 2004-2005

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
ASPLE begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end begin int z;
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Explicando ms detalladamente el proceso consideremos el siguiente programa

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

Prcticas de compiladores 2004-2005

Prcticas de compiladores 2004-2005

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal


El programa llamante introduce en la pila los argumentos

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

segment .data _z dd 0 segment .text global main extern lee_entero, imprime_entero main:

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

Prcticas de compiladores 2004-2005

Prcticas de compiladores 2004-2005

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal


Realiza la llamada a la funcin

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

Y limpia la pila. Esta instruccin es equivalente a pop <registro> pero no necesita modificar ningn registro

Prcticas de compiladores 2004-2005

Prcticas de compiladores 2004-2005

10

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

begin int z;
De la misma manera hay que hacer con una llamada a una funcin definida por el programador

function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

push dword [_z] call _doble add esp, 4

push dword [_z] call _doble add esp, 4 push dword eax El retorno de la funcin se encuentra en eax

Prcticas de compiladores 2004-2005

11

Prcticas de compiladores 2004-2005

12

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

Imaginemos el cdigo NASM equivalente. Comencemos por el programa principal

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

main: push dword _z call lee_entero add esp, 4

push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4

push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4 ret

Prcticas de compiladores 2004-2005

13

Prcticas de compiladores 2004-2005

14

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Para comprender el cdigo que hay que generar para la funcin imaginemos cmo
est la pila (donde se tiene que almacenar toda la informacin) en una llamada si z contiene el valor 3 begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end
main: push dword _z call lee_entero add esp, 4

Recurdese que la pila de 32 bits tiene su puntero almacenado en el registro esp


recuerde, tambin, que la pila crece hacia posiciones de memoria de valor menor, se representar grficamente con crecimiento hacia abajo begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end
main: push dword _z call lee_entero add esp, 4

Se introduce en la pila el valor de z

push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4 ret

push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4 ret

esp

Prcticas de compiladores 2004-2005

15

Prcticas de compiladores 2004-2005

16

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Recurdese que la pila de 32 bits tiene su puntero almacenado en el registro esp


recuerde, tambin, que la pila crece hacia posiciones de memoria de valor menor, se representar grficamente con crecimiento hacia abajo begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end
main: push dword _z call lee_entero add esp, 4

Esta es la pila que se encuentra la funcin cuando comienza su ejecucin Est claro dnde se encuentra el argumento de la funcin (arg) Se tiene que utilizar tambin la pila para localizar las variables locales (auxArg) Debemos conocer qu expresin, en funcin de los registros de gestin de la pila, sirve para localizar en ella argumentos y variables locales. Obsrvese que el compilador tendr que generar el cdigo necesario para el cuerpo de la funcin. Por las decisiones de diseo tomadas, se utilizar la pila, por lo tanto, el valor del registro esp cambiar. NASM proporciona otro registro ebp especficamente para poder solucionar esta circunstancia. Para ello hay que hacer lo siguiente: Guardar el valor de ebp (tambin en la pila) Utilizar ebp para mantener una copia del valor de esp en el momento de la entrada Utilizar ebp para localizar los parmetros y las variables locales Recuperar los valores de los dos registros antes de salir de la funcin
18

La instruccin call introduce en la pila la direccin de retorno

push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4 ret

3 dir ret. esp

Prcticas de compiladores 2004-2005

17

Prcticas de compiladores 2004-2005

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

_doble: push ebp

3 dir ret. ebp esp

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

_doble: push ebp mov ebp, esp

3 dir ret. ebp esp ebp

Se guarda el valor de ebp en la pila

Se guarda en ebp el valor de esp

Prcticas de compiladores 2004-2005

19

Prcticas de compiladores 2004-2005

20

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Recurdese que usamos un tamao de dato de 32 bits, que son 4 bytes. As es


fcil saber que arg se encuentra separado de ebp por 2 dword, es decir + 8 bytes
_doble: push ebp mov ebp, esp 3 dir ret. ebp esp ebp ebp+8

Ahora slo queda localizar (reservar espacio en la pila y saber como acceder

posteriormente) las variables locales (auxArg). Para ello se utiliza las posiciones libres bajo la cima de la pila (como con push, restamos a esp lo necesario)
_doble: push ebp mov ebp, esp sub esp, 4 3 dir ret. ebp ebp esp ebp+8

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

Prcticas de compiladores 2004-2005

21

Prcticas de compiladores 2004-2005

22

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
en ebp-4
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
mano y seguro que diferir de lo generado por el compilador)
_doble: push ebp mov ebp, esp sub esp, 4
Marina de la Cruz Alfonso Ortega

Por lo tanto, auxArg se encontrar siempre 4 bytes por debajo de ebp es decir,

Ahora se puede generar el cdigo para el cuerpo de la funcin (aqu se genera a

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

_doble: push ebp mov ebp, esp sub esp, 4

3 dir ret. ebp

ebp+8 ebp esp ebp-4

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

3 dir ret. ebp 3

ebp+8 ebp esp ebp-4

mov dword eax, [ebp+8] mov dword [ebp-4], eax

Prcticas de compiladores 2004-2005

23

Prcticas de compiladores 2004-2005

24

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
mano y seguro que diferir de lo generado por el compilador)
_doble: push ebp mov ebp, esp sub esp, 4
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Ahora se puede generar el cdigo para el cuerpo de la funcin (aqu se genera a

Antes de salir de la funcin se debe recuperar los valores iniciales de ebp y esp.

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

3 dir ret. ebp 3

ebp+8 ebp esp ebp-4

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

_doble: push ebp mov ebp, esp sub esp, 4

3 dir ret. ebp 3

ebp+8 ebp esp

ebp-4

mov mov mov mul

dword eax, [ebp+8] dword [ebp-4], eax dword edx, 2 edx

mov mov mov mul

dword eax, [ebp+8] dword [ebp-4], eax dword edx, 2 edx Se copia en esp su valor que est guardado en ebp. Obsrvese que es como si se hicieran los pop necesarios para eliminar las variables locales

mov esp, ebp

Prcticas de compiladores 2004-2005

25

Prcticas de compiladores 2004-2005

26

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Antes de salir de la funcin se debe recuperar los valores iniciales de ebp y esp.

Antes de salir de la funcin se debe recuperar los valores iniciales de ebp y esp.

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

_doble: push ebp mov ebp, esp sub esp, 4

3 dir ret. ebp 3

ebp+8 esp ebp ebp-4

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

_doble: push ebp mov ebp, esp sub esp, 4

3 dir ret.

esp

mov mov mov mul

dword eax, [ebp+8] dword [ebp-4], eax dword edx, 2 edx Se recupera (desde la pila) el antiguo valor de ebp. Obsrvese que, tras modificar en la instruccin anterior esp la cima de la pila apunta ahora a la posicin que guarda la copia de ebp

mov mov mov mul

dword eax, [ebp+8] dword [ebp-4], eax dword edx, 2 edx Y ya se puede devolver el control al programa llamante mediante la instruccin ret. Esta instruccin elimina de la pila la direccin de retorno

mov esp, ebp pop ebp

mov esp, ebp pop ebp ret

Prcticas de compiladores 2004-2005

27

Prcticas de compiladores 2004-2005

28

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Llamada a subrutinas: ejemplo preliminar
Marina de la Cruz Alfonso Ortega

Retornamos, por lo tanto, al cdigo del programa principal que se encuentra la pila

como la tena antes de la ejecucin de la instruccin call. Obsrvese que la pila todava contiene los argumentos de la funcin, el programa debe limpiar la pila.
main: push dword _z call lee_entero add esp, 4

Retornamos, por lo tanto, al cdigo del programa principal que se encuentra la pila

como la tena antes de la ejecucin de la instruccin call. Obsrvese que la pila todava contiene los argumentos de la funcin, el programa debe limpiar la pila.
main: push dword _z call lee_entero add esp, 4

begin int z; function int doble(int arg) begin int auxArg; auxArg := arg; return 2*arg end input z; output doble(z) end

begin int z; function int doble(int arg) begin int auxArg;


3 esp

esp push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4 ret 3 Se vio previamente la posibilidad de simula los pop necesarios para limpiar la pila sumando directamente en el puntero de la cima (esp)

push dword [_z] call _doble add esp, 4 push dword eax call imprime_entero add esp, 4 ret

auxArg := arg; return 2*arg end input z; output doble(z) end

Prcticas de compiladores 2004-2005

29

Prcticas de compiladores 2004-2005

30

Generacin de cdigo para funciones


Cdigo para la llamada a funciones
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Cdigo inicial y final para funciones recursivas y reentrantes
Marina de la Cruz Alfonso Ortega

Lo observado en el ejemplo anterior puede generalizarse para cualquier funcin


con cualquier nmero de variables locales y cualquier nmero de argumentos: El programa llamante debe primero copiar los argumentos de la funcin en la pila en el mismo orden en el que aparecen en la declaracin de la funcin push dword push dword <ltimo argumento> <1er argumento>

Lo observado en el ejemplo anterior puede generalizarse para cualquier funcin


con cualquier nmero de variables locales y cualquier nmero de argumentos:

Las primeras sentencias NASM del cuerpo de cualquier funcin deben ser las
siguientes: _<nombre_funcion>: push ebp mov ebp, esp sub esp, <4*n var locales>

Debe, luego llamar a la funcin:


call _<nombre funcin>

Y limpiar la pila:
add esp, <4 * n argumentos de la funcin> Antes de continuar con su cdigo sabiendo que eax contiene el retorno de la funcin (el cdigo escrito a continuacin imprime el entero devuelto por la funcin llamada) push eax call imprime_entero add esp, 4
Prcticas de compiladores 2004-2005 31

Y las ltimas deben ser las siguientes:


mov esp, ebp pop ebp ret

Prcticas de compiladores 2004-2005

32

Generacin de cdigo para funciones


Localizacin de contenido de parmetros
los parmetros se utilizar la expresin [ebp + <4 + 4*posicin del parmetro en declaracin>]
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Localizacin de contenido de variables locales
las variables locales se utilizar la expresin [ebp - <4*posicin de la variable en declaracin>]
Marina de la Cruz Alfonso Ortega

Y, en el cdigo del cuerpo de la funcin, cuando se quiera acceder al valor de

Y, en el cdigo del cuerpo de la funcin, cuando se quiera acceder al valor de

Recuerde que, el primer 4 es para saltar la direccin de retorno. Por ejemplo:


El valor del ltimo argumento ser [ebp+8]. El valor del penltimo argumento ser [ebp+12]. El valor del i-esimo argumento ser [ebp+<4+4*(num-argumentos-i)>], contando i con origen 0.

Por ejemplo:
El valor de la primera variable local ser [ebp-4]. El valor de la segunda variable local ser [ebp-8]. El valor de la i-esima variable local ser [ebp-<4*i>].

Prcticas de compiladores 2004-2005

33

Prcticas de compiladores 2004-2005

34

Generacin de cdigo para funciones


Localizacin de direccin de parmetros y variables locales
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Localizacin de direccin de parmetros y variables locales
Marina de la Cruz Alfonso Ortega

Sin embargo, como se ha indicado en la generacin de cdigo de otras


construcciones de ASPLE (por ejemplo en el de las expresiones que contienen identificadores), a veces es necesario utilizar la direccin y no el contenido Recurdese, por ejemplo, que para la variable global ASPLE z,
La expresin para referirse al contenido es

En este curso se va a utilizar la siguiente sintaxis para la instruccin lea de NASM


lea <registro> [<expresin>]

Donde
<registro>, es el nombre de un registro (por ejemplo eax) <expresin>, puede ser, por ejemplo ebp+12.

[_z]
Pero, la expresin para la direccin es

_z

Lamentablemente, las funciones reentrantes y recursivas no utilizan nombres


explcitos para los parmetros y las variables locales, por lo que la expresin equivalente para su direccin (ebp+<desplazamiento> y ebp-<desplazamiento>, respectivamente) son incorrectas en NASM. NASM proporciona la instruccin lea para resolver este problema.

Prcticas de compiladores 2004-2005

35

Prcticas de compiladores 2004-2005

36

Generacin de cdigo para funciones


Resumen: tratamiento de identificadores
utilizar las siguientes expresiones NASM para
Aacceder a su contenido
Si es una variable global
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Resumen: tratamiento de identificadores
Aacceder a su direccin
Si es una variable global
Marina de la Cruz Alfonso Ortega

Como resumen de estos ltimos puntos, considrese el identificador ASPLE z. Se

_z [_z]
Si es el argumento i-simo de una funcin, lo siguiente deja en el registro eax la direccin

Si es el argumento i-simo de una funcin

lea eax, [ebp+<4+4*i>]


Si es la variable local i-sima de una funcin

[ebp+<4+4*i>]
Si es la variable local i-sima de una funcin

lea eax, [ebp-<4*i>]

[ebp-<4*i>]

Prcticas de compiladores 2004-2005

37

Prcticas de compiladores 2004-2005

38

Generacin de cdigo para funciones


Otras modificaciones necesarias
lugares donde pueda aparecer un identificador. Es decir, siempre que hay un identificador, se tiene que determinar
Si es
una variable global una variable local de una funcin un argumento de una funcin
Marina de la Cruz Alfonso Ortega

Generacin de cdigo para funciones


Bibliografa
Paraninfo, Thomson Learning. 2001
Marina de la Cruz Alfonso Ortega

Es muy importante que el alumno propague este tratamiento a todos los

[deMiguel01] Pedro de Miguel Anasagasti, Fundamentos de los computadores. Ed.

Si el cdigo que se necesita generar acceder


A su contenido A su direccin

Ya que cada opcin necesita un tratamiento diferente.

Prcticas de compiladores 2004-2005

39

Prcticas de compiladores 2004-2005

40

Anda mungkin juga menyukai