blob: 3e69f03bb13a758c22a040bc25e8e7b6f762c6c3 [file] [log] [blame]
//===- 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;
}
}