1 //===- CtorUtils.cpp - Helpers for working with global_ctors ----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines functions that are used to process llvm.global_ctors. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Transforms/Utils/CtorUtils.h" 15 #include "llvm/IR/Constants.h" 16 #include "llvm/IR/Function.h" 17 #include "llvm/IR/GlobalVariable.h" 18 #include "llvm/IR/Instructions.h" 19 #include "llvm/IR/Module.h" 20 #include "llvm/Support/Debug.h" 21 22 #define DEBUG_TYPE "ctor_utils" 23 24 namespace llvm { 25 26 namespace { 27 /// Given a specified llvm.global_ctors list, install the 28 /// specified array. 29 void installGlobalCtors(GlobalVariable *GCL, 30 const std::vector<Function *> &Ctors) { 31 // If we made a change, reassemble the initializer list. 32 Constant *CSVals[2]; 33 CSVals[0] = ConstantInt::get(Type::getInt32Ty(GCL->getContext()), 65535); 34 CSVals[1] = nullptr; 35 36 StructType *StructTy = 37 cast<StructType>(GCL->getType()->getElementType()->getArrayElementType()); 38 39 // Create the new init list. 40 std::vector<Constant *> CAList; 41 for (unsigned i = 0, e = Ctors.size(); i != e; ++i) { 42 if (Ctors[i]) { 43 CSVals[1] = Ctors[i]; 44 } else { 45 Type *FTy = FunctionType::get(Type::getVoidTy(GCL->getContext()), false); 46 PointerType *PFTy = PointerType::getUnqual(FTy); 47 CSVals[1] = Constant::getNullValue(PFTy); 48 CSVals[0] = 49 ConstantInt::get(Type::getInt32Ty(GCL->getContext()), 0x7fffffff); 50 } 51 CAList.push_back(ConstantStruct::get(StructTy, CSVals)); 52 } 53 54 // Create the array initializer. 55 Constant *CA = 56 ConstantArray::get(ArrayType::get(StructTy, CAList.size()), CAList); 57 58 // If we didn't change the number of elements, don't create a new GV. 59 if (CA->getType() == GCL->getInitializer()->getType()) { 60 GCL->setInitializer(CA); 61 return; 62 } 63 64 // Create the new global and insert it next to the existing list. 65 GlobalVariable *NGV = 66 new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(), 67 CA, "", GCL->getThreadLocalMode()); 68 GCL->getParent()->getGlobalList().insert(GCL, NGV); 69 NGV->takeName(GCL); 70 71 // Nuke the old list, replacing any uses with the new one. 72 if (!GCL->use_empty()) { 73 Constant *V = NGV; 74 if (V->getType() != GCL->getType()) 75 V = ConstantExpr::getBitCast(V, GCL->getType()); 76 GCL->replaceAllUsesWith(V); 77 } 78 GCL->eraseFromParent(); 79 } 80 81 /// Given a llvm.global_ctors list that we can understand, 82 /// return a list of the functions and null terminator as a vector. 83 std::vector<Function*> parseGlobalCtors(GlobalVariable *GV) { 84 if (GV->getInitializer()->isNullValue()) 85 return std::vector<Function *>(); 86 ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); 87 std::vector<Function *> Result; 88 Result.reserve(CA->getNumOperands()); 89 for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { 90 ConstantStruct *CS = cast<ConstantStruct>(*i); 91 Result.push_back(dyn_cast<Function>(CS->getOperand(1))); 92 } 93 return Result; 94 } 95 96 /// Find the llvm.global_ctors list, verifying that all initializers have an 97 /// init priority of 65535. 98 GlobalVariable *findGlobalCtors(Module &M) { 99 GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); 100 if (!GV) 101 return nullptr; 102 103 // Verify that the initializer is simple enough for us to handle. We are 104 // only allowed to optimize the initializer if it is unique. 105 if (!GV->hasUniqueInitializer()) 106 return nullptr; 107 108 if (isa<ConstantAggregateZero>(GV->getInitializer())) 109 return GV; 110 ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); 111 112 for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { 113 if (isa<ConstantAggregateZero>(*i)) 114 continue; 115 ConstantStruct *CS = cast<ConstantStruct>(*i); 116 if (isa<ConstantPointerNull>(CS->getOperand(1))) 117 continue; 118 119 // Must have a function or null ptr. 120 if (!isa<Function>(CS->getOperand(1))) 121 return nullptr; 122 123 // Init priority must be standard. 124 ConstantInt *CI = cast<ConstantInt>(CS->getOperand(0)); 125 if (CI->getZExtValue() != 65535) 126 return nullptr; 127 } 128 129 return GV; 130 } 131 } // namespace 132 133 /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the 134 /// entries for which it returns true. Return true if anything changed. 135 bool optimizeGlobalCtorsList(Module &M, 136 function_ref<bool(Function *)> ShouldRemove) { 137 GlobalVariable *GlobalCtors = findGlobalCtors(M); 138 if (!GlobalCtors) 139 return false; 140 141 std::vector<Function *> Ctors = parseGlobalCtors(GlobalCtors); 142 if (Ctors.empty()) 143 return false; 144 145 bool MadeChange = false; 146 147 // Loop over global ctors, optimizing them when we can. 148 for (unsigned i = 0; i != Ctors.size(); ++i) { 149 Function *F = Ctors[i]; 150 // Found a null terminator in the middle of the list, prune off the rest of 151 // the list. 152 if (!F) { 153 if (i != Ctors.size() - 1) { 154 Ctors.resize(i + 1); 155 MadeChange = true; 156 } 157 break; 158 } 159 DEBUG(dbgs() << "Optimizing Global Constructor: " << *F << "\n"); 160 161 // We cannot simplify external ctor functions. 162 if (F->empty()) 163 continue; 164 165 // If we can evaluate the ctor at compile time, do. 166 if (ShouldRemove(F)) { 167 Ctors.erase(Ctors.begin() + i); 168 MadeChange = true; 169 --i; 170 continue; 171 } 172 } 173 174 if (!MadeChange) 175 return false; 176 177 installGlobalCtors(GlobalCtors, Ctors); 178 return true; 179 } 180 181 } // End llvm namespace 182