es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué se necesita un marco de pila o una pila de sombreado en un procedimiento?

Eres un traductor de español que traduce documentos de TI. Traduce lo siguiente al español. No traduzcas el código y la salida en formato de markdown.

Disculpa por mi mal inglés, porque soy de Corea del Sur.

Intenté este código

lea rcx, QWORD PTR [message]
call [print_message] ; cubre la dirección de retorno con una dirección errónea

xor rcx, rcx
ret

y se estrelló… después de eso, intenté otra forma

`sub rsp, 8 ;shadow stack

lea rcx, QWORD PTR [message]
call [print_message]

add rsp, 8
ret`

“`

; marco de la pila
push rbp
mov rbp, rsp

lea rcx, QWORD PTR [message]
call [print_message]

mov rsp, rbp
pop rbp
ret

Estos 2 códigos funcionan, pero el problema es … ¿por qué el procedimiento necesita estas cosas? Esto me hace curioso.

Código real donde se produjo el problema

extern <em>_imp</em>MessageBoxA: QWORD

.data

message db "1234", 0

.code

entry_point proc

sub rsp, 8

xor ecx, ecx
lea rdx, QWORD PTR [message]
lea r8, QWORD PTR [message]
mov r9, 0
call [<em>_imp</em>MessageBoxA] ;stdcall

add rsp, 8
ret

entry_point endp
end
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema con el código original es que sobrescribió la dirección de retorno en la pila con la dirección de la función “print_message”, lo que causó que el programa se bloqueara cuando intentó retornar de esa función.

    Para solucionar este problema, el segundo ejemplo de código asigna espacio en la pila para una llamada “pila sombra” y almacena la dirección de retorno original ahí antes de realizar la llamada a la función. Esto asegura que la dirección de retorno no se sobrescriba y se pueda recuperar de manera segura cuando la llamada a la función retorna.

    El tercer ejemplo sigue la configuración típica del marco de pila donde el puntero base actual (rbp) se empuja a la pila y luego se establece en el puntero de pila actual (rsp) antes de asignar espacio para variables locales. En este caso, no hay variables locales, por lo que el código simplemente procede a llamar a la función MessageBoxA con los argumentos necesarios. Finalmente, el marco de pila se restablece al valor guardado de rbp, se extrae el rbp guardado de la pila y la función retorna.

    En resumen, el uso de una pila sombra o un marco de pila es necesario para asegurar que las direcciones de retorno no se sobrescriban y que el programa pueda retornar de manera segura desde las llamadas a funciones.

Comments are closed.