Comprenda el registro ebp y esp, el proceso de llamada de función, el paso de parámetros de función y el equilibrio de pila desde una perspectiva de ensamblaje

Con respecto a la transferencia de parámetros de función y el cambio del puntero de la pila, ha habido una falta de comprensión y comprensión sistemáticas. Varios blogs solo han explicado un punto de conocimiento parcial de manera unilateral, y no tienen una comprensión general y profunda de la pila. Este artículo intenta explicar el cambio de la pila cuando se llama a la función desde el ensamblado y el conjunto, y cómo pasar los parámetros. Si lees este artículo detenidamente, creo que habrá algunas ganancias.


Puntero de pila y registros relacionados

La pila es la estructura de datos más común en el sistema operativo. Estrictamente hablando, la pila se compone de dos estructuras de datos, una pila y una pila, pero generalmente decimos que la pila realmente se refiere a la pila. En la pila, los dos punteros más importantes son SP (puntero de pila) y BP (puntero de dedo base).

  • SP (Stack Pointer), puntero de pila: en un sistema de 32 bits, el registro ESP (Extended SP) almacena el puntero de pila. En un sistema de 64 bits, aparece como un registro RSP. SP siempre apunta a la parte superior del marco de la pila superior de la pila del sistema. Entonces SP es el puntero superior
  • BP (puntero base), el puntero del dedo base En un sistema de 32 bits, el registro EBP (BP extendido) almacena el puntero del dedo base. En el sistema de 64 bits, se representa como registro RBP. BP apunta a la parte inferior del marco de la pila, comúnmente conocido como el puntero inferior de la pila

Creo que verá la definición anterior en la mayoría de los blogs, pero ¿qué hacen exactamente estos punteros y registros? SP, el puntero es la dirección y se almacena el puntero superior de la pila. El propósito es que la próxima vez que se opere la pila, el sistema pueda encontrar la posición actual de la pila a tiempo. Por ejemplo, push empuja un operando y almacena un operando de longitud de palabra en el espacio de memoria de la dirección de sp + 4. El papel de BP se describirá a continuación.


Llamada a la función

Cuando una función llama a otra, ¿cómo cambia la pila? ¿Cómo han cambiado SP y BP? ¿Cómo se pasan los parámetros de la función? Más adelante, escribiremos un programa de demostración simple para profundizar la comprensión de los registros relacionados con la pila.

En una función, llame a otra función, a menudo hay los siguientes pasos

Instrucciones de montaje Función de atribución de instrucción Cambios SP Efecto
empujar arg2 Función principal sp-4
empujar arg1 Función principal sp-4
call function Función principal sp-4 Comience a llamar a la subrutina mientras guarda la dirección de retorno
push ebp Subfuncion sp-4
empujar ebp, esp Subfuncion sp-4 Guarde el sp actual en bp, el propósito es localizar los parámetros de la función
Bajo SP, #NUM Subfuncion SP-si Asignar espacio de pila para subrutinas
... Subfuncion ... La lógica de implementación específica de la función.
pop ebp Subfuncion sp + 4
derecho Subfuncion sp + 4

Explicación

  • push argAntes de llamar a una función, debe insertar los parámetros pasados ​​en la pila, por lo que debe tenerlos. Después de cada inserción, la pila tiene una longitud de palabra adicional (sistema de 32 bits-> 4 bytes), por lo que la parte superior de la pila debe moverse 4 bytes hacia arriba, la instrucción implicasub sp, #4
  • call La instrucción de llamada se usa para llamar a una función. La instrucción tiene dos operaciones: (1) insertar la dirección de retorno en la pila; (2) sp = sp-4
  • push ebp push ebp, esp Tal operación, verá al comienzo de cada función
  • ret, Es decir, el retorno, esta vez debe apuntar sp callinstrucción simplemente empujó la dirección del remitente, la ejecución retes en realidad el caso de la pila de datos emergente, registro de memoria a EIP. eip almacena la dirección de la siguiente instrucción que se ejecutará. Al mismo tiempo sp = sp + 4
  • ret El comando es equivalente a pop eip; esp = esp + 4
  • call La instrucción es equivalente a push eip; esp = esp-4

Al ver el código y la descripción anteriores, es posible que aún no comprenda completamente los cambios en la pila. El azul indica la instrucción de ensamblaje de la función original, y el verde indica la instrucción de ensamblaje de la función llamada y el espacio de pila correspondiente.

La función principal llama a la subfunción

Inserte la descripción de la imagen aquí
La imagen de arriba muestra el cambio en el espacio de la pila cuando se llama a la función. De abajo hacia arriba, sp es la parte superior de la pila de funciones original. Aquí, se supone que sp = 0xc1111 0000 original . Al comienzo de la función llamada, siempre habrá

push ebp
mov ebp, esp

