| Index: lib/Transforms/NaCl/ExpandCtors.cpp
|
| diff --git a/lib/Transforms/NaCl/ExpandCtors.cpp b/lib/Transforms/NaCl/ExpandCtors.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a8d8bbfd37da1028bdfd8b8871f79c42f9b4d530
|
| --- /dev/null
|
| +++ b/lib/Transforms/NaCl/ExpandCtors.cpp
|
| @@ -0,0 +1,154 @@
|
| +//===- ExpandCtors.cpp - Convert ctors/dtors to concrete arrays -----------===//
|
| +//
|
| +// The LLVM Compiler Infrastructure
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +//
|
| +// This pass converts LLVM's special symbols llvm.global_ctors and
|
| +// llvm.global_dtors to concrete arrays, __init_array_start/end and
|
| +// __fini_array_start/end, that are usable by a C library.
|
| +//
|
| +// This pass sorts the contents of global_ctors/dtors according to the
|
| +// priority values they contain and removes the priority values.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#include <vector>
|
| +
|
| +#include "llvm/Pass.h"
|
| +#include "llvm/IR/Constants.h"
|
| +#include "llvm/IR/DerivedTypes.h"
|
| +#include "llvm/IR/Instructions.h"
|
| +#include "llvm/IR/Module.h"
|
| +#include "llvm/IR/TypeBuilder.h"
|
| +#include "llvm/Support/raw_ostream.h"
|
| +#include "llvm/Transforms/NaCl.h"
|
| +
|
| +using namespace llvm;
|
| +
|
| +namespace {
|
| + struct ExpandCtors : public ModulePass {
|
| + static char ID; // Pass identification, replacement for typeid
|
| + ExpandCtors() : ModulePass(ID) {
|
| + initializeExpandCtorsPass(*PassRegistry::getPassRegistry());
|
| + }
|
| +
|
| + virtual bool runOnModule(Module &M);
|
| + };
|
| +}
|
| +
|
| +char ExpandCtors::ID = 0;
|
| +INITIALIZE_PASS(ExpandCtors, "nacl-expand-ctors",
|
| + "Hook up constructor and destructor arrays to libc",
|
| + false, false)
|
| +
|
| +static void setGlobalVariableValue(Module &M, const char *Name,
|
| + Constant *Value) {
|
| + if (GlobalVariable *Var = M.getNamedGlobal(Name)) {
|
| + if (Var->hasInitializer()) {
|
| + report_fatal_error(std::string("Variable ") + Name +
|
| + " already has an initializer");
|
| + }
|
| + Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType()));
|
| + Var->eraseFromParent();
|
| + }
|
| +}
|
| +
|
| +struct FuncArrayEntry {
|
| + uint64_t priority;
|
| + Constant *func;
|
| +};
|
| +
|
| +static bool compareEntries(FuncArrayEntry Entry1, FuncArrayEntry Entry2) {
|
| + return Entry1.priority < Entry2.priority;
|
| +}
|
| +
|
| +static void readFuncList(GlobalVariable *Array, std::vector<Constant*> *Funcs) {
|
| + if (!Array->hasInitializer())
|
| + return;
|
| + Constant *Init = Array->getInitializer();
|
| + ArrayType *Ty = dyn_cast<ArrayType>(Init->getType());
|
| + if (!Ty) {
|
| + errs() << "Initializer: " << *Array->getInitializer() << "\n";
|
| + report_fatal_error("ExpandCtors: Initializer is not of array type");
|
| + }
|
| + if (Ty->getNumElements() == 0)
|
| + return;
|
| + ConstantArray *InitList = dyn_cast<ConstantArray>(Init);
|
| + if (!InitList) {
|
| + errs() << "Initializer: " << *Array->getInitializer() << "\n";
|
| + report_fatal_error("ExpandCtors: Unexpected initializer ConstantExpr");
|
| + }
|
| + std::vector<FuncArrayEntry> FuncsToSort;
|
| + for (unsigned Index = 0; Index < InitList->getNumOperands(); ++Index) {
|
| + ConstantStruct *CS = cast<ConstantStruct>(InitList->getOperand(Index));
|
| + FuncArrayEntry Entry;
|
| + Entry.priority = cast<ConstantInt>(CS->getOperand(0))->getZExtValue();
|
| + Entry.func = CS->getOperand(1);
|
| + FuncsToSort.push_back(Entry);
|
| + }
|
| +
|
| + std::sort(FuncsToSort.begin(), FuncsToSort.end(), compareEntries);
|
| + for (std::vector<FuncArrayEntry>::iterator Iter = FuncsToSort.begin();
|
| + Iter != FuncsToSort.end();
|
| + ++Iter) {
|
| + Funcs->push_back(Iter->func);
|
| + }
|
| +}
|
| +
|
| +static void defineFuncArray(Module &M, const char *LlvmArrayName,
|
| + const char *StartSymbol,
|
| + const char *EndSymbol) {
|
| + std::vector<Constant*> Funcs;
|
| +
|
| + GlobalVariable *Array = M.getNamedGlobal(LlvmArrayName);
|
| + if (Array) {
|
| + readFuncList(Array, &Funcs);
|
| + // No code should be referencing global_ctors/global_dtors,
|
| + // because this symbol is internal to LLVM.
|
| + Array->eraseFromParent();
|
| + }
|
| +
|
| + Type *FuncTy = FunctionType::get(Type::getVoidTy(M.getContext()), false);
|
| + Type *FuncPtrTy = FuncTy->getPointerTo();
|
| + ArrayType *ArrayTy = ArrayType::get(FuncPtrTy, Funcs.size());
|
| + GlobalVariable *NewArray =
|
| + new GlobalVariable(M, ArrayTy, /* isConstant= */ true,
|
| + GlobalValue::InternalLinkage,
|
| + ConstantArray::get(ArrayTy, Funcs));
|
| + setGlobalVariableValue(M, StartSymbol, NewArray);
|
| + // We do this last so that LLVM gives NewArray the name
|
| + // "__{init,fini}_array_start" without adding any suffixes to
|
| + // disambiguate from the original GlobalVariable's name. This is
|
| + // not essential -- it just makes the output easier to understand
|
| + // when looking at symbols for debugging.
|
| + NewArray->setName(StartSymbol);
|
| +
|
| + // We replace "__{init,fini}_array_end" with the address of the end
|
| + // of NewArray. This removes the name "__{init,fini}_array_end"
|
| + // from the output, which is not ideal for debugging. Ideally we
|
| + // would convert "__{init,fini}_array_end" to being a GlobalAlias
|
| + // that points to the end of the array. However, unfortunately LLVM
|
| + // does not generate correct code when a GlobalAlias contains a
|
| + // GetElementPtr ConstantExpr.
|
| + Constant *NewArrayEnd =
|
| + ConstantExpr::getGetElementPtr(NewArray,
|
| + ConstantInt::get(M.getContext(),
|
| + APInt(32, 1)));
|
| + setGlobalVariableValue(M, EndSymbol, NewArrayEnd);
|
| +}
|
| +
|
| +bool ExpandCtors::runOnModule(Module &M) {
|
| + defineFuncArray(M, "llvm.global_ctors",
|
| + "__init_array_start", "__init_array_end");
|
| + defineFuncArray(M, "llvm.global_dtors",
|
| + "__fini_array_start", "__fini_array_end");
|
| + return true;
|
| +}
|
| +
|
| +ModulePass *llvm::createExpandCtorsPass() {
|
| + return new ExpandCtors();
|
| +}
|
|
|