4

LLVM では、通常、生成された関数を で終了しますCreateRetが、関数でインスタンス化されたローカル オブジェクトのクリーンアップ デストラクタを追加したいと考えています。

私の質問は: を挿入する前にクリーンアップ関数呼び出しを挿入するCreateRet必要があると思いますが、戻り値がローカルの 1 つであるかどうか疑問に思っています (値で返されていると仮定します)。 、しかし、ローカルは返された後も破壊されないので、ローカルの寿命とクリーンアップを適切に挿入する場所について少し混乱していると思います

4

2 に答える 2

2

C++ の逆アセンブリを見てみましょう。:)
通常、戻り値をスタックに保存し、すべてのローカル オブジェクトのデストラクタを呼び出してから、戻り値をスタックからeaxレジスタに移動します (cdecl 呼び出し規約)。デストラクタはそのeaxレジスタを変更できるため、保存が必要です。
たとえば、次の非常に架空の疑似アセンブリを見てください。

// inside imaginary function
mov [ebp-0Ch],eax; // save eax register
lea ecx, [ebp-4]; // [ebp-4] == your object address
call Foo::~Foo(); // call the destructor
mov eax,[ebp-0Ch]; // retrieve the saved return value
ret; // now return

返された値がローカル オブジェクトの場合は、もちろん、最初にそのオブジェクトを準備されたスペースにコピーする必要があります。

// pseudo function call
int i = func();

ここでは、戻り値のスペースがfuncスタックに提供され、そこに戻り値をコピーします。その後、上記のように進みます。

于 2011-05-14T03:16:50.583 に答える
2

ソース言語のreturnステートメント/式を return ストレージへのコピーとしてコード生成し、続いて指定された return 基本ブロックへの分岐を行うことができます。これにより、ローカルが破棄されます。生成された LLVM 関数が独自のプロトコルに従うのではなく (最初のパラメーターを介して値を返すなどして) 値自体を返す場合は、戻り値をalloca最初に保存し、それを読み込んでallocaで返すことができretます。%valuetype言語ランタイムに値を格納する構造体を示す、最初のパラメーターを介して戻る場合の例

define void @myfn(%valuetype *%ret) {
  ; use and create whatever locals you need

  ; source-language: return somelocal
  store %valuetype %local1, %valuetype *%ret
  br label %retlabel

retlabel:
  ; emit code to destruct locals ..., then return
  ret void
}
于 2011-05-14T11:49:50.907 に答える