Combinado con la figura anterior, no es difícil ver que ebp = 0xc1111icsoft4 * 4. Cuando no se llama a ninguna otra función, el ebp en la función generalmente permanece sin cambios. En otras palabras, ebp + 8 representa la dirección de arg1, y ebp + 12 representa la dirección de arg2. Así, un papel de ebp es encontrar el parámetro de la función, por supuesto, también las variables locales para localizar la pila por ebp , la subrutina es a través ebp + 偏移量de los parámetros de llamada se pasan al programa principal.


La subfunción devuelve la función principal

Inserte la descripción de la imagen aquí
La figura anterior muestra el cambio en el espacio de la pila cuando la función vuelve a la capa anterior. Esta vez, mira hacia abajo desde arriba. Debido a que acaba de comenzar push ebplas operaciones al final de la función de llamada, pero también es necesario pop ebp. retLa operación desplegará la dirección de devolución en la pila para eip, y sp aumentará en 4. Después de ejecutar la función llamada, el siguiente paso continuará ejecutando la instrucción antes de la función llamada. Pero en este momento, sp apunta al arg1 original y no apunta a la parte superior de la pila de funciones principal original . Si hay otros datos en la pila original, sp no regresa al inicio hará que la función principal haga referencia a los datos en el error de la pila.


Balance de pila

En este contexto, apareció el concepto de balance de pila . Es decir, debe realizar una operación separada en sp antes de poder apuntar sp a la parte superior de la pila de funciones original. En el lenguaje C común, hay varias reglas de llamada para funciones. Por ejemplo, método cdecl y método stdcall .

cdecl modo de realización, la rutina principal ejecutada por el add esp, najuste de ESP pila de instrucciones al equilibrio alcance. En una realización stdcall, al volver de la subrutina, la ejecución ret npila equilibrio. n es en realidad la cantidad de espacio ocupado por los parámetros de la función.


Caso especifico

/* stack_test.c */
#include <stdio.h>

int func(int a, int b)
{
	int c = a + b;
	return c;
}

int main(int argc, char const *argv[])
{
	int result = func(1, 2); /* */
	return 0;
}

Compile el código anterior en un programa de 32 bits

gcc stack_test.c -m32 -o test

Utilice objdump o ida vista de conjunto, se puede ver, el uso de la opción predeterminada cdeclmodo de pila equilibrada.

objdump -d test -M intel

Programa principal

Inserte la descripción de la imagen aquí
Subrutina

Inserte la descripción de la imagen aquí

Paso de parámetros del sistema de 64 bits

En los sistemas operativos de 32 bits, como mencionamos en la sección anterior, la forma de usar ebp + n es usar la pila para pasar parámetros . El sistema operativo de 64 bits es diferente del de 32 bits, y el registro llama directamente a los parámetros de función , por lo que no hay balance de pila.

Compile el ejemplo anterior en un programa de 64 bits y luego desmóntelo. El programa principal es el siguiente

Inserte la descripción de la imagen aquí
Subrutina

Inserte la descripción de la imagen aquí
El papel de los registros del sistema de 64 bits, los primeros seis parámetros de los programas de 64 bits se pasan a través de RDI, RSI, RDX, RCX, R8 y R9

Resumen

Este artículo explica la llamada de función y el paso de parámetros desde la perspectiva del ensamblaje.Tomando el sistema operativo de 32 bits como ejemplo, muestra el proceso de cambio dinámico de la pila en la llamada del programa, especialmente los registros esp y ebp. En este contexto, se introduce el concepto de balance de pila. Finalmente, introduce las diferencias en los parámetros de transferencia de funciones en el sistema operativo de 64 bits, es decir, el sistema de 64 bits utiliza registros para acceder directamente a los parámetros de la función, de modo que no hay una pila de equilibrio.

Los ejemplos dados en este documento describen el caso de utilizar C idioma predeterminado Cdeclfunción de llamada de modo, en el caso de 32 bits, utilizando la pila para pasar parámetros, el proceso específico se resume como sigue

  1. El programa principal empuja cada parámetro a la pila uno por uno de derecha a izquierda, lo que significa que el último parámetro se inserta primero en la pila
  2. La subrutina accede a los parámetros a través del registro ebp ebp + n. Cuando n = 8, representa el primer parámetro, n = 12 representa el segundo parámetro, y así sucesivamente
  3. La subrutina usa la instrucción ret para volver al programa principal.
  4. punto principal para add esp, nser pila equilibrada
  5. El programa principal obtiene el valor de retorno de la subrutina a través de eax

Finalmente, coloque una imagen para ilustrar la distribución del espacio de memoria virtual de 4GB en el sistema de arquitectura x86 de 32 bits, espero que todos puedan tener una comprensión macro de la pila

52 artículos originales publicados · Me gusta 30 · Visitas 50,000+

Supongo que te gusta

Origin blog.csdn.net/song_lee/article/details/105297902
Recomendado
Clasificación