Agregaré otra respuesta, para abordar algunas de las discusiones tangenciales que tuvieron lugar.
El C ABI (interfaz binaria de la aplicación) originalmente solicitó pasar argumentos en la pila en orden inverso (es decir, empujado de derecha a izquierda), donde la persona que llama también libera el almacenamiento de la pila. El ABI moderno en realidad usa registros para pasar argumentos, pero muchas de las consideraciones de cambio se remontan a la aprobación del argumento de pila original.
El ABI Pascal original, por el contrario, empujó los argumentos de izquierda a derecha, y el destinatario tuvo que reventar los argumentos. El C ABI original es superior al Pascal ABI original en dos puntos importantes. El orden de inserción de argumentos significa que siempre se conoce el desplazamiento de la pila del primer argumento, lo que permite funciones que tienen un número desconocido de argumentos, donde los primeros argumentos controlan cuántos otros argumentos hay (ala printf
).
La segunda forma en que el C ABI es superior es el comportamiento en caso de que la persona que llama y la persona que llama no estén de acuerdo sobre cuántos argumentos hay. En el caso C, siempre y cuando no acceda a argumentos más allá del último, no pasa nada malo. En Pascal, se saca una cantidad incorrecta de argumentos de la pila y se corrompe toda la pila.
El ABI original de Windows 3.1 estaba basado en Pascal. Como tal, usó el ABI de Pascal (argumentos en orden de izquierda a derecha, pops callee). Dado que cualquier discrepancia en el número de argumento podría conducir a la corrupción de la pila, se formó un esquema de distribución. Cada nombre de función fue destrozado con un número que indica el tamaño, en bytes, de sus argumentos. Entonces, en una máquina de 16 bits, la siguiente función (sintaxis C):
int function(int a)
Fue destrozado function@2
porque int
tiene dos bytes de ancho. Esto se hizo para que si la declaración y la definición no coinciden, el vinculador no podrá encontrar la función en lugar de dañar la pila en tiempo de ejecución. Por el contrario, si el programa se vincula, puede estar seguro de que el número correcto de bytes aparece de la pila al final de la llamada.
Windows de 32 bits en adelante usa el stdcall
ABI en su lugar. Es similar al Pascal ABI, excepto que el orden de inserción es como en C, de derecha a izquierda. Al igual que el ABI de Pascal, el cambio de nombre altera el tamaño del byte de argumentos en el nombre de la función para evitar la corrupción de la pila.
A diferencia de las afirmaciones hechas aquí, el C ABI no destruye los nombres de las funciones, incluso en Visual Studio. Por el contrario, las funciones de manipulación decoradas con la stdcall
especificación ABI no son exclusivas de VS. GCC también admite este ABI, incluso cuando compila para Linux. Wine lo utiliza ampliamente , ya que utiliza su propio cargador para permitir la vinculación en tiempo de ejecución de archivos binarios compilados de Linux a archivos DLL compilados de Windows.