LowerGlobalDtors.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //===-- LowerGlobalDtors.cpp - Lower @llvm.global_dtors -------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file
  10. /// Lower @llvm.global_dtors.
  11. ///
  12. /// Implement @llvm.global_dtors by creating wrapper functions that are
  13. /// registered in @llvm.global_ctors and which contain a call to
  14. /// `__cxa_atexit` to register their destructor functions.
  15. ///
  16. //===----------------------------------------------------------------------===//
  17. #include "llvm/Transforms/Utils/LowerGlobalDtors.h"
  18. #include "llvm/IR/Constants.h"
  19. #include "llvm/IR/Instructions.h"
  20. #include "llvm/IR/Intrinsics.h"
  21. #include "llvm/InitializePasses.h"
  22. #include "llvm/Pass.h"
  23. #include "llvm/Transforms/Utils.h"
  24. #include "llvm/Transforms/Utils/ModuleUtils.h"
  25. #include <map>
  26. using namespace llvm;
  27. #define DEBUG_TYPE "lower-global-dtors"
  28. namespace {
  29. class LowerGlobalDtorsLegacyPass final : public ModulePass {
  30. StringRef getPassName() const override {
  31. return "Lower @llvm.global_dtors via `__cxa_atexit`";
  32. }
  33. void getAnalysisUsage(AnalysisUsage &AU) const override {
  34. AU.setPreservesCFG();
  35. ModulePass::getAnalysisUsage(AU);
  36. }
  37. bool runOnModule(Module &M) override;
  38. public:
  39. static char ID;
  40. LowerGlobalDtorsLegacyPass() : ModulePass(ID) {
  41. initializeLowerGlobalDtorsLegacyPassPass(*PassRegistry::getPassRegistry());
  42. }
  43. };
  44. } // End anonymous namespace
  45. char LowerGlobalDtorsLegacyPass::ID = 0;
  46. INITIALIZE_PASS(LowerGlobalDtorsLegacyPass, DEBUG_TYPE,
  47. "Lower @llvm.global_dtors via `__cxa_atexit`", false, false)
  48. ModulePass *llvm::createLowerGlobalDtorsLegacyPass() {
  49. return new LowerGlobalDtorsLegacyPass();
  50. }
  51. static bool runImpl(Module &M);
  52. bool LowerGlobalDtorsLegacyPass::runOnModule(Module &M) { return runImpl(M); }
  53. PreservedAnalyses LowerGlobalDtorsPass::run(Module &M,
  54. ModuleAnalysisManager &AM) {
  55. bool Changed = runImpl(M);
  56. if (!Changed)
  57. return PreservedAnalyses::all();
  58. PreservedAnalyses PA;
  59. PA.preserveSet<CFGAnalyses>();
  60. return PA;
  61. }
  62. static bool runImpl(Module &M) {
  63. GlobalVariable *GV = M.getGlobalVariable("llvm.global_dtors");
  64. if (!GV || !GV->hasInitializer())
  65. return false;
  66. const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
  67. if (!InitList)
  68. return false;
  69. // Validate @llvm.global_dtor's type.
  70. auto *ETy = dyn_cast<StructType>(InitList->getType()->getElementType());
  71. if (!ETy || ETy->getNumElements() != 3 ||
  72. !ETy->getTypeAtIndex(0U)->isIntegerTy() ||
  73. !ETy->getTypeAtIndex(1U)->isPointerTy() ||
  74. !ETy->getTypeAtIndex(2U)->isPointerTy())
  75. return false; // Not (int, ptr, ptr).
  76. // Collect the contents of @llvm.global_dtors, ordered by priority. Within a
  77. // priority, sequences of destructors with the same associated object are
  78. // recorded so that we can register them as a group.
  79. std::map<
  80. uint16_t,
  81. std::vector<std::pair<Constant *, std::vector<Constant *>>>
  82. > DtorFuncs;
  83. for (Value *O : InitList->operands()) {
  84. auto *CS = dyn_cast<ConstantStruct>(O);
  85. if (!CS)
  86. continue; // Malformed.
  87. auto *Priority = dyn_cast<ConstantInt>(CS->getOperand(0));
  88. if (!Priority)
  89. continue; // Malformed.
  90. uint16_t PriorityValue = Priority->getLimitedValue(UINT16_MAX);
  91. Constant *DtorFunc = CS->getOperand(1);
  92. if (DtorFunc->isNullValue())
  93. break; // Found a null terminator, skip the rest.
  94. Constant *Associated = CS->getOperand(2);
  95. Associated = cast<Constant>(Associated->stripPointerCasts());
  96. auto &AtThisPriority = DtorFuncs[PriorityValue];
  97. if (AtThisPriority.empty() || AtThisPriority.back().first != Associated) {
  98. std::vector<Constant *> NewList;
  99. NewList.push_back(DtorFunc);
  100. AtThisPriority.push_back(std::make_pair(Associated, NewList));
  101. } else {
  102. AtThisPriority.back().second.push_back(DtorFunc);
  103. }
  104. }
  105. if (DtorFuncs.empty())
  106. return false;
  107. // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
  108. LLVMContext &C = M.getContext();
  109. PointerType *VoidStar = Type::getInt8PtrTy(C);
  110. Type *AtExitFuncArgs[] = {VoidStar};
  111. FunctionType *AtExitFuncTy =
  112. FunctionType::get(Type::getVoidTy(C), AtExitFuncArgs,
  113. /*isVarArg=*/false);
  114. FunctionCallee AtExit = M.getOrInsertFunction(
  115. "__cxa_atexit",
  116. FunctionType::get(Type::getInt32Ty(C),
  117. {PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar},
  118. /*isVarArg=*/false));
  119. // Declare __dso_local.
  120. Type *DsoHandleTy = Type::getInt8Ty(C);
  121. Constant *DsoHandle = M.getOrInsertGlobal("__dso_handle", DsoHandleTy, [&] {
  122. auto *GV = new GlobalVariable(M, DsoHandleTy, /*isConstant=*/true,
  123. GlobalVariable::ExternalWeakLinkage, nullptr,
  124. "__dso_handle");
  125. GV->setVisibility(GlobalVariable::HiddenVisibility);
  126. return GV;
  127. });
  128. // For each unique priority level and associated symbol, generate a function
  129. // to call all the destructors at that level, and a function to register the
  130. // first function with __cxa_atexit.
  131. for (auto &PriorityAndMore : DtorFuncs) {
  132. uint16_t Priority = PriorityAndMore.first;
  133. uint64_t Id = 0;
  134. auto &AtThisPriority = PriorityAndMore.second;
  135. for (auto &AssociatedAndMore : AtThisPriority) {
  136. Constant *Associated = AssociatedAndMore.first;
  137. auto ThisId = Id++;
  138. Function *CallDtors = Function::Create(
  139. AtExitFuncTy, Function::PrivateLinkage,
  140. "call_dtors" +
  141. (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
  142. : Twine()) +
  143. (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
  144. : Twine()) +
  145. (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
  146. : Twine()),
  147. &M);
  148. BasicBlock *BB = BasicBlock::Create(C, "body", CallDtors);
  149. FunctionType *VoidVoid = FunctionType::get(Type::getVoidTy(C),
  150. /*isVarArg=*/false);
  151. for (auto *Dtor : reverse(AssociatedAndMore.second))
  152. CallInst::Create(VoidVoid, Dtor, "", BB);
  153. ReturnInst::Create(C, BB);
  154. Function *RegisterCallDtors = Function::Create(
  155. VoidVoid, Function::PrivateLinkage,
  156. "register_call_dtors" +
  157. (Priority != UINT16_MAX ? (Twine(".") + Twine(Priority))
  158. : Twine()) +
  159. (AtThisPriority.size() > 1 ? Twine("$") + Twine(ThisId)
  160. : Twine()) +
  161. (!Associated->isNullValue() ? (Twine(".") + Associated->getName())
  162. : Twine()),
  163. &M);
  164. BasicBlock *EntryBB = BasicBlock::Create(C, "entry", RegisterCallDtors);
  165. BasicBlock *FailBB = BasicBlock::Create(C, "fail", RegisterCallDtors);
  166. BasicBlock *RetBB = BasicBlock::Create(C, "return", RegisterCallDtors);
  167. Value *Null = ConstantPointerNull::get(VoidStar);
  168. Value *Args[] = {CallDtors, Null, DsoHandle};
  169. Value *Res = CallInst::Create(AtExit, Args, "call", EntryBB);
  170. Value *Cmp = new ICmpInst(*EntryBB, ICmpInst::ICMP_NE, Res,
  171. Constant::getNullValue(Res->getType()));
  172. BranchInst::Create(FailBB, RetBB, Cmp, EntryBB);
  173. // If `__cxa_atexit` hits out-of-memory, trap, so that we don't misbehave.
  174. // This should be very rare, because if the process is running out of
  175. // memory before main has even started, something is wrong.
  176. CallInst::Create(Intrinsic::getDeclaration(&M, Intrinsic::trap), "",
  177. FailBB);
  178. new UnreachableInst(C, FailBB);
  179. ReturnInst::Create(C, RetBB);
  180. // Now register the registration function with @llvm.global_ctors.
  181. appendToGlobalCtors(M, RegisterCallDtors, Priority, Associated);
  182. }
  183. }
  184. // Now that we've lowered everything, remove @llvm.global_dtors.
  185. GV->eraseFromParent();
  186. return true;
  187. }