diff options
author | John McCall <rjmccall@apple.com> | 2012-04-06 18:21:06 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2012-04-06 18:21:06 +0000 |
commit | 30fa3707c440222f65fcbb78ee8677462ea0d9ce (patch) | |
tree | bc9373e70233fd57d77f32361c627807ea3f8391 /lib/CodeGen | |
parent | 3f88f686e32949ffe02ccb551f482f9cf810358b (diff) |
Use atexit when __cxa_atexit isn't available instead of adding a
global destructor entry. For some reason this isn't enabled for
apple-kexts; it'd be good to have documentation for that.
Based on a patch by Nakamura Takumi!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154191 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 124 |
1 files changed, 98 insertions, 26 deletions
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index ddfe26581e..99d50312b5 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -145,37 +145,109 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T); } -void -CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, - llvm::Constant *DeclPtr) { - // Generate a global destructor entry if not using __cxa_atexit. - if (!CGM.getCodeGenOpts().CXAAtExit) { - CGM.AddCXXDtorEntry(DtorFn, DeclPtr); - return; - } +/// Register a global destructor using __cxa_atexit. +static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, + llvm::Constant *dtor, + llvm::Constant *addr) { + // We're assuming that the destructor function is something we can + // reasonably call with the default CC. Go ahead and cast it to the + // right prototype. + llvm::Type *dtorTy = + llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, false)->getPointerTo(); + + // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d); + llvm::Type *paramTys[] = { dtorTy, CGF.Int8PtrTy, CGF.Int8PtrTy }; + llvm::FunctionType *atexitTy = + llvm::FunctionType::get(CGF.IntTy, paramTys, false); + + // Fetch the actual function. + llvm::Constant *atexit = + CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit"); + if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit)) + fn->setDoesNotThrow(); + + // Create a variable that binds the atexit to this shared object. + llvm::Constant *handle = + CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle"); + + llvm::Value *args[] = { + llvm::ConstantExpr::getBitCast(dtor, dtorTy), + llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy), + handle + }; + CGF.Builder.CreateCall(atexit, args); +} - // Get the destructor function type - llvm::Type *DtorFnTy = llvm::FunctionType::get(VoidTy, Int8PtrTy, false); - DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); +static llvm::Function * +CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, + llvm::FunctionType *ty, + const Twine &name); + +/// Create a stub function, suitable for being passed to atexit, +/// which passes the given address to the given destructor function. +static llvm::Constant *createAtExitStub(CodeGenModule &CGM, + llvm::Constant *dtor, + llvm::Constant *addr) { + // Get the destructor function type, void(*)(void). + llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false); + llvm::Function *fn = + CreateGlobalInitOrDestructFunction(CGM, ty, + Twine("__dtor_", addr->getName())); + + CodeGenFunction CGF(CGM); + + CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, fn, + CGM.getTypes().arrangeNullaryFunction(), + FunctionArgList(), SourceLocation()); + + llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr); + + // Make sure the call and the callee agree on calling convention. + if (llvm::Function *dtorFn = + dyn_cast<llvm::Function>(dtor->stripPointerCasts())) + call->setCallingConv(dtorFn->getCallingConv()); + + CGF.FinishFunction(); - llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy }; + return fn; +} - // Get the __cxa_atexit function type - // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); - llvm::FunctionType *AtExitFnTy = - llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); +/// Register a global destructor using atexit. +static void emitGlobalDtorWithAtExit(CodeGenFunction &CGF, + llvm::Constant *dtor, + llvm::Constant *addr) { + // Create a function which calls the destructor. + llvm::Constant *dtorStub = createAtExitStub(CGF.CGM, dtor, addr); - llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, - "__cxa_atexit"); - if (llvm::Function *Fn = dyn_cast<llvm::Function>(AtExitFn)) - Fn->setDoesNotThrow(); + // extern "C" int atexit(void (*f)(void)); + llvm::FunctionType *atexitTy = + llvm::FunctionType::get(CGF.IntTy, dtorStub->getType(), false); + + llvm::Constant *atexit = + CGF.CGM.CreateRuntimeFunction(atexitTy, "atexit"); + if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit)) + atexitFn->setDoesNotThrow(); + + CGF.Builder.CreateCall(atexit, dtorStub); +} + +void CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *dtor, + llvm::Constant *addr) { + // Use __cxa_atexit if available. + if (CGM.getCodeGenOpts().CXAAtExit) { + emitGlobalDtorWithCXAAtExit(*this, dtor, addr); + return; + } + + // In Apple kexts, we want to add a global destructor entry. + // FIXME: shouldn't this be guarded by some variable? + if (CGM.getContext().getLangOpts().AppleKext) { + // Generate a global destructor entry. + CGM.AddCXXDtorEntry(dtor, addr); + } - llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, - "__dso_handle"); - llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), - llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), - llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; - Builder.CreateCall(AtExitFn, Args); + // Otherwise, we just use atexit. + emitGlobalDtorWithAtExit(*this, dtor, addr); } void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, |