私が行った接線方向の議論のいくつかに対処するために、もう1つの答えを追加します。
C ABI(アプリケーションバイナリインターフェイス)は、元々スタックに引数を逆の順序で渡すことを求めていました(つまり、右から左にプッシュされました)。この場合、呼び出し元もスタックストレージを解放します。現代のABIは実際には引数を渡すためにレジスターを使用しますが、マングル化の考慮事項の多くは、元のスタック引数の受け渡しに戻ります。
対照的に、元のPascal ABIは引数を左から右にプッシュし、呼び出し先は引数をポップする必要がありました。オリジナルのC ABIは、2つの重要な点でオリジナルのPascal ABIより優れています。引数のプッシュ順序は、最初の引数のスタックオフセットが常にわかっていることを意味し、未知の数の引数を持つ関数を許可します。初期の引数は、他の引数の数を制御します(ala printf
)。
C ABIが優れている2番目の方法は、呼び出し元と呼び出し先が引数の数に同意しない場合の動作です。Cの場合、実際に最後の引数を過ぎて引数にアクセスしない限り、何も悪いことは起こりません。Pascalでは、誤った数の引数がスタックからポップされ、スタック全体が破損します。
オリジナルのWindows 3.1 ABIはPascalに基づいていました。そのため、Pascal ABI(左から右の順序の引数、呼び出し先ポップ)を使用しました。引数番号の不一致はスタックの破損につながる可能性があるため、マングリング方式が形成されました。各関数名は、その引数のサイズ(バイト単位)を示す数値でマングルされました。したがって、16ビットマシンでは、次の関数(C構文)を使用します。
int function(int a)
は2バイト幅なfunction@2
ので、にマングルされましたint
。これは、宣言と定義が一致しない場合に、リンカが実行時にスタックを破壊するのではなく、関数を見つけられないようにするために行われました。逆に、プログラムがリンクしている場合は、呼び出しの最後にスタックから正しいバイト数が確実にポップされます。
32ビットWindows以降では、stdcall
代わりにABIを使用します。これはPascal ABIに似ていますが、Cの場合と同様に、右から左へのプッシュ順です。Pascal ABIのように、名前のマングリングは、引数のバイトサイズを関数名に変換して、スタックの破損を回避します。
ここの他の場所で行われた主張とは異なり、C ABIはVisual Studioであっても関数名を壊しません。逆に、stdcall
ABI仕様で装飾されたマングリング関数は、VSに固有のものではありません。Linux用にコンパイルする場合でも、GCCはこのABIもサポートします。これは、独自のローダーを使用してLinuxコンパイル済みバイナリをWindowsコンパイル済みDLLに実行時にリンクできるようにするWineで広く使用されています。