2012-02-12 13 views
8

De http://en.wikipedia.org/wiki/Stack_pointer#Structure¿Por qué los parámetros de funciones se presionan antes en la pila de llamadas que la dirección de retorno?

enter image description here

Me pregunto por qué la dirección de retorno de una función se coloca por encima de los parámetros para esa función?

tiene más sentido tener Dirección de devolución inserta en la pila antes de que los parámetros de drawLine ya que los parámetros no son necesarios más cuando la Dirección Volver se extrae para regresar de nuevo a la función de llamada.

¿Cuáles son las razones para preferir la implementación que se muestra en el diagrama anterior?

+3

Tenga en cuenta que este acuerdo ** no forma parte del estándar C++. Es específico para una CPU, compilador y/o entorno operativo individual. La situación descrita en ese artículo es típica, y es precisa para GCC/X86, pero de ninguna manera es universal. –

+0

Es posible que no se solucione el número de parámetros y locales. ¿Cómo podría determinar la dirección de los 3 si la dirección del remitente no estaba en el medio? – Pubby

+0

@Pubby: no tengo la respuesta, pero esa situación también está sucediendo con ** Locales de DrawSquare ** y ** Parámetros de DrawLine ** aquí. – Lazer

Respuesta

5

La dirección de retorno generalmente se envía a través del comando de máquina call, [que en el idioma nativo instruction set] mientras que los parámetros y variables se envían con varios comandos de máquina, que el compilador crea.

Por lo tanto, la dirección de retorno es lo último empujado por la persona que llama, y antes de nada [variables locales] empujado por el destinatario.

Todos los parámetros se presionan antes de la dirección de retorno, porque el salto a la función real y la inserción de la dirección de retorno a la pila se realiza en el mismo comando de máquina.

Además, otra razón es que la persona que llama es el que asigna espacio en la pila para los parámetros. También debe ser él quien lo limpie.

+0

"[El que llama] también debería ser quien lo limpie". - en realidad, en casi todas las convenciones de llamadas que no admiten parámetros variados (por ejemplo, 'stdcall') la responsabilidad de limpieza depende del destinatario de la llamada para reducir el tamaño del ejecutable (el código de limpieza se escribe una sola vez al final de la función en lugar de una vez para cada llamada de función). –

1

El motivo es simple: los argumentos de la función son enviados a la pila por la función de llamada (que es la única que puede hacerlo porque solo tiene la información necesaria; después de todo, el objetivo de hacerlo es pasar) esa información a la función llamada). La dirección de retorno es empujada a la pila por el mecanismo de llamada de función. La función se llama después de la función de llamada ha configurado los parámetros, porque después de la llamada es la función llamada que se ejecuta, no la que llama.

Bien, entonces ahora podría argumentar que la función de llamada podría poner los parámetros más allá de la pila actualmente utilizada, y la función llamada podría entonces ajustar el puntero de la pila en consecuencia. Pero eso no funcionaría bien porque en cualquier momento podría haber una interrupción o una señal, lo que empujaría el estado actual a la pila para restaurarlo más tarde (no me sorprendería si un cambio de tarea también lo hiciera) . Pero si configura los parámetros más allá de la pila actual, esos eventos asincrónicos lo sobreescribirían, y como no puede predecir cuándo ocurrirán, no puede evitar eso (más allá de la desactivación, que puede tener otros inconvenientes o incluso ser imposible, en el caso) del cambio de tarea). Básicamente, todo lo que está más allá de la pila actual debe considerarse volátil.

También tenga en cuenta que esto es independiente de la cuestión de quién limpia los parámetros. En principio, la función llamada podría llamar a los destructores de llamadas de los argumentos, incluso si físicamente se encuentran en el marco de pila de la persona que llama.Además, muchos procesadores (incluido el x86) tienen instrucciones que automáticamente extraen espacio extra por encima de la dirección de retorno a la devolución (por ejemplo, los compiladores de Pascal generalmente lo hicieron porque en Pascal no tiene ninguna limpieza más allá de devolver la memoria, y al menos fr procesadores de la época, era más eficiente limpiar con esa instrucción del procesador (no tengo idea si eso sigue siendo cierto para los procesadores modernos). Sin embargo, C no usó ese mecanismo debido a las listas de argumentos de longitud variable: para aquellos, el mecanismo no era aplicable porque necesitarías saber en tiempo de compilación cuánto espacio extra liberar, y K & RC no requirió reenviar-declarar funciones variadas (C89 lo hace, pero pocos compiladores lo aprovechan, debido a la compatibilidad con el código anterior), por lo que no había forma de que la función de llamada supiera si limpiar los argumentos a menos que tuviera que hacer eso siempre.

Cuestiones relacionadas