[LLVMdev] runStaticConstructorsDestructors not calling static destructors

Eli Friedman eli.friedman at gmail.com
Fri Sep 9 13:42:28 PDT 2011


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