| //===- RegisterRuntimeInitializer.cpp ---------------------------*- C++ -*----// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Pass to register runtime initialization calls into user-space programs. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "safecode/RegisterRuntimeInitializer.h" |
| #include "safecode/Utility.h" |
| |
| using namespace llvm; |
| |
| namespace llvm { |
| |
| char RegisterRuntimeInitializer::ID = 0; |
| |
| static llvm::RegisterPass<RegisterRuntimeInitializer> |
| X1 ("reg-runtime-init", "Register runtime initializer into programs"); |
| |
| bool |
| RegisterRuntimeInitializer::runOnModule(llvm::Module & M) { |
| constructInitializer(M); |
| insertInitializerIntoGlobalCtorList(M); |
| setLogFileName (M); |
| return true; |
| } |
| |
| // |
| // Method: setLogFileName() |
| // |
| // Description: |
| // Insert a call into main() that tells the run-time the name of the log file |
| // into which to put SAFECode error messages. |
| // |
| // Note that we do *not* put them into a constructor. Some libc functions are |
| // initialized by constructors; functions like fprintf() won't work before |
| // before these constructors are called. Therefore, we put the call into |
| // main(); any SAFECode errors before main() will just go to stderr. |
| // |
| void |
| RegisterRuntimeInitializer::setLogFileName (llvm::Module & M) { |
| // |
| // Do nothing if the name is empty. |
| // |
| if (strcmp (logfilename, "") == 0) |
| return; |
| |
| // |
| // See if there is a main function. If not, just do nothing. |
| // |
| Function * Main = M.getFunction ("main"); |
| if (!Main) |
| return; |
| |
| // |
| // Find a place to insert the call within main(). |
| // |
| BasicBlock::iterator InsertPt = Main->getEntryBlock().begin(); |
| while (isa<AllocaInst>(InsertPt)) |
| ++InsertPt; |
| |
| // |
| // Create the function that sets the log filename. |
| // |
| Constant * SetLogC = M.getOrInsertFunction ("pool_init_logfile", |
| Type::getVoidTy (M.getContext()), |
| getVoidPtrType (M), |
| NULL); |
| Function * SetLog = cast<Function>(SetLogC); |
| |
| // |
| // Create a global variable containing the log filename. |
| // |
| Constant * LogNameInit = ConstantDataArray::getString (M.getContext(), |
| logfilename); |
| Value * LogName = new GlobalVariable (M, |
| LogNameInit->getType(), |
| true, |
| GlobalValue::InternalLinkage, |
| LogNameInit, |
| "logname"); |
| |
| // |
| // Create a call to set the log filename. |
| // |
| Value * Param = castTo (LogName, getVoidPtrType (M), "logname", InsertPt); |
| CallInst::Create (SetLog, Param, "", InsertPt); |
| return; |
| } |
| |
| void |
| RegisterRuntimeInitializer::constructInitializer(llvm::Module & M) { |
| // |
| // Create a new function with zero arguments. This will be the SAFECode |
| // run-time constructor; it will be called by static global variable |
| // constructor magic before main() is called. |
| // |
| Type * VoidTy = Type::getVoidTy (M.getContext()); |
| Type * Int32Ty = IntegerType::getInt32Ty(M.getContext()); |
| Function * RuntimeCtor = (Function *) M.getOrInsertFunction("pool_ctor", |
| VoidTy, |
| NULL); |
| |
| Function * RuntimeInit = (Function *) M.getOrInsertFunction("pool_init_runtime", VoidTy, Int32Ty, Int32Ty, Int32Ty, NULL); |
| Constant * CF = M.getOrInsertFunction ("sc.register_globals", VoidTy, NULL); |
| Function * RegGlobals = dyn_cast<Function>(CF); |
| |
| // |
| // Make the global registration function internal. |
| // |
| RegGlobals->setDoesNotThrow(); |
| RegGlobals->setLinkage(GlobalValue::InternalLinkage); |
| |
| // Make the runtime constructor compatible with other ctors |
| RuntimeCtor->setDoesNotThrow(); |
| RuntimeCtor->setLinkage(GlobalValue::InternalLinkage); |
| |
| // |
| // Empty out the default definition of the SAFECode constructor function. |
| // We'll replace it with our own code. |
| // |
| destroyFunction (RuntimeCtor); |
| |
| // |
| // Add a call in the new constructor function to the SAFECode initialization |
| // function. |
| // |
| BasicBlock * BB = BasicBlock::Create (M.getContext(), "entry", RuntimeCtor); |
| |
| // Delegate the responbilities of initializing pool descriptor to the |
| // SAFECode runtime initializer |
| // CallInst::Create (PoolInit, "", BB); |
| |
| Type * Int32Type = IntegerType::getInt32Ty(M.getContext()); |
| std::vector<Value *> args; |
| |
| // |
| // By default, explicit dangling pointer checks are disabled, |
| // rewrite pointers are enabled, and we should not terminate on |
| // errors. Some more refactoring will be needed to make all of this |
| // work properly. |
| // |
| args.push_back (ConstantInt::get(Int32Type, 0)); |
| args.push_back (ConstantInt::get(Int32Type, 1)); |
| args.push_back (ConstantInt::get(Int32Type, 0)); |
| CallInst::Create (RuntimeInit, args, "", BB); |
| |
| args.clear(); |
| CallInst::Create (RegGlobals, args, "", BB); |
| |
| |
| // |
| // Add a return instruction at the end of the basic block. |
| // |
| ReturnInst::Create (M.getContext(), BB); |
| } |
| |
| void |
| RegisterRuntimeInitializer::insertInitializerIntoGlobalCtorList(Module & M) { |
| Function * RuntimeCtor = M.getFunction ("pool_ctor"); |
| |
| // |
| // Insert the run-time ctor into the ctor list. |
| // |
| Type * Int32Type = IntegerType::getInt32Ty(M.getContext()); |
| std::vector<Constant *> CtorInits; |
| |
| // |
| // Make the priority 1 so we can allow the poolalloc constructor to go first. |
| // |
| CtorInits.push_back (ConstantInt::get (Int32Type, 1)); |
| CtorInits.push_back (RuntimeCtor); |
| StructType * ST = ConstantStruct::getTypeForElements (CtorInits, false); |
| Constant * RuntimeCtorInit = ConstantStruct::get (ST, CtorInits); |
| |
| // |
| // Get the current set of static global constructors and add the new ctor |
| // to the list. |
| // |
| std::vector<Constant *> CurrentCtors; |
| GlobalVariable * GVCtor = M.getNamedGlobal ("llvm.global_ctors"); |
| if (GVCtor) { |
| if (Constant * C = GVCtor->getInitializer()) { |
| for (unsigned index = 0; index < C->getNumOperands(); ++index) { |
| CurrentCtors.push_back (dyn_cast<Constant>(C->getOperand (index))); |
| } |
| } |
| } |
| |
| // |
| // The ctor list seems to be initialized in different orders on different |
| // platforms, and the priority settings don't seem to work. Examine the |
| // module's platform string and take a best guess to the order. |
| // |
| if (M.getTargetTriple().find ("linux") == std::string::npos) |
| CurrentCtors.insert (CurrentCtors.begin(), RuntimeCtorInit); |
| else |
| CurrentCtors.push_back (RuntimeCtorInit); |
| |
| assert (CurrentCtors.back()->getType() == RuntimeCtorInit->getType()); |
| |
| // |
| // Create a new initializer. |
| // |
| ArrayType * AT = ArrayType::get (RuntimeCtorInit-> getType(), |
| CurrentCtors.size()); |
| Constant * NewInit=ConstantArray::get (AT, CurrentCtors); |
| |
| // |
| // Create the new llvm.global_ctors global variable and remove the old one |
| // if it existed. |
| // |
| Value * newGVCtor = new GlobalVariable (M, |
| NewInit->getType(), |
| false, |
| GlobalValue::AppendingLinkage, |
| NewInit, |
| "llvm.global_ctors"); |
| if (GVCtor) { |
| newGVCtor->takeName (GVCtor); |
| GVCtor->eraseFromParent (); |
| } |
| |
| return; |
| } |
| |
| } |