Articulo de referencia

Prólogo y epílogo de la función

En la programación en lenguaje ensamblador , el prólogo de una función consiste en unas pocas líneas de código al inicio de la misma, que preparan la pila y los registros para s...

En la programación en lenguaje ensamblador , el prólogo de una función consiste en unas pocas líneas de código al inicio de la misma, que preparan la pila y los registros para su uso dentro de la función. De manera similar, el epílogo aparece al final de la función y restaura la pila y los registros al estado en que se encontraban antes de que se llamara a la función.

El prólogo y el epílogo no forman parte del lenguaje ensamblador en sí; representan una convención utilizada por los programadores de lenguaje ensamblador y los compiladores de muchos lenguajes de alto nivel . Son bastante rígidos, ya que tienen la misma estructura en cada función.

El prólogo y el epílogo de las funciones también contienen a veces código para la protección contra desbordamientos de búfer .

Prólogo

Un prólogo de función normalmente realiza las siguientes acciones si la arquitectura tiene un puntero base (también conocido como puntero de marco ) y un puntero de pila:

  • Coloca el puntero base actual en la pila para que pueda restaurarse posteriormente.
  • El valor del puntero base se establece en la dirección del puntero de pila (que apunta a la parte superior de la pila) para que el puntero base apunte a la parte superior de la pila.
  • Mueve el puntero de pila disminuyendo o aumentando su valor, según si la pila crece hacia abajo o hacia arriba. En la arquitectura x86, el puntero de pila disminuye para dejar espacio a las variables locales de la función.

Se pueden escribir varios prólogos posibles, lo que da como resultado configuraciones de pila ligeramente diferentes. Estas diferencias son aceptables, siempre y cuando el programador o el compilador utilicen la pila correctamente dentro de la función.

Como ejemplo, aquí se muestra un prólogo de función típico en lenguaje ensamblador x86, tal como lo produce GCC.

empujar ebp mover ebp , esp sub esp , N

El valor inmediato N es el número de bytes reservados en la pila para uso local.

El mismo resultado se puede obtener utilizando la enterinstrucción:

ingrese N , 0

Se pueden obtener prólogos más complejos utilizando valores distintos (distintos de 0) para el segundo operando de la enterinstrucción. Estos prólogos modifican varios punteros base/de marco para permitir funciones anidadas , como requieren lenguajes como Pascal . Sin embargo, las versiones modernas de estos lenguajes no utilizan estas instrucciones porque limitan la profundidad de anidamiento en algunos casos.

Epílogo

El epílogo de la función revierte las acciones del prólogo y devuelve el control a la función que la llamó. Normalmente realiza las siguientes acciones (este procedimiento puede variar según la arquitectura):

  • Baja el puntero de pila al puntero base actual, liberando así el espacio reservado en el prólogo para las variables locales.
  • Extrae el puntero base de la pila, de modo que se restablece a su valor anterior al prólogo.
  • Regresa a la función que la llamó, extrayendo el contador de programa del marco anterior de la pila y saltando a él.

El epílogo dado revertirá los efectos de cualquiera de los prólogos anteriores (ya sea el completo o el que utiliza enter). Según ciertas convenciones de llamada, es responsabilidad de la función llamada limpiar los argumentos de la pila, por lo que el epílogo también puede incluir el paso de mover el puntero de pila hacia arriba o hacia abajo.

Por ejemplo, estos tres pasos se pueden realizar en lenguaje ensamblador x86 de 32 bits mediante las siguientes instrucciones:

mov esp , ebp pop ebp ret

Al igual que el prólogo, el procesador x86 contiene una instrucción integrada que ejecuta parte del epílogo. El siguiente código es equivalente al código anterior:

dejar atrás

La leaveinstrucción ejecuta las movinstrucciones pop, como se describe anteriormente.

Una función puede contener múltiples epílogos. Cada punto de salida de la función debe saltar a un epílogo común al final o contener su propio epílogo. Por lo tanto, los programadores o compiladores suelen usar la combinación de ` leaveand` y `for` retpara salir de la función en cualquier punto. (Por ejemplo, un compilador de C sustituiría una returninstrucción `for` con una secuencia leave`/ ret`).

Lecturas adicionales

  • de Boyne Pollard, Jonathan (2010). "Los peligros de la gen on function" . Respuestas frecuentes .