registros registro instrucciones indice esp ensamblador ecx ebx eax assembler assembly x86 x86-64

assembly - instrucciones - ¿Por qué la arquitectura x86 usa dos registros de pila(especialmente, ebp)?



registro edi (2)

Todo esto depende de la convención de llamadas, por supuesto, pero generalmente es así.

El puntero de la pila se puede mover de forma arbitraria en función de lo que necesite para empujar o salirse de la pila en cualquier punto dado en el tiempo. Esto puede suceder en cualquier momento dentro de una función, ya que necesita guardar temporalmente algunos datos en la pila.

El puntero base generalmente se establece en el mismo valor para cualquier profundidad dada de la pila, y se usa para acceder a los parámetros pasados ​​(por un lado) y variables locales (por el otro lado). También se usa para mover rápidamente el puntero de pila al salir de una función.

La razón por la que se hace de esta manera es simplificar el código para que no tenga que hacer referencia al contenido de la pila en función de un puntero de pila posiblemente cambiante. Usar el puntero base facilita considerablemente la tarea de generación de código (no tiene que saber qué es el puntero de la pila en un momento dado, simplemente use el puntero base, que permanece igual durante la duración de la función).

Sin eso, el código que quería insertar dos copias de una variable local para llamar a la siguiente función se vería así:

mov eax, [esp+16] ; get var1 push eax ; push it mov eax, [esp+20] ; get var1 again push eax call _somethingElse

Dejando de lado el hecho de que no volvería a cargar eax en este caso, el punto que estoy tratando de hacer es que la ubicación relativa de los elementos de un puntero de pila móvil puede complicar innecesariamente las cosas.

Por ejemplo, aquí hay una función codificada en ensamblaje que sigue una convención de llamada común:

_doSomething: push ebp ; stack current base pointer mov ebp, esp ; save previous stack pointer sub esp, 48 ; incl 48 bytes local storage ; do whatever you want here, including changing ; esp, as long as it ends where it started. mov esp, ebp ; restore previous stack pointer pop ebp ; and previous base pointer ret ; then return _callIt: mov eax, 7 push eax ; push parameter for function call _doSomething add esp, 4 ; get rid of pushed value :

Si sigue el código, puede ver que ebp dentro del cuerpo de la función es un punto de referencia fijo con [ebp] (contenidos de ebp ) siendo la dirección de retorno, [ebp+4] siendo el valor de 7 , y [ebp-N] es el almacenamiento local de _doSomething , donde N varía de 1 a 48 .

Este es el caso, independientemente de la cantidad de elementos que se inserten o salten dentro del cuerpo de la función.

Mi pregunta es simple: ¿Por qué la arquitectura x86 usa dos registros de pila ( esp ; ebp )?

La longitud del marco de pila se ha determinado durante el tiempo de compilación, entonces creo que podemos usar un solo registro (por ejemplo esp ) para acceder a la pila, y mantener la dirección base que solía estar en el registro de ebp en la pila (o en otras regiones de memoria, pero eso incurriría en una mayor penalización de rendimiento)

¿Es posible?


¿Por qué la arquitectura x86 usa dos registros de pila (especialmente, ebp)?

De acuerdo con la respuesta de @gsg a la pregunta relacionada " ¿ Algún lenguaje / compilador utiliza la instrucción x86 ENTER con un nivel de anidación no nulo?" la arquitectura x86 fue diseñada hace 30 años como " Pascal machine ".

Vea The 8086/8088 Primer, por Stephen P. Morse, Capítulo 8: Programación de alto nivel (Pascal) para la justificación de uno de los diseñadores de chips.

Como tal, incorpora soporte de hardware para subrutinas anidadas y recursivas (procedimientos, funciones), ya que en el lenguaje de programación de Pascal, este era un aspecto importante del paradigma de programación estructurada que se suponía que producía un código que era más fácil de leer / escribir / mantener.

El soporte de hardware en forma de instrucciones especiales de CPU habilitadas para generar código usando menos instrucciones. Menos instrucciones generalmente también significan un código más rápido.

¿Es posible implementar el acceso a la variable de marco de pila en otra máquina completa de Turing sin el uso del registro de ebp?

Sí, pero con diferente tiempo de ejecución