Graham Wakefield
2011-Sep-09 20:36 UTC
[LLVMdev] runStaticConstructorsDestructors not calling static destructors
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! 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
Graham Wakefield
2011-Sep-09 20:41 UTC
[LLVMdev] runStaticConstructorsDestructors not calling static destructors
Another data point - it looks like the destructors are called when the running program exits (which crashes because the machine code has been freed). Is there a configuration to LLVM or Clang to tell it to put the destructors in a different location than __cxa_atexit ? Thanks~ On Sep 9, 2011, at 1:36 PM, Graham Wakefield 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! > > 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 >
Eli Friedman
2011-Sep-09 20:42 UTC
[LLVMdev] runStaticConstructorsDestructors not calling static destructors
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 >
Graham Wakefield
2011-Sep-09 20:56 UTC
[LLVMdev] runStaticConstructorsDestructors not calling static destructors
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 >>
Seemingly Similar Threads
- [LLVMdev] runStaticConstructorsDestructors not calling static destructors
- runStaticConstructorsDestructors() causes crash on exit
- [LLVMdev] having troubles mixing ExecutionEngine::runStaticConstructorsDestructors() and Linker::LinkModules()
- runStaticConstructorsDestructors() causes crash on exit
- runStaticConstructorsDestructors() causes crash on exit