[LLVMdev] runStaticConstructorsDestructors not calling static destructors

Graham Wakefield wakefield at mat.ucsb.edu
Fri Sep 9 13:56:30 PDT 2011


Perfect - CodeGenOptions has the flag I needed!

CodeGenOptions.CGO;
CGO.CXAAtExit = 0;

Thanks for the fast reply!

On Sep 9, 2011, at 1:42 PM, Eli Friedman wrote:

> On Fri, Sep 9, 2011 at 1:36 PM, Graham Wakefield <wakefield at mat.ucsb.edu> wrote:
>> Hi there,
>> 
>> I'm having trouble getting ExecutionEngine->runStaticConstructorsDestructors(module, true) to actually trigger static destructors in my code. The static constructors however do get called.
>> 
>> I don't know if this is an LLVM or Clang issue, from looking at the IR (see below) it looks like the destructor is being tied to cxa_atexit, and I wonder if that is not called by runStaticConstructorsDestructors(module, true);
>> 
>> Thanks in advance for any suggestions you can offer!
> 
> Yes, that would do it... if you really need to be able to trigger
> static destructors for C++ objects before calling exit(), you'll need
> to mess with clang's IRGen.  grep for cxa_atexit in
> clang/lib/CodeGen/.
> 
> -Eli
> 
>> Graham
>> 
>> 
>> Using LLVM/Clang 2.9 release for OSX, on OSX 10.6.8, on a core i7 macbook pro.
>> 
>> I'm compiling from C++ using Clang, and passing the compiled module to an ExecutionEngine created as follows:
>> 
>> EE = llvm::EngineBuilder(globalModule)
>>                        .setEngineKind(llvm::EngineKind::JIT)
>>                        .setErrorStr(&err)
>>                        .setOptLevel(llvm::CodeGenOpt::Default)
>>                        .setAllocateGVsWithCode(false)
>>                        //.setMAttrs("-avx")
>>                        .setMCPU("core2")
>>                        .create();
>> EE->DisableLazyCompilation();
>> 
>> After passing in the compiled module, I call:
>> 
>> EE->runStaticConstructorsDestructors(module, false);
>> 
>> Then to test the tear-down of the module, I call:
>> 
>> EE->runStaticConstructorsDestructors(mImpl->module, true);
>> EE->clearGlobalMappingsFromModule(mImpl->module);
>> EE->removeModule(mImpl->module);
>> 
>> 
>> 
>> The C++ code compiled:
>> 
>> #include <stdio.h>
>> class Foo {
>> public:
>>        Foo() { printf("Foo\n"); };
>>        ~Foo() { printf("~Foo\n"); };
>> 
>>        int x;
>> };
>> 
>> // a static variable:
>> Foo foo;
>> 
>> 
>> The constructor is being called (I see 'Foo' in my stdout), but the destructor is not.
>> 
>> 
>> The LLVM IR produced:
>> 
>> ; ModuleID = 'mymodule'
>> target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
>> target triple = "i386-apple-darwin10"
>> 
>> %0 = type { i32, void ()* }
>> %class.Foo = type { i32 }
>> 
>> @foo = global %class.Foo zeroinitializer, align 4
>> @__dso_handle = external global i8*
>> @.str = private unnamed_addr constant [6 x i8] c"~Foo\0A\00"
>> @.str1 = private unnamed_addr constant [5 x i8] c"Foo\0A\00"
>> @llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @_GLOBAL__I_a }]
>> 
>> define internal void @__cxx_global_var_init() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
>>  call void @_ZN3FooC1Ev(%class.Foo* @foo)
>>  %1 = call i32 @__cxa_atexit(void (i8*)* bitcast (void (%class.Foo*)* @_ZN3FooD1Ev to void (i8*)*), i8* bitcast (%class.Foo* @foo to i8*), i8* bitcast (i8** @__dso_handle to i8*))
>>  ret void
>> }
>> 
>> define linkonce_odr void @_ZN3FooC1Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
>>  %1 = alloca %class.Foo*, align 4
>>  store %class.Foo* %this, %class.Foo** %1, align 4
>>  %2 = load %class.Foo** %1
>>  call void @_ZN3FooC2Ev(%class.Foo* %2)
>>  ret void
>> }
>> 
>> define linkonce_odr void @_ZN3FooD1Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
>>  %1 = alloca %class.Foo*, align 4
>>  store %class.Foo* %this, %class.Foo** %1, align 4
>>  %2 = load %class.Foo** %1
>>  call void @_ZN3FooD2Ev(%class.Foo* %2)
>>  ret void
>> }
>> 
>> declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
>> 
>> define linkonce_odr void @_ZN3FooD2Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
>>  %1 = alloca %class.Foo*, align 4
>>  store %class.Foo* %this, %class.Foo** %1, align 4
>>  %2 = load %class.Foo** %1
>>  %3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0))
>>  ret void
>> }
>> 
>> declare i32 @printf(i8*, ...)
>> 
>> define linkonce_odr void @_ZN3FooC2Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
>>  %1 = alloca %class.Foo*, align 4
>>  store %class.Foo* %this, %class.Foo** %1, align 4
>>  %2 = load %class.Foo** %1
>>  %3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str1, i32 0, i32 0))
>>  ret void
>> }
>> 
>> define internal void @_GLOBAL__I_a() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
>>  call void @__cxx_global_var_init()
>>  ret void
>> }
>> 
>> 
>> 
>> I added a JITEventListener, which displays:
>> 
>> JIT emitted Function _GLOBAL__I_a at 0x1c00010, size 12
>> JIT emitted Function __cxx_global_var_init at 0x1c00020, size 47
>> JIT emitted Function _ZN3FooD1Ev at 0x1c00060, size 23
>> JIT emitted Function _ZN3FooD2Ev at 0x1c00080, size 27
>> JIT emitted Function _ZN3FooC1Ev at 0x1c000a0, size 23
>> JIT emitted Function _ZN3FooC2Ev at 0x1c000c0, size 27
>> 
>> JIT freed 0x1c00020
>> JIT freed 0x1c000a0
>> JIT freed 0x1c00060
>> JIT freed 0x1c00080
>> JIT freed 0x1c000c0
>> JIT freed 0x1c00010
>> 
>> 
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>> 





More information about the llvm-dev mailing list