CreateRet
退出生成的函数,但是,我想为函数中实例化的本地对象添加清理析构函数。
我的问题是:我假设我必须在插入CreateRet
之前插入清理函数调用,但是,我想知道返回值是否是本地人之一(假设我们按值返回)然后我们不能在返回之前破坏这个值,但是在返回之后本地也不会被破坏,所以我会说我对当地人的生命以及在哪里正确插入清理
答案 0 :(得分:2)
您可以将源语言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
}
答案 1 :(得分:1)
看看一些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
的空间将在堆栈中提供,这是您复制返回值的位置。之后,按上图所示进行操作。