tutorial español aprender c compiler-construction abi function-call stackframe

c - aprender - solidity español



¿Cómo regresan las llamadas a su llamador después de ser llamadas? (4)

Leí que cuando una llamada de función es realizada por un programa, la función llamada debe saber cómo regresar a su llamador.

Mi pregunta es: ¿cómo sabe la función llamada cómo regresar a su llamante? ¿Hay algún mecanismo que funcione entre bastidores a través del compilador?


  1. El compilador sabe cómo llamar a una función y qué convención de llamadas se usa. Por ejemplo, en C, los argumentos para una función se insertan en la pila. La persona que llama es responsable de borrar la pila, por lo que la función llamada no tiene que eliminar los argumentos. Otras convenciones de llamadas pueden incluir presionar los argumentos en la pila y la función llamada tiene que limpiarlo. En este caso, el código generado es tal, que la función corrige la pila antes de que pueda regresar. Las convenciones de llamada Ohter pueden pasar los argumentos en los registros, por lo que en tal caso la función llamada tampoco tiene que tener cuidado.

  2. La CPU tiene un mecanismo para llamar a una subrutina. Esto almacenará la dirección de ejecución actual en la pila y luego transferirá el procesamiento a la nueva dirección. Cuando la función está lista, ejecuta una declaración de devolución, que recuperará la dirección de la persona que llama y reanudará la ejecución allí.

Si la dirección de devolución se destruye, porque la pila no se limpia correctamente o la memoria se sobrescribe, entonces obtendrá un comportamiento indefinido. Por supuesto, los detalles exactos de implementación varían según la plataforma que se utilice.


El compilador obedece a una "convención de llamadas" en particular, definida como parte de la ABI a la que se dirige. Esa convención de llamadas incluirá una forma para que el sistema sepa a qué dirección regresar. La convención de llamadas normalmente aprovecha el soporte del hardware para llamadas a procedimientos. En Intel, por ejemplo, la dirección de retorno se envía a la pila:

... el procesador empuja el valor del registro EIP (que contiene el desplazamiento de la instrucción que sigue a la instrucción CALL ) en la pila (para usar más tarde como un puntero de instrucción de retorno).

El regreso de una función se realiza a través de la instrucción ret :

... el procesador muestra el puntero (desplazamiento) de la instrucción de retorno desde la parte superior de la pila en el registro EIP y comienza la ejecución del programa en el nuevo puntero de instrucción.

Para contrastar, en ARM, la dirección de retorno se coloca en el registro de enlace:

Las instrucciones BL y BLX copian la dirección de la siguiente instrucción en lr ( r14 , el registro de enlace).

Las devoluciones se realizan comúnmente ejecutando movs pc, lr para copiar la dirección del registro del enlace nuevamente dentro del registro del contador del programa.

Referencias

  1. Manual de desarrolladores de software Intel
  2. Centro de información ARM

Esto es posible gracias a la pila (especialmente en sistemas similares a Intel). Digamos que tenemos un método caller que incluye, por ejemplo, un int que guarda localmente.

Cuando caller( llamadas target( que int debe guardarse) se coloca en la pila, junto con la dirección desde la que se realiza la llamada. target( puede realizar su lógica, crear sus propias variables locales y llamar a otros métodos. las variables se colocarán en la pila junto con la dirección de la llamada.

Cuando el target( finaliza, la pila se "desenrolla"). Se elimina la parte superior de la pila que contiene las variables locales del target( .

Cuando los métodos se repiten demasiado, la pila puede crecer demasiado y puede ocurrir un "desbordamiento de pila".


Requiere cooperación entre el llamado y el que llama.

La persona que llama se compromete a dar la dirección que el destinatario debería devolver al destinatario (generalmente presionándola en la pila, o pasándola en un registro), y el destinatario acuerda regresar a esa dirección cuando haya terminado de ejecutar.