OLD | NEW |
(Empty) | |
| 1 //===- ExpandCtors.cpp - Convert ctors/dtors to concrete arrays -----------===// |
| 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 pass converts LLVM's special symbols llvm.global_ctors and |
| 11 // llvm.global_dtors to concrete arrays, __init_array_start/end and |
| 12 // __fini_array_start/end, that are usable by a C library. |
| 13 // |
| 14 // This pass sorts the contents of global_ctors/dtors according to the |
| 15 // priority values they contain and removes the priority values. |
| 16 // |
| 17 //===----------------------------------------------------------------------===// |
| 18 |
| 19 #include <vector> |
| 20 |
| 21 #include "llvm/Pass.h" |
| 22 #include "llvm/IR/Constants.h" |
| 23 #include "llvm/IR/DerivedTypes.h" |
| 24 #include "llvm/IR/Instructions.h" |
| 25 #include "llvm/IR/Module.h" |
| 26 #include "llvm/IR/TypeBuilder.h" |
| 27 #include "llvm/Support/raw_ostream.h" |
| 28 #include "llvm/Transforms/NaCl.h" |
| 29 |
| 30 using namespace llvm; |
| 31 |
| 32 namespace { |
| 33 struct ExpandCtors : public ModulePass { |
| 34 static char ID; // Pass identification, replacement for typeid |
| 35 ExpandCtors() : ModulePass(ID) { |
| 36 initializeExpandCtorsPass(*PassRegistry::getPassRegistry()); |
| 37 } |
| 38 |
| 39 virtual bool runOnModule(Module &M); |
| 40 }; |
| 41 } |
| 42 |
| 43 char ExpandCtors::ID = 0; |
| 44 INITIALIZE_PASS(ExpandCtors, "nacl-expand-ctors", |
| 45 "Hook up constructor and destructor arrays to libc", |
| 46 false, false) |
| 47 |
| 48 static void setGlobalVariableValue(Module &M, const char *Name, |
| 49 Constant *Value) { |
| 50 if (GlobalVariable *Var = M.getNamedGlobal(Name)) { |
| 51 if (Var->hasInitializer()) { |
| 52 report_fatal_error(std::string("Variable ") + Name + |
| 53 " already has an initializer"); |
| 54 } |
| 55 Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType())); |
| 56 Var->eraseFromParent(); |
| 57 } |
| 58 } |
| 59 |
| 60 struct FuncArrayEntry { |
| 61 uint64_t priority; |
| 62 Constant *func; |
| 63 }; |
| 64 |
| 65 static bool compareEntries(FuncArrayEntry Entry1, FuncArrayEntry Entry2) { |
| 66 return Entry1.priority < Entry2.priority; |
| 67 } |
| 68 |
| 69 static void readFuncList(GlobalVariable *Array, std::vector<Constant*> *Funcs) { |
| 70 if (!Array->hasInitializer()) |
| 71 return; |
| 72 Constant *Init = Array->getInitializer(); |
| 73 ArrayType *Ty = dyn_cast<ArrayType>(Init->getType()); |
| 74 if (!Ty) { |
| 75 errs() << "Initializer: " << *Array->getInitializer() << "\n"; |
| 76 report_fatal_error("ExpandCtors: Initializer is not of array type"); |
| 77 } |
| 78 if (Ty->getNumElements() == 0) |
| 79 return; |
| 80 ConstantArray *InitList = dyn_cast<ConstantArray>(Init); |
| 81 if (!InitList) { |
| 82 errs() << "Initializer: " << *Array->getInitializer() << "\n"; |
| 83 report_fatal_error("ExpandCtors: Unexpected initializer ConstantExpr"); |
| 84 } |
| 85 std::vector<FuncArrayEntry> FuncsToSort; |
| 86 for (unsigned Index = 0; Index < InitList->getNumOperands(); ++Index) { |
| 87 ConstantStruct *CS = cast<ConstantStruct>(InitList->getOperand(Index)); |
| 88 FuncArrayEntry Entry; |
| 89 Entry.priority = cast<ConstantInt>(CS->getOperand(0))->getZExtValue(); |
| 90 Entry.func = CS->getOperand(1); |
| 91 FuncsToSort.push_back(Entry); |
| 92 } |
| 93 |
| 94 std::sort(FuncsToSort.begin(), FuncsToSort.end(), compareEntries); |
| 95 for (std::vector<FuncArrayEntry>::iterator Iter = FuncsToSort.begin(); |
| 96 Iter != FuncsToSort.end(); |
| 97 ++Iter) { |
| 98 Funcs->push_back(Iter->func); |
| 99 } |
| 100 } |
| 101 |
| 102 static void defineFuncArray(Module &M, const char *LlvmArrayName, |
| 103 const char *StartSymbol, |
| 104 const char *EndSymbol) { |
| 105 std::vector<Constant*> Funcs; |
| 106 |
| 107 GlobalVariable *Array = M.getNamedGlobal(LlvmArrayName); |
| 108 if (Array) { |
| 109 readFuncList(Array, &Funcs); |
| 110 // No code should be referencing global_ctors/global_dtors, |
| 111 // because this symbol is internal to LLVM. |
| 112 Array->eraseFromParent(); |
| 113 } |
| 114 |
| 115 Type *FuncTy = FunctionType::get(Type::getVoidTy(M.getContext()), false); |
| 116 Type *FuncPtrTy = FuncTy->getPointerTo(); |
| 117 ArrayType *ArrayTy = ArrayType::get(FuncPtrTy, Funcs.size()); |
| 118 GlobalVariable *NewArray = |
| 119 new GlobalVariable(M, ArrayTy, /* isConstant= */ true, |
| 120 GlobalValue::InternalLinkage, |
| 121 ConstantArray::get(ArrayTy, Funcs)); |
| 122 setGlobalVariableValue(M, StartSymbol, NewArray); |
| 123 // We do this last so that LLVM gives NewArray the name |
| 124 // "__{init,fini}_array_start" without adding any suffixes to |
| 125 // disambiguate from the original GlobalVariable's name. This is |
| 126 // not essential -- it just makes the output easier to understand |
| 127 // when looking at symbols for debugging. |
| 128 NewArray->setName(StartSymbol); |
| 129 |
| 130 // We replace "__{init,fini}_array_end" with the address of the end |
| 131 // of NewArray. This removes the name "__{init,fini}_array_end" |
| 132 // from the output, which is not ideal for debugging. Ideally we |
| 133 // would convert "__{init,fini}_array_end" to being a GlobalAlias |
| 134 // that points to the end of the array. However, unfortunately LLVM |
| 135 // does not generate correct code when a GlobalAlias contains a |
| 136 // GetElementPtr ConstantExpr. |
| 137 Constant *NewArrayEnd = |
| 138 ConstantExpr::getGetElementPtr(NewArray, |
| 139 ConstantInt::get(M.getContext(), |
| 140 APInt(32, 1))); |
| 141 setGlobalVariableValue(M, EndSymbol, NewArrayEnd); |
| 142 } |
| 143 |
| 144 bool ExpandCtors::runOnModule(Module &M) { |
| 145 defineFuncArray(M, "llvm.global_ctors", |
| 146 "__init_array_start", "__init_array_end"); |
| 147 defineFuncArray(M, "llvm.global_dtors", |
| 148 "__fini_array_start", "__fini_array_end"); |
| 149 return true; |
| 150 } |
| 151 |
| 152 ModulePass *llvm::createExpandCtorsPass() { |
| 153 return new ExpandCtors(); |
| 154 } |
OLD | NEW |