0

インライン化されない次の関数を検討し、プラットフォームとして x86 を想定します。

void doSomething(int & in){
//do something
}

まず、そのようなシナリオが発生するかどうかはわかりませんが、可能だと思うので、呼び出し元でこの関数が呼び出されるたびに、提供される引数が呼び出し元のスタックフレームの正確に一番上にあるように尋ねるつもりです。呼び出された関数は、アセンブリ言語で ebp レジスタ (呼び出し先が esp の内容を ebp に移動した後) を介してアクセスすることが可能です。関数定義をそのままにして、それが何をするかをコンパイラに任せますか? コンパイラーがそのような例外的なケースを呼び出し規則の要因と見なすことをどこにも読んだことがないので、引数へのポインターを呼び出し先スタックフレームまたはレジスターの1つに渡すコードを生成するだけだと思います

4

3 に答える 3

4

まず第一に、これは非常に簡単に壊れます。たとえば、別のバージョンのコンパイラを入手すると、コードが異なる方法で生成されます。または、最適化機能を変更します。doSomething変数がスタックの一番上にないため、突然別の場所で使用する必要が生じた場合でも、それが機能しないという状況は気にしないでください。

第 2 に、関数内のコードが十分に短いと仮定すると、コンパイラが関数をインライン化する可能性が高いため、何も「失う」ことはありません。

第 3 に、最新のコンパイラの単一の引数は通常、とにかくレジスタに渡されるため、最適化が有効になっている場合、これには利点がありません。

これに価値のある利点があり、コンパイラがコードをインライン化または最適化しないと本当に考えている場合 [生成されたコードを見ましたか? forceinline]always_inlineそのようなオプション)。それでもうまくいかない場合は、マクロを使用して手動でインライン化します。または、コードを「コピー アンド ペースト」で呼び出された場所に移動するだけです。

于 2013-07-05T08:21:44.967 に答える
2

あなたのメモ「提供される引数は呼び出し元のスタックフレームの一番上にあるため、呼び出された関数でebpレジスタを介してアクセスする」には事実上の誤解が含まれています。

それは、次のような理由によるものです。

  • スタックベースの呼び出し規約、つまり、関数の引数が関数を呼び出すpush前に呼び出し元によってスタックに追加されることを前提としてcallいます。一般的にはそうではありません。32 ビット x86 でも、スタックベースではない呼び出し規則があります (たとえば、Windowsfastcallまたは 32 ビット Linux カーネルで使用される GNU GCC のもの)。そのようなものが使用されている場合、引数はスタックの一番上ではなく、最初の引数を保持するために使用されているレジスタで見つかります。


    しかし、スタックベースのパラメーターを渡している場合でも...それでも:

  • x86では、少なくとも命令が戻りアドレスをスタックの一番上にcallプッシュしていることを見逃していたので、関数の最初の命令がその方法で実行されたときに、その関数の最初の引数を指しません。 、しかし、リターンアドレスに。ESP
  • EBP呼び出し先に保存された (関数呼び出しで保存された) レジスタであり、アーキテクチャによってユーザーに代わって初期化されていないことを見逃していました。生成されたコードで明示的に設定する必要があります。したがって、それを使用したい関数 (フレームポインタとしてのみであっても) は、使用する前にどこかに保存する必要があります。これは、通常のプロローグが持つことを意味しpush EBP; mov EBP, ESPます (無効な/実行できない呼び出し元を上書きするため、実行することはできません)。したがって、関数の最初の引数を参照したい場合は、必要ありません。 そうでない場合MOV EBP, ESPEBP[ EBP + 8 ] [ EBP ]
    フレームポインタを使用すると、最初の引数 (call戻りアドレスをプッシュした関数に到達するために使用されたため) は[ ESP + 4 ] not [ ESP ]になります。

これが少し明確になることを願っています。

質問を明確にすることが役立つという他のポスターに同意します。正確に何を達成したいのか、なぜここでアセンブリ言語が役立つと思うのか。

于 2013-07-15T10:24:54.110 に答える
1

いいえ、私はしません。呼び出し規約は異なる場合があります (x86 と x86_64 の間)。パラメータはスタックにプッシュするか、レジスタに入れることができますが、それらがどこにあるのかを確実に知ることができるかどうかはわかりません.

これをアセンブリで記述すると、自分が何をしているのか本当にわかっていない限り、未定義の動作コードにつながる可能性があります。

于 2013-07-05T07:47:03.070 に答える