Acrescentarei outra resposta, para abordar algumas das discussões tangenciais que ocorreram.
O C ABI (interface binária do aplicativo) originalmente pedia a passagem de argumentos na pilha na ordem inversa (ou seja, pressionada da direita para a esquerda), onde o chamador também libera o armazenamento da pilha. A ABI moderna realmente usa registradores para passar argumentos, mas muitas das considerações desconcertantes remontam à passagem original do argumento da pilha.
O Pascal ABI original, em contraste, empurrou os argumentos da esquerda para a direita, e o chamado teve que aparecer. O ABI C original é superior ao ABI Pascal original em dois pontos importantes. A ordem de envio de argumentos significa que o deslocamento da pilha do primeiro argumento é sempre conhecido, permitindo funções que possuem um número desconhecido de argumentos, onde os argumentos iniciais controlam quantos outros argumentos existem (ala printf
).
A segunda maneira pela qual a C ABI é superior é o comportamento, caso o chamador e o destinatário não concordem com quantos argumentos existem. No caso C, desde que você não acesse argumentos anteriores ao último, nada de ruim acontece. Em Pascal, o número errado de argumentos é exibido na pilha e a pilha inteira está corrompida.
O ABI original do Windows 3.1 foi baseado em Pascal. Como tal, utilizou o Pascal ABI (argumentos da esquerda para a direita, chamados poplee). Como qualquer incompatibilidade no número do argumento pode levar à corrupção da pilha, um esquema confuso foi formado. Cada nome de função foi desconfigurado com um número indicando o tamanho, em bytes, de seus argumentos. Portanto, na máquina de 16 bits, a seguinte função (sintaxe C):
int function(int a)
Foi manipulado para function@2
, porque int
tem dois bytes de largura. Isso foi feito para que, se a declaração e a definição não coincidirem, o vinculador falhará ao encontrar a função em vez de corromper a pilha no tempo de execução. Por outro lado, se o programa for vinculado, você poderá ter certeza de que o número correto de bytes será exibido da pilha no final da chamada.
Windows de 32 bits e em diante use a stdcall
ABI. É semelhante ao Pascal ABI, exceto que a ordem de envio é como em C, da direita para a esquerda. Assim como a Pascal ABI, o nome mangling manipula o tamanho do byte de argumentos no nome da função para evitar a corrupção da pilha.
Diferentemente das declarações feitas em outros lugares aqui, o C ABI não altera os nomes das funções, mesmo no Visual Studio. Por outro lado, as funções de desconfiguração decoradas com a stdcall
especificação ABI não são exclusivas do VS. O GCC também suporta essa ABI, mesmo ao compilar para Linux. Isso é usado extensivamente pelo Wine , que usa seu próprio carregador para permitir a vinculação em tempo de execução dos binários compilados do Linux às DLLs compiladas do Windows.