3

fortranコードをオブジェクトファイルにコンパイルする場合:コンパイラはどのようにシンボル名を決定しますか?

組み込み関数「getarg」を使用すると、コンパイラはそれを「_getarg@12」というシンボルに変換します。

外部ライブラリを調べたところ、内部のシンボル名は「_getarg @ 16」と呼ばれていることがわかりました。「getarg」の最後にある「@[number]」の意味は何ですか?

4

2 に答える 2

4

_name@lengthPascalの呼び出し規約の変形である呼び出し規約stdcall(またはCで使用されるキーワードの名前)に従うルーチンの名前に適用される、Windows固有の名前マングリングです。__stdcallこれは、すべてのWin32 API関数で使用される呼び出し規約です。DLLのエクスポートテーブルを次のようKERNEL32.DLLUSER32.DLL見ると、すべてのシンボルに次のような名前が付けられていることがわかります。

装飾は_...@length、ルーチン引数が占めるバイト数を示します。これが必要なのは、stdcall呼び出し規約では、C呼び出し規約の場合のように呼び出し元ではなく、スタックから引数をクリーンアップするのは呼び出し先であるためです。コンパイラfuncが2つの4バイト引数を使用してへの呼び出しを生成すると_func@8、オブジェクトコードにへの参照が配置されます。実数funcの引数の数やサイズが異なる場合、その装飾された名前は別のものになります。たとえば_func@12、リンクエラーが発生します。これは、ダイナミックライブラリ(DLL)で非常に役立ちます。funcDLLが、 1つの追加の引数を取る別のバージョンに置き換えられたと想像してください。名前マングリング(前置の専門用語)がなかった場合_シンボル名に追加@length)、プログラムはfunc間違った引数で呼び出しを行いfunc、渡された引数リストのサイズよりも多くのバイトでスタックポインターをインクリメントするため、呼び出し元が壊れます。名前マングリングが適切に行われていると、ローダーはへの参照を解決できないため、実行可能ファイルをまったく起動しません_func@8

あなたの場合、外部ライブラリは実際にはこのコンパイラで使用することを意図していないようです。または、プラグマまたはコンパイラオプションがありません。組み込み関数は2つのgetarg引数を取ります。1つは整数で、もう1つは想定サイズの文字配列(文字列)です。一部のコンパイラは、文字配列サイズを追加の引数として渡します。32ビットコードの場合、これにより2つのポインタと1つの整数が渡され、合計で12バイトの引数が渡されます_getarg@12_getarg@16たとえば、ある種の記述子によって文字列が渡される64ビットルーチンである可能性があります。

IanHが彼のコメントで私に思い出させたように、この名前の不一致のもう1つの理由はgetarg、予想よりも少ない引数で呼び出していることである可能性があります。Fortranには、「プロトタイプのない」ルーチン呼び出しというこの独特の機能があります。Fortranコンパイラーは、明示的な署名を関数プロトタイプの形式で提供する必要があるC / C ++とは異なり、署名を実際に知らなくてもルーチンへの呼び出しを生成できます。これが可能なのは、Fortranではすべての引数が参照によって渡され、ポインターが指す実際の型に関係なく、ポインターは常に同じサイズであるためです。この特定のケースでは、stdcall名前マングリングは非常に大雑把な引数チェックメカニズムの役割を果たします。マングリングがなかった場合(たとえば、そのような装飾が採用されていないGNU Fortranを使用したLinuxの場合、またはデフォルトの呼び出し規約がcdecl)予想とは異なる数の引数を使用してルーチンを呼び出すことができ、リンカはオブジェクトコードを実行可能ファイルにリンクします。実行可能ファイルは、実行時にクラッシュする可能性があります。

于 2012-11-18T17:08:08.017 に答える
2

これは完全に実装に依存します。どのコンパイラを使用しているのか、あなたは言いませんでした。(非標準の)組み込み関数は、さまざまな整数または文字の種類に対して、より多くのバージョンで存在する可能性があります。より多くのコンピュータアーキテクチャ(32ビットや64ビットなど)用に、ランタイムライブラリのバージョンを増やすこともできます。

于 2012-11-18T07:41:51.633 に答える