En informática , una convención de llamada es un esquema de nivel de implementación (nivel bajo) para cómo las subrutinas o funciones reciben parámetros de su llamador y cómo devuelven un resultado. [1] Cuando algún código llama a una función, se han tomado decisiones de diseño para dónde y cómo se pasan los parámetros a esa función, y dónde y cómo se devuelven los resultados de esa función, y estas transferencias generalmente se realizan a través de ciertos registros o dentro de un marco de pila en la pila de llamadas . Hay opciones de diseño para cómo se dividen las tareas de preparación para una llamada de función y restauración del entorno después de que la función se haya completado entre el llamador y el llamado. Algunas convenciones de llamada especifican la forma en que se debe llamar a cada función. Se debe utilizar la convención de llamada correcta para cada llamada de función, para permitir la ejecución correcta y confiable de todo el programa utilizando estas funciones.
Introducción
Las convenciones de llamada suelen considerarse parte de la interfaz binaria de la aplicación (ABI). Pueden considerarse un contrato entre el que llama y la función llamada. [1]
Conceptos relacionados
Los nombres o significados de los parámetros y valores de retorno se definen en la interfaz de programación de aplicaciones (API, a diferencia de ABI), que es un concepto independiente, aunque relacionado con ABI y la convención de llamada. Los nombres de los miembros dentro de las estructuras y objetos pasados también se considerarían parte de la API, y no de la ABI. A veces, las API incluyen palabras clave para especificar la convención de llamada para las funciones.
Las convenciones de llamadas no suelen incluir información sobre el manejo de la vida útil de las estructuras y los objetos asignados dinámicamente. Otra documentación complementaria puede indicar quién es el responsable de liberar la memoria asignada.
Es poco probable que las convenciones de llamada especifiquen el diseño de los elementos dentro de las estructuras y los objetos, como el orden de bytes o el empaquetamiento de estructuras.
Para algunos lenguajes, la convención de llamada incluye detalles de manejo de errores o excepciones (por ejemplo, Go , Java ) y para otros, no (por ejemplo, C++ ).
Para las llamadas a procedimientos remotos , existe un concepto análogo llamado Marshalling .
Las convenciones de llamada pueden estar relacionadas con la estrategia de evaluación de un lenguaje de programación en particular , pero la mayoría de las veces no se las considera parte de ella (o viceversa), ya que la estrategia de evaluación generalmente se define en un nivel de abstracción más alto y se la considera parte del lenguaje en lugar de un detalle de implementación de bajo nivel del compilador de un lenguaje en particular .
Diferentes convenciones de llamadas
Las convenciones de llamada pueden diferir en:
- Dónde se colocan los parámetros. Las opciones incluyen registros , en la pila de llamadas , una combinación de ambos o en otras estructuras de memoria.
- El orden en el que se pasan los parámetros. Las opciones incluyen el orden de izquierda a derecha, de derecha a izquierda o algo más complejo.
- Cómo se manejan las funciones que toman una cantidad variable de argumentos ( funciones variádicas ). Las opciones incluyen simplemente pasar en orden (suponiendo que el primer parámetro está en una posición obvia) o las partes variables en una matriz.
- Cómo se envían los valores de retorno del receptor de la llamada al emisor de la llamada. Las opciones incluyen en la pila, en un registro o haciendo referencia a algo asignado en el montón.
- Cómo se manejan los valores largos o complejos, quizás dividiéndolos entre múltiples registros, dentro del marco de la pila o con referencia a la memoria.
- ¿Qué registros tienen la garantía de tener el mismo valor cuando el receptor de la llamada regresa que cuando se lo llamó? Se dice que estos registros se guardan o preservan , por lo que no son volátiles .
- Cómo se divide la tarea de preparación y limpieza después de una llamada de función entre el que realiza la llamada y el que la recibe. En particular, cómo se restaura el marco de la pila para que el que realiza la llamada pueda continuar después de que el que la recibe haya terminado.
- Si se pasan metadatos que describen los argumentos y cómo
- Donde se almacena el valor anterior del puntero de marco , que se utiliza para restaurar el marco de la pila cuando finaliza la subrutina. Las opciones incluyen dentro de la pila de llamadas o en un registro específico. A veces, los punteros de marco no se utilizan en absoluto. [2]
- Dónde se ubican los enlaces de alcance estático para el acceso a datos no locales de la rutina (normalmente en una o más posiciones en el marco de la pila, pero a veces en un registro general o, para algunas arquitecturas, en registros de propósito especial)
- Para los lenguajes orientados a objetos, cómo se hace referencia al objeto de la función
Convenciones de llamadas dentro de una plataforma
A veces aparecen múltiples convenciones de llamada en una única plataforma; una determinada plataforma e implementación de lenguaje puede ofrecer una selección de convenciones de llamada. Las razones para esto incluyen el rendimiento, la adaptación de convenciones de otros lenguajes populares y las restricciones o convenciones impuestas por varias " plataformas informáticas ".
Muchas arquitecturas solo tienen una convención de llamada ampliamente utilizada, a menudo sugerida por el arquitecto. Para RISC, como SPARC, MIPS y RISC-V , se suelen utilizar nombres de registros basados en esta convención de llamada. Por ejemplo, los registros MIPS $4a través de $7tienen "nombres ABI" $a0a través de $a3, lo que refleja su uso para el paso de parámetros en la convención de llamada estándar. (Las CPU RISC tienen muchos registros de propósito general equivalentes, por lo que normalmente no hay ninguna razón de hardware para darles nombres distintos a los números).
La convención de llamada del lenguaje de un programa determinado puede diferir de la convención de llamada de la plataforma subyacente, el sistema operativo o alguna biblioteca a la que se vincula. Por ejemplo, en Windows de 32 bits , las llamadas al sistema operativo tienen la convención de llamada stdcall , mientras que muchos programas C que se ejecutan allí utilizan la convención de llamada cdecl . Para dar cabida a estas diferencias en la convención de llamada, los compiladores suelen permitir palabras clave que especifican la convención de llamada para una función determinada. Las declaraciones de función incluirán palabras clave específicas de la plataforma adicionales que indican la convención de llamada que se utilizará. Cuando se maneja correctamente, el compilador generará código para llamar a las funciones de la manera adecuada.
Algunos lenguajes permiten que la convención de llamada para una función se especifique explícitamente con esa función; otros lenguajes tendrán alguna convención de llamada pero estará oculta para los usuarios de ese lenguaje y, por lo tanto, normalmente no será una consideración para el programador.
Arquitecturas
x86 (32 bits)
La versión de 32 bits de la arquitectura x86 se utiliza con muchas convenciones de llamada diferentes. Debido a la pequeña cantidad de registros arquitectónicos y al enfoque histórico en la simplicidad y el tamaño pequeño del código, muchas convenciones de llamada x86 pasan argumentos en la pila. El valor de retorno (o un puntero a él) se devuelve en un registro. Algunas convenciones utilizan registros para los primeros parámetros, lo que puede mejorar el rendimiento, especialmente para rutinas de hoja cortas y simples que se invocan con mucha frecuencia (es decir, rutinas que no llaman a otras rutinas).
Ejemplo de llamada:
push EAX ; pasa algún resultado de registro push dword [ EBP + 20 ] ; pasa alguna variable de memoria (sintaxis FASM/TASM) push 3 ; pasa alguna constante call calc ; el resultado devuelto ahora está en EAX
Estructura típica del llamado: (algunas o todas (excepto ret) de las instrucciones a continuación pueden optimizarse en procedimientos simples). Algunas convenciones dejan el espacio de parámetros asignado, utilizando plain reten lugar de ret imm16. En ese caso, el llamador podría add esp,12en este ejemplo, o de otra manera, lidiar con el cambio a ESP.
calc:
push EBP ; guardar el puntero de marco antiguo mov EBP , ESP ; obtener el nuevo puntero de marco sub ESP , localsize ; reservar espacio de pila para variables locales ; realizar cálculos, dejar el resultado en EAX . mov ESP , EBP ; liberar espacio para variables locales pop EBP ; restaurar el puntero de marco antiguo ret paramsize ; liberar espacio de parámetros y regresar.
x86-64
La versión de 64 bits de la arquitectura x86, conocida como x86-64 , AMD64 e Intel 64, tiene dos secuencias de llamada de uso común. Una secuencia de llamada, definida por Microsoft, se utiliza en Windows; la otra secuencia de llamada, especificada en la ABI de System V de AMD64, se utiliza en sistemas tipo Unix y, con algunos cambios, en OpenVMS . Como x86-64 tiene más registros de propósito general que x86 de 16 bits, ambas convenciones pasan algunos argumentos en los registros.
BRAZO (A32)
La convención de llamada ARM estándar de 32 bits asigna los 16 registros de propósito general de la siguiente manera:
- r15: Contador de programa (según la especificación del conjunto de instrucciones).
- r14: Registro de enlace. La instrucción BL, utilizada en una llamada a una subrutina, almacena la dirección de retorno en este registro.
- r13: puntero de pila. Las instrucciones Push/Pop en modo operativo "Thumb" utilizan únicamente este registro.
- r12: Registro scratch de llamada intra-procedimiento.
- r4 a r11: Variables locales.
- r0 a r3: Valores de argumentos pasados a una subrutina y resultados devueltos desde una subrutina.
Si el tipo de valor devuelto es demasiado grande para caber en r0 a r3, o cuyo tamaño no se puede determinar estáticamente en tiempo de compilación, entonces el llamador debe asignar espacio para ese valor en tiempo de ejecución y pasar un puntero a ese espacio en r0.
Las subrutinas deben preservar el contenido de r4 a r11 y el puntero de pila (quizás guardándolos en la pila en el prólogo de la función , luego usándolos como espacio de trabajo y luego restaurándolos desde la pila en el epílogo de la función ). En particular, las subrutinas que llaman a otras subrutinas deben guardar la dirección de retorno en el registro de enlace r14 en la pila antes de llamar a esas otras subrutinas. Sin embargo, dichas subrutinas no necesitan devolver ese valor a r14; solo necesitan cargar ese valor en r15, el contador del programa, para regresar.
La convención de llamadas ARM exige el uso de una pila completamente descendente. Además, el puntero de la pila siempre debe estar alineado con 4 bytes y siempre debe estar alineado con 8 bytes en una llamada de función con una interfaz pública. [3]
Esta convención de llamada hace que una subrutina ARM "típica":
- En el prólogo, inserte r4 a r11 en la pila y inserte la dirección de retorno en r14 en la pila (esto se puede hacer con una sola instrucción STM);
- Copiar cualquier argumento pasado (en r0 a r3) a los registros scratch locales (r4 a r11);
- Asignar otras variables locales a los registros scratch locales restantes (r4 a r11);
- Realice cálculos y llame a otras subrutinas según sea necesario utilizando BL, asumiendo que r0 a r3, r12 y r14 no se conservarán;
- Coloque el resultado en r0;
- En el epílogo, extraiga r4 a r11 de la pila y extraiga la dirección de retorno al contador de programa r15. Esto se puede hacer con una sola instrucción LDM.
BRAZO (A64)
La convención de llamada ARM de 64 bits ( AArch64 ) asigna los 31 registros de propósito general como: [4]
- x31 (SP): Puntero de pila o un registro cero, según el contexto.
- x30 (LR): Registro de enlace de procedimiento, utilizado para regresar de subrutinas.
- x29 (FP): Puntero de marco.
- x19 a x28: Callee-guardado.
- x18 (PR): registro de plataforma. Se utiliza para algún propósito especial específico del sistema operativo o como registro adicional guardado por el autor de la llamada.
- x16 (IP0) y x17 (IP1): registros scratch de llamada intra-procedimiento.
- x9 a x15: Variables locales, llamador guardado.
- x8 (XR): Dirección de valor de retorno indirecto.
- x0 a x7: Valores de argumentos pasados a y resultados devueltos desde una subrutina.
Todos los registros que comienzan con x tienen un registro correspondiente de 32 bits con el prefijo w . Por lo tanto, un x0 de 32 bits se denomina w0.
De manera similar, los 32 registros de punto flotante se asignan como: [5]
- v0 a v7: Valores de argumentos pasados a y resultados devueltos desde una subrutina.
- v8 a v15: se guarda el destinatario, pero solo es necesario conservar los 64 bits inferiores.
- v16 a v31: Variables locales, llamador guardado.
ISA RISC-V
RISC-V tiene una convención de llamada definida con dos variantes, con o sin punto flotante. [6] Pasa argumentos en registros siempre que sea posible.
POWER, PowerPC y Power ISA
Las arquitecturas POWER , PowerPC y Power ISA tienen una gran cantidad de registros, por lo que la mayoría de las funciones pueden pasar todos los argumentos en registros para llamadas de un solo nivel . Los argumentos adicionales se pasan en la pila y siempre se asigna espacio para argumentos basados en registros en la pila como una conveniencia para la función llamada en caso de que se utilicen llamadas de varios niveles (recursivas o de otro tipo) y se deban guardar los registros. Esto también es útil en funciones variádicas , como printf(), donde se debe acceder a los argumentos de la función como una matriz. Se utiliza una única convención de llamada para todos los lenguajes procedimentales.
Las instrucciones de ramificación y enlace almacenan la dirección de retorno en un registro de enlace especial separado de los registros de propósito general; una rutina regresa a su llamador con una instrucción de ramificación que usa el registro de enlace como la dirección de destino. Las rutinas de hoja no necesitan guardar o restaurar el registro de enlace; las rutinas que no son de hoja deben guardar la dirección de retorno antes de realizar una llamada a otra rutina y restaurarla antes de que regrese, guardándola mediante la instrucción Mover desde registro de propósito especial para mover el registro de enlace a un registro de propósito general y, si es necesario, guardándola luego en la pila y restaurándola, si se guardó en la pila, cargando el valor del registro de enlace guardado en un registro de propósito general y luego usando la instrucción Mover a registro de propósito especial para mover el registro que contiene el valor del registro de enlace guardado al registro de enlace.
MIPS
La ABI O32 [7] es la más utilizada, debido a su condición de ABI original de System V para MIPS. [8] Está basada estrictamente en pila, con solo cuatro registros disponibles para pasar argumentos. Esta lentitud percibida, junto con un modelo de punto flotante antiguo con solo 16 registros, ha fomentado la proliferación de muchas otras convenciones de llamada. La ABI tomó forma en 1990 y nunca se actualizó desde 1994. Solo está definida para MIPS de 32 bits, pero GCC ha creado una variación de 64 bits llamada O64. [9]$a0-$a3
Para 64 bits, la ABI de N64 (no relacionada con Nintendo 64 ) de Silicon Graphics es la más utilizada. La mejora más importante es que ahora hay ocho registros disponibles para el paso de argumentos; también aumenta el número de registros de punto flotante a 32. También existe una versión ILP32 llamada N32, que utiliza punteros de 32 bits para código más pequeño, análogo a la ABI x32 . Ambas se ejecutan bajo el modo de 64 bits de la CPU. [9]
Se han hecho algunos intentos para reemplazar O32 con una ABI de 32 bits que se parezca más a N32. En una conferencia de 1995 se presentó MIPS EABI, para la cual la versión de 32 bits era bastante similar. [10] EABI inspiró a MIPS Technologies a proponer una ABI "NUBI" más radical que además reutiliza los registros de argumentos para el valor de retorno. [11] GCC admite MIPS EABI, pero no LLVM; ninguno admite NUBI.
Para todos los sistemas O32 y N32/N64, la dirección de retorno se almacena en un $raregistro. Esto se establece automáticamente con el uso de las instrucciones JAL(saltar y enlazar) o JALR(saltar y enlazar registro). La pila crece hacia abajo.
SPARC
La arquitectura SPARC , a diferencia de la mayoría de las arquitecturas RISC , está construida sobre ventanas de registro . Hay 24 registros accesibles en cada ventana de registro: 8 son los registros "in" (%i0-%i7), 8 son los registros "locales" (%l0-%l7) y 8 son los registros "out" (%o0-%o7). Los registros "in" se utilizan para pasar argumentos a la función que se está llamando, y cualquier argumento adicional debe colocarse en la pila . Sin embargo, la función llamada siempre asigna espacio para manejar un potencial desbordamiento de la ventana de registro, variables locales y (en SPARC de 32 bits) devolver una estructura por valor. Para llamar a una función, se colocan los argumentos para la función que se va a llamar en los registros "out"; cuando se llama a la función, los registros "out" se convierten en los registros "in" y la función llamada accede a los argumentos en sus registros "in". Cuando se completa la función llamada, coloca el valor de retorno en el primer registro "de entrada", que se convierte en el primer registro "de salida" cuando la función llamada regresa.
La ABI del System V , [12] que siguen la mayoría de los sistemas modernos tipo Unix , pasa los primeros seis argumentos en los registros "de entrada" %i0 a %i5, reservando %i6 para el puntero del marco y %i7 para la dirección de retorno.
IBM System/360 y sucesores
El IBM System/360 es otra arquitectura sin una pila de hardware. Los ejemplos siguientes ilustran la convención de llamada utilizada por OS/360 y sus sucesores antes de la introducción de z/Architecture de 64 bits ; otros sistemas operativos para System/360 pueden tener convenciones de llamada diferentes.
Programa de llamada:
LA 1,ARGS Cargar la dirección de la lista de argumentos
L 15,=A(SUB) Cargar dirección de subrutina
BALR 14,15 Ramal a llamada rutina 1
...
ARGS DC A(PRIMER) Dirección del primer argumento
DC A(SEGUNDO)
...
DC A(TERCERO)+X'80000000' Último argumento 2
Programa llamado:
SUB EQU * Este es el punto de entrada del subprograma
Secuencia de entrada estándar:
USANDO *,15 3
STM 14,12,12(13) Guardar registros 4
ST 13, GUARDAR+4 Guardar la dirección del área de guardado del llamante
LA 12, GUARDAR Cadena de zonas de guardado
S. 12,8(13)
LR 13,12
...
Secuencia de retorno estándar:
L 13, GUARDAR+4 5
LM 14,12,12(13)
L 15, RETIRO 6
BR 14 Regresar a la llamada
GUARDAR DS 18F Área de guardado 7
Notas:
- La
BALRinstrucción almacena la dirección de la siguiente instrucción (dirección de retorno) en el registro especificado por el primer argumento (registro 14) y se ramifica a la dirección del segundo argumento en el registro 15. - El llamador pasa la dirección de una lista de direcciones de argumentos en el registro 1. La última dirección tiene el bit de orden superior configurado para indicar el final de la lista. Esto limita los programas que utilizan esta convención a direcciones de 31 bits .
- La dirección de la rutina llamada está en el registro 15. Normalmente, esta se carga en otro registro y el registro 15 no se utiliza como registro base.
- La
STMinstrucción guarda los registros 14, 15 y 0 a 12 en un área de 72 bytes proporcionada por el invocador, denominada área de guardado a la que apunta el registro 13. La rutina llamada proporciona su propia área de guardado para que la utilicen las subrutinas que llama; la dirección de esta área normalmente se guarda en el registro 13 durante toda la rutina. Las instrucciones siguientesSTMactualizan las cadenas hacia adelante y hacia atrás que vinculan esta área de guardado con el área de guardado del invocador. - La secuencia de retorno restaura los registros del llamador.
- El registro 15 generalmente se utiliza para pasar un valor de retorno.
- Declarar un
saveareaestáticamente en la rutina llamada lo hace no reentrante y no recursivo ; un programa reentrante utiliza un dinámicosavearea, adquirido ya sea del sistema operativo y liberado al regresar, o en el almacenamiento pasado por el programa que llama.
En la ABI System/390 [13] y la ABI z/Architecture [14] , utilizadas en Linux:
- Los registros 0 y 1 son volátiles
- Los registros 2 y 3 se utilizan para pasar parámetros y devolver valores.
- Los registros 4 y 5 también se utilizan para pasar parámetros.
- El registro 6 se utiliza para pasar parámetros y el destinatario debe guardarlo y restaurarlo.
- Los registros 7 a 13 son para uso del destinatario de la llamada, y ellos deben guardarlos y restaurarlos.
- El registro 14 se utiliza para la dirección de retorno.
- El registro 15 se utiliza como puntero de pila.
- Los registros de punto flotante 0 y 2 se utilizan para pasar parámetros y devolver valores.
- Los registros de punto flotante 4 y 6 son para uso del destinatario de la llamada, y ellos deben guardarlos y restaurarlos.
- En z/Architecture, los registros de punto flotante 1, 3, 5 y 7 a 15 son para uso del destinatario de la llamada.
- El registro de acceso 0 está reservado para uso del sistema.
- Los registros de acceso 1 a 15 son para uso del destinatario de la llamada.
Se pasan argumentos adicionales a la pila.
Súper H
Nota: las reservas "preservadas" corresponden al ahorro del destinatario; lo mismo aplica para las "garantizadas".
68k
La convención de llamada más común para la serie Motorola 68000 es: [15] [16] [17] [18]
- d0, d1, a0 y a1 son registros scratch
- Todos los demás registros se guardan en el destinatario de la llamada.
- a6 es el puntero del marco, que se puede desactivar mediante una opción del compilador
- Los parámetros se introducen en la pila, de derecha a izquierda.
- El valor de retorno se almacena en d0
IBM 1130
El IBM 1130 era una pequeña máquina direccionable por palabra de 16 bits. Tenía solo seis registros más indicadores de condición y no tenía pila. Los registros son Registro de dirección de instrucción (IAR) , Acumulador (ACC) , Extensión de acumulador (EXT) y tres registros de índice X1–X3. El programa que realiza la llamada es responsable de guardar ACC, EXT, X1 y X2. [19] Hay dos pseudooperaciones para llamar a subrutinas, CALLpara codificar subrutinas no reubicables vinculadas directamente con el programa principal y LIBFpara llamar a subrutinas de biblioteca reubicables a través de un vector de transferencia . [20] Ambas pseudooperaciones se resuelven en una instrucción de máquina Branch and Store IAR ( BSI) que almacena la dirección de la siguiente instrucción en su dirección efectiva (EA) y se ramifica a EA+1.
Los argumentos siguen a BSI—normalmente son direcciones de argumentos de una palabra—la rutina llamada debe saber cuántos argumentos esperar para poder omitirlos al regresar. Alternativamente, los argumentos se pueden pasar en registros. Las rutinas de función devolvieron el resultado en ACC para argumentos reales, o en una ubicación de memoria denominada Pseudoacumulador de números reales (FAC). Los argumentos y la dirección de retorno se direccionaron utilizando un desplazamiento al valor IAR almacenado en la primera ubicación de la subrutina.
* Ejemplo de subrutina 1130
ENT SUB Declara "SUB" un punto de entrada externo
SUB DC 0 Palabra reservada en el punto de entrada, codificada convencionalmente "DC *-*"
* El código de subrutina comienza aquí
* Si hubiera argumentos las direcciones se pueden cargar indirectamente desde la dirección de retorno
LDX I 1 SUB Cargar X1 con la dirección del primer argumento (por ejemplo)
...
* Secuencia de retorno
LD RES Cargar resultado entero en ACC
* Si no se proporcionaron argumentos, rama indirecta a la dirección de retorno almacenada
BI SUB Si no se proporcionaron argumentos
FIN DEL SUB
Las subrutinas en IBM 1130, CDC 6600 y PDP-8 (las tres computadoras se introdujeron en 1965) almacenan la dirección de retorno en la primera ubicación de una subrutina. [21]
Convenciones de llamadas fuera de las arquitecturas de las máquinas
Código enhebrado
El código enhebrado asigna toda la responsabilidad de la configuración y la limpieza después de una llamada de función al código llamado. El código de llamada no hace nada más que enumerar las subrutinas que se llamarán. Esto coloca todo el código de configuración y limpieza de la función en un solo lugar (el prólogo y el epílogo de la función) en lugar de en los muchos lugares en los que se llama a la función. Esto hace que el código enhebrado sea la convención de llamada más compacta.
El código enhebrado pasa todos los argumentos en la pila. Todos los valores de retorno se devuelven en la pila. Esto hace que las implementaciones ingenuas sean más lentas que las convenciones de llamada que mantienen más valores en los registros. Sin embargo, las implementaciones de código enhebrado que almacenan en caché varios de los valores superiores de la pila en los registros (en particular, la dirección de retorno) suelen ser más rápidas que las convenciones de llamada de subrutinas que siempre insertan y extraen la dirección de retorno en la pila. [22] [23] [24]
PL/YO
La convención de llamada predeterminada para los programas escritos en el lenguaje PL/I pasa todos los argumentos por referencia , aunque se pueden especificar opcionalmente otras convenciones. Los argumentos se manejan de forma diferente para distintos compiladores y plataformas, pero normalmente las direcciones de los argumentos se pasan a través de una lista de argumentos en memoria. Se puede pasar una dirección final, oculta, que apunte a un área para contener el valor de retorno. Debido a la amplia variedad de tipos de datos admitidos por PL/I, también se puede pasar un descriptor de datos para definir, por ejemplo, las longitudes de cadenas de caracteres o bits, la dimensión y los límites de matrices ( vectores dope ) o el diseño y el contenido de una estructura de datos . Se crean argumentos ficticios para argumentos que son constantes o que no concuerdan con el tipo de argumento que espera el procedimiento llamado.
Véase también
Referencias
- ^ ab "Convenciones de llamada". cs.cornell.edu . Consultado el 5 de marzo de 2024 .
- ^ "/Oy (Omisión de puntero de marco)". learn.microsoft.com . 3 de agosto de 2021 . Consultado el 14 de junio de 2024 .
- ^ "Estándar de llamada a procedimiento para la arquitectura ARM". 2021.
- ^ "Parámetros en registros de propósito general". Guía del programador de la serie ARM Cortex-A para ARMv8-A . Consultado el 12 de noviembre de 2020 .
- ^ "Parámetros en NEON y registros de punto flotante". developer.arm.com . Consultado el 13 de noviembre de 2020 .
- ^ "Convención de llamada RISC-V" (PDF) .
- ^ "Referencia rápida del conjunto de instrucciones MIPS32".
- ^ Sweetman, Dominic. Véase MIPS Run (2.ª edición). Morgan Kaufmann Publishers . ISBN 0-12088-421-6.
- ^ ab "Historia de MIPS ABI".
- ^ Christopher, Eric (11 de junio de 2003). «mips eabi documentation». binutils@sources.redhat.com (lista de correo) . Consultado el 19 de junio de 2020 .
- ^ "NUBI".
- ^ Suplemento del procesador SPARC de interfaz binaria de aplicación del sistema V (3.ª edición).
- ^ "Suplemento de interfaz binaria de aplicación S/390 ELF".
- ^ "Suplemento de interfaz binaria de aplicación ELF zSeries".
- ^ Smith, Dr. Mike. "Comparación de registros SHARC (21k) y 68k".
- ^ XGCC: El sistema de lenguaje Gnu C/C++ para desarrollo integrado (PDF) . Embedded Support Tools Corporation. 2000. pág. 59.
- ^ "COLDFIRE/68K: ThreadX para la familia ColdFire de Freescale". Archivado desde el original el 2 de octubre de 2015.
- ^ Moshovos, Andreas. "Subrutinas continuas: paso de argumentos, retorno de valores y asignación de variables locales".
Todos los registros excepto d0, d1, a0, a1 y a7 deben conservarse en una llamada.
- ^ IBM Corporation (1967). IBM 1130 Disk Monitor System, Version 2 System Introduction (C26-3709-0) (PDF) . pág. 67 . Consultado el 21 de diciembre de 2014 .
- ^ IBM Corporation (1968). Lenguaje ensamblador IBM 1130 (C26-5927-4) (PDF) . págs. 24–25.
- ^ Smotherman, Mark (2004). "Soporte de llamadas a subrutinas y procedimientos: historia temprana".
- ^ Rodríguez, Brad. "Avanzando, parte 1: decisiones de diseño en el núcleo Forth".
En el 6809 o el Zilog Super8, el DTC es más rápido que el STC.
- ^ Ertl, Anton. "Velocidad de diversas técnicas de envío de intérpretes".
- ^ Zaleski, Mathew (2008). "Capítulo 4: Diseño e implementación de una interpretación eficiente". YETI: un intérprete de seguimiento gradualmente extensible .
Aunque se sabe que los intérpretes de subprocesos directos tienen propiedades de predicción de bifurcaciones deficientes... la latencia de una llamada y un retorno puede ser mayor que la de un salto indirecto.
Enlaces externos
- Johnson, Stephen Curtis ; Ritchie, Dennis MacAlistair (septiembre de 1981). "Informe técnico de ciencias de la computación n.º 102: La secuencia de llamadas del lenguaje C". Bell Laboratories .
- Introducción al ensamblaje en PowerPC
- Guía de llamadas a funciones ABI de Mac OS X
- Estándar de llamada a procedimiento para la arquitectura ARM
- Programación integrada con la cadena de herramientas GNU, Sección 10. Inicio en C