Prólogo y epílogo x64x64 prolog and epilog

Todas las funciones que asignan espacio de pila, llaman a otras funciones, guardan registros no volátiles o usan el control de excepciones deben tener un prólogo cuyos límites de dirección se describen en los datos de desenredado asociados a la entrada de la tabla de funciones correspondiente.Every function that allocates stack space, calls other functions, saves nonvolatile registers, or uses exception handling must have a prolog whose address limits are described in the unwind data associated with the respective function table entry. Para obtener más información, vea Control de excepciones x64.For more information, see x64 exception handling. El prólogo guarda los registros de argumentos en sus direcciones de inicio si es necesario, envía registros no volátiles en la pila, asigna la parte fija de la pila para variables locales y objetos temporales y, opcionalmente, establece un puntero de marco.The prolog saves argument registers in their home addresses if necessary, pushes nonvolatile registers on the stack, allocates the fixed part of the stack for locals and temporaries, and optionally establishes a frame pointer. Los datos de desenredado asociados deben describir la acción del prólogo y proporcionar la información necesaria para deshacer el efecto del código de prólogo.The associated unwind data must describe the action of the prolog and must provide the information necessary to undo the effect of the prolog code.

Si la asignación fija en la pila es más de una página (es decir, mayor de 4096 bytes), es posible que la asignación de la pila pueda abarcar más de una página de memoria virtual y, por tanto, se debe comprobar la asignación antes de asignarla.If the fixed allocation in the stack is more than one page (that is, greater than 4096 bytes), then it's possible that the stack allocation could span more than one virtual memory page and, therefore, the allocation must be checked before it's allocated. Para este fin, se proporciona una rutina especial a la que se puede llamar desde el prólogo y que no destruye ninguno de los registros de argumento.A special routine that's callable from the prolog and which doesn't destroy any of the argument registers is provided for this purpose.

El método preferido para guardar registros no volátiles consiste en moverlos a la pila antes de la asignación de pila fija.The preferred method for saving nonvolatile registers is to move them onto the stack before the fixed stack allocation. Si se realiza la asignación de pila fija antes de que se guarden los registros no volátiles, lo más probable es que se requiera un desplazamiento de 32 bits para abordar el área de registro guardada.If the fixed stack allocation is performed before the nonvolatile registers are saved, then most probably a 32-bit displacement is required to address the saved register area. (Supuestamente, las inserciones de registros son tan rápidas como los movimientos y deben conservarse para el futuro inmediato a pesar de la dependencia implícita entre inserciones). Los registros no volátiles se pueden guardar en cualquier orden.(Reportedly, pushes of registers are as fast as moves and should remain so for the foreseeable future in spite of the implied dependency between pushes.) Nonvolatile registers can be saved in any order. Pero el primer uso de un registro no volátil en el prólogo debe ser para guardarlo.However, the first use of a nonvolatile register in the prolog must be to save it.

Código de prólogoProlog code

El código de un prólogo típico podría ser el siguiente:The code for a typical prolog might be:

    mov    [RSP + 8], RCX
    push   R15
    push   R14
    push   R13
    sub    RSP, fixed-allocation-size
    lea    R13, 128[RSP]
    ...

En este prólogo se almacena el registro de argumento RCX en su ubicación de inicio, se guardan los registros no volátiles R13-R15, se asigna la parte fija del marco de pila y se establece un puntero de marco que apunta a 128 bytes en el área de asignación fija.This prolog stores the argument register RCX in its home location, saves nonvolatile registers R13-R15, allocates the fixed part of the stack frame, and establishes a frame pointer that points 128 bytes into the fixed allocation area. El uso de un desplazamiento permite acceder a una mayor parte del área de asignación fija con desplazamientos de un byte.Using an offset allows more of the fixed allocation area to be addressed with one-byte offsets.

Si el tamaño de asignación fija es mayor o igual que una página de memoria, se debe llamar a una función auxiliar antes de modificar RSP.If the fixed allocation size is greater than or equal to one page of memory, then a helper function must be called before modifying RSP. Este asistente, __chkstk, sondea el intervalo de pila que se va a asignar para asegurarse de que la pila se extienda de la forma correcta.This helper, __chkstk, probes the to-be-allocated stack range to ensure that the stack is extended properly. En ese caso, el ejemplo de prólogo anterior ahora sería el siguiente:In that case, the previous prolog example would instead be:

    mov    [RSP + 8], RCX
    push   R15
    push   R14
    push   R13
    mov    RAX,  fixed-allocation-size
    call   __chkstk
    sub    RSP, RAX
    lea    R13, 128[RSP]
    ...

El asistente __chkstk no modificará ningún registro que no sea R10, R11 y los códigos de condición.The __chkstk helper will not modify any registers other than R10, R11, and the condition codes. En concreto, devolverá RAX sin modificar y dejará sin cambios todos los registros no volátiles y los registros de paso de argumentos.In particular, it will return RAX unchanged and leave all nonvolatile registers and argument-passing registers unmodified.

Código de epílogoEpilog code

El código de epílogo existe en cada salida a una función.Epilog code exists at each exit to a function. Mientras que normalmente solo hay un prólogo, puede haber muchos epílogos.Whereas there is normally only one prolog, there can be many epilogs. El código de epílogo recorta la pila a su tamaño de asignación fijo (si es necesario), desasigna la asignación de pila fija, restaura los registros no volátiles mediante la extracción de sus valores guardados de la pila y devuelve un valor.Epilog code trims the stack to its fixed allocation size (if necessary), deallocates the fixed stack allocation, restores nonvolatile registers by popping their saved values from the stack, and returns.

El código de epílogo debe seguir un conjunto estricto de reglas para que el código de desenredo se desenrede de forma confiable a través de excepciones e interrupciones.The epilog code must follow a strict set of rules for the unwind code to reliably unwind through exceptions and interrupts. Estas reglas reducen la cantidad de datos de desenredo necesarios, ya que no se necesitan datos adicionales para describir cada epílogo.These rules reduce the amount of unwind data required, because no extra data is needed to describe each epilog. En su lugar, el código de desenredado puede determinar que se está ejecutando un epílogo mediante un examen de un flujo de código para identificar un epílogo.Instead, the unwind code can determine that an epilog is being executed by scanning forward through a code stream to identify an epilog.

Si no se usa ningún puntero de marco en la función, el epílogo debe desasignar primero la parte fija de la pila, extraer los registros no volátiles y devolver el control a la función de llamada.If no frame pointer is used in the function, then the epilog must first deallocate the fixed part of the stack, the nonvolatile registers are popped, and control is returned to the calling function. Por ejemplo,For example,

    add      RSP, fixed-allocation-size
    pop      R13
    pop      R14
    pop      R15
    ret

Si en la función se usa un puntero de marco, la pila se debe recortar a su asignación fija antes de la ejecución del epílogo.If a frame pointer is used in the function, then the stack must be trimmed to its fixed allocation prior to the execution of the epilog. Técnicamente, esta acción no forma parte del epílogo.This action is technically not part of the epilog. Por ejemplo, se podría utilizar el epílogo siguiente para deshacer el prólogo que se ha usado antes:For example, the following epilog could be used to undo the prolog previously used:

    lea      RSP, -128[R13]
    ; epilogue proper starts here
    add      RSP, fixed-allocation-size
    pop      R13
    pop      R14
    pop      R15
    ret

En la práctica, cuando se usa un puntero de marco, no es necesario ajustar RSP en dos pasos, por lo que en su lugar se usaría el siguiente epílogo:In practice, when a frame pointer is used, there is no good reason to adjust RSP in two steps, so the following epilog would be used instead:

    lea      RSP, fixed-allocation-size - 128[R13]
    pop      R13
    pop      R14
    pop      R15
    ret

Estos son los únicos formatos válidos para un epílogo.These forms are the only legal ones for an epilog. Debe constar de una instancia de add RSP,constant o lea RSP,constant[FPReg], seguida de una serie de cero o más extracciones de registro de 8 bytes y una instancia de return o jmp.It must consist of either an add RSP,constant or lea RSP,constant[FPReg], followed by a series of zero or more 8-byte register pops and a return or a jmp. (Solo se permite un subconjunto de instrucciones jmp en el epílogo.(Only a subset of jmp statements are allowable in the epilog. El subconjunto es exclusivamente la clase de instrucciones jmp con referencias de memoria ModRM, donde el valor del campo mod de ModRM es 00.The subset is exclusively the class of jmp statements with ModRM memory references where ModRM mod field value is 00. Se prohíbe el uso de instrucciones jmp en el epílogo con el valor de campo mod de ModRM 01 o 10.The use of jmp statements in the epilog with ModRM mod field value 01 or 10 is prohibited. Vea la Tabla A-15 del Manual del programador de arquitectura x86-64 de AMD volumen 3: Instrucciones de uso general y del sistema, para obtener más información sobre las referencias de ModRM permitidas). No puede aparecer ningún otro código.See Table A-15 in the AMD x86-64 Architecture Programmer's Manual Volume 3: General Purpose and System Instructions, for more info on the allowable ModRM references.) No other code can appear. En concreto, no se puede programar nada en un epílogo, incluida la carga de un valor devuelto.In particular, nothing can be scheduled within an epilog, including loading of a return value.

Cuando no se usa un puntero de marco, el epílogo debe utilizar add RSP,constant para desasignar la parte fija de la pila.When a frame pointer is not used, the epilog must use add RSP,constant to deallocate the fixed part of the stack. No puede usar lea RSP,constant[RSP] en su lugar.It may not use lea RSP,constant[RSP] instead. Esta restricción existe para que el código de desenredado tenga menos patrones que reconocer al buscar los epílogos.This restriction exists so the unwind code has fewer patterns to recognize when searching for epilogs.

Si se siguen estas reglas, el código de desenredado puede determinar que un epílogo se está ejecutando actualmente y simular la ejecución del resto del epílogo para permitir volver a crear el contexto de la función de llamada.Following these rules allows the unwind code to determine that an epilog is currently being executed and to simulate execution of the remainder of the epilog to allow recreating the context of the calling function.

Vea tambiénSee also

Convenciones de software x64x64 Software Conventions