aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ExecutionEngine
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-02-11 20:01:10 -0800
committerStephen Hines <srhines@google.com>2014-02-11 20:01:10 -0800
commitce9904c6ea8fd669978a8eefb854b330eb9828ff (patch)
tree2418ee2e96ea220977c8fb74959192036ab5b133 /lib/ExecutionEngine
parentc27b10b198c1d9e9b51f2303994313ec2778edd7 (diff)
parentdbb832b83351cec97b025b61c26536ef50c3181c (diff)
downloadexternal_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.zip
external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.gz
external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.bz2
Merge remote-tracking branch 'upstream/release_34' into merge-20140211
Conflicts: lib/Linker/LinkModules.cpp lib/Support/Unix/Signals.inc Change-Id: Ia54f291fa5dc828052d2412736e8495c1282aa64
Diffstat (limited to 'lib/ExecutionEngine')
-rw-r--r--lib/ExecutionEngine/ExecutionEngine.cpp44
-rw-r--r--lib/ExecutionEngine/ExecutionEngineBindings.cpp45
-rw-r--r--lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h2
-rw-r--r--lib/ExecutionEngine/Interpreter/Execution.cpp255
-rw-r--r--lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp31
-rw-r--r--lib/ExecutionEngine/Interpreter/Interpreter.h6
-rw-r--r--lib/ExecutionEngine/JIT/JIT.cpp156
-rw-r--r--lib/ExecutionEngine/JIT/JITMemoryManager.cpp7
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJIT.cpp288
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJIT.h235
-rw-r--r--lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp16
-rw-r--r--lib/ExecutionEngine/OProfileJIT/OProfileJITEventListener.cpp66
-rw-r--r--lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp17
-rw-r--r--lib/ExecutionEngine/RTDyldMemoryManager.cpp222
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h1
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h1
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp134
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp312
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h55
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h104
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp167
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h32
-rw-r--r--lib/ExecutionEngine/TargetSelect.cpp2
23 files changed, 1691 insertions, 507 deletions
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp
index c463e9f..2a610d5 100644
--- a/lib/ExecutionEngine/ExecutionEngine.cpp
+++ b/lib/ExecutionEngine/ExecutionEngine.cpp
@@ -15,6 +15,7 @@
#define DEBUG_TYPE "jit"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ExecutionEngine/GenericValue.h"
@@ -39,6 +40,11 @@ using namespace llvm;
STATISTIC(NumInitBytes, "Number of bytes of global vars initialized");
STATISTIC(NumGlobals , "Number of global vars initialized");
+// Pin the vtable to this file.
+void ObjectCache::anchor() {}
+void ObjectBuffer::anchor() {}
+void ObjectBufferStream::anchor() {}
+
ExecutionEngine *(*ExecutionEngine::JITCtor)(
Module *M,
std::string *ErrorStr,
@@ -56,9 +62,7 @@ ExecutionEngine *(*ExecutionEngine::InterpCtor)(Module *M,
ExecutionEngine::ExecutionEngine(Module *M)
: EEState(*this),
- LazyFunctionCreator(0),
- ExceptionTableRegister(0),
- ExceptionTableDeregister(0) {
+ LazyFunctionCreator(0) {
CompilingLazily = false;
GVCompilationDisabled = false;
SymbolSearchingDisabled = false;
@@ -72,16 +76,6 @@ ExecutionEngine::~ExecutionEngine() {
delete Modules[i];
}
-void ExecutionEngine::DeregisterAllTables() {
- if (ExceptionTableDeregister) {
- DenseMap<const Function*, void*>::iterator it = AllExceptionTables.begin();
- DenseMap<const Function*, void*>::iterator ite = AllExceptionTables.end();
- for (; it != ite; ++it)
- ExceptionTableDeregister(it->second);
- AllExceptionTables.clear();
- }
-}
-
namespace {
/// \brief Helper class which uses a value handler to automatically deletes the
/// memory block when the GlobalVariable is destroyed.
@@ -556,6 +550,24 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
// with the correct bit width.
Result.IntVal = APInt(C->getType()->getPrimitiveSizeInBits(), 0);
break;
+ case Type::StructTyID: {
+ // if the whole struct is 'undef' just reserve memory for the value.
+ if(StructType *STy = dyn_cast<StructType>(C->getType())) {
+ unsigned int elemNum = STy->getNumElements();
+ Result.AggregateVal.resize(elemNum);
+ for (unsigned int i = 0; i < elemNum; ++i) {
+ Type *ElemTy = STy->getElementType(i);
+ if (ElemTy->isIntegerTy())
+ Result.AggregateVal[i].IntVal =
+ APInt(ElemTy->getPrimitiveSizeInBits(), 0);
+ else if (ElemTy->isAggregateType()) {
+ const Constant *ElemUndef = UndefValue::get(ElemTy);
+ Result.AggregateVal[i] = getConstantValue(ElemUndef);
+ }
+ }
+ }
+ }
+ break;
case Type::VectorTyID:
// if the whole vector is 'undef' just reserve memory for the value.
const VectorType* VTy = dyn_cast<VectorType>(C->getType());
@@ -564,7 +576,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
Result.AggregateVal.resize(elemNum);
if (ElemTy->isIntegerTy())
for (unsigned int i = 0; i < elemNum; ++i)
- Result.AggregateVal[i].IntVal =
+ Result.AggregateVal[i].IntVal =
APInt(ElemTy->getPrimitiveSizeInBits(), 0);
break;
}
@@ -1283,6 +1295,10 @@ void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) {
if (GA == 0) {
// If it's not already specified, allocate memory for the global.
GA = getMemoryForGV(GV);
+
+ // If we failed to allocate memory for this global, return.
+ if (GA == 0) return;
+
addGlobalMapping(GV, GA);
}
diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
index 88e73bf..2d34eea 100644
--- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp
+++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp
@@ -339,14 +339,10 @@ void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) {
namespace {
struct SimpleBindingMMFunctions {
- uint8_t *(*AllocateCodeSection)(void *Opaque,
- uintptr_t Size, unsigned Alignment,
- unsigned SectionID);
- uint8_t *(*AllocateDataSection)(void *Opaque,
- uintptr_t Size, unsigned Alignment,
- unsigned SectionID, LLVMBool IsReadOnly);
- LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg);
- void (*Destroy)(void *Opaque);
+ LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection;
+ LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection;
+ LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory;
+ LLVMMemoryManagerDestroyCallback Destroy;
};
class SimpleBindingMemoryManager : public RTDyldMemoryManager {
@@ -355,12 +351,13 @@ public:
void *Opaque);
virtual ~SimpleBindingMemoryManager();
- virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID);
+ virtual uint8_t *allocateCodeSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName);
- virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID,
- bool isReadOnly);
+ virtual uint8_t *allocateDataSection(
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName, bool isReadOnly);
virtual bool finalizeMemory(std::string *ErrMsg);
@@ -388,13 +385,17 @@ SimpleBindingMemoryManager::~SimpleBindingMemoryManager() {
}
uint8_t *SimpleBindingMemoryManager::allocateCodeSection(
- uintptr_t Size, unsigned Alignment, unsigned SectionID) {
- return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID);
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName) {
+ return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID,
+ SectionName.str().c_str());
}
uint8_t *SimpleBindingMemoryManager::allocateDataSection(
- uintptr_t Size, unsigned Alignment, unsigned SectionID, bool isReadOnly) {
+ uintptr_t Size, unsigned Alignment, unsigned SectionID,
+ StringRef SectionName, bool isReadOnly) {
return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID,
+ SectionName.str().c_str(),
isReadOnly);
}
@@ -415,14 +416,10 @@ bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) {
LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager(
void *Opaque,
- uint8_t *(*AllocateCodeSection)(void *Opaque,
- uintptr_t Size, unsigned Alignment,
- unsigned SectionID),
- uint8_t *(*AllocateDataSection)(void *Opaque,
- uintptr_t Size, unsigned Alignment,
- unsigned SectionID, LLVMBool IsReadOnly),
- LLVMBool (*FinalizeMemory)(void *Opaque, char **ErrMsg),
- void (*Destroy)(void *Opaque)) {
+ LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection,
+ LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection,
+ LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory,
+ LLVMMemoryManagerDestroyCallback Destroy) {
if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory ||
!Destroy)
diff --git a/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h b/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h
index 3d9ff53..777d0f1 100644
--- a/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h
+++ b/lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h
@@ -61,7 +61,7 @@ public:
GetNewMethodIDFunc(GetNewMethodIDImpl) {
}
- // Sends an event anncouncing that a function has been emitted
+ // Sends an event announcing that a function has been emitted
// return values are event-specific. See Intel documentation for details.
int iJIT_NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
if (!NotifyEventFunc)
diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp
index fc3d579..5de0659 100644
--- a/lib/ExecutionEngine/Interpreter/Execution.cpp
+++ b/lib/ExecutionEngine/Interpreter/Execution.cpp
@@ -786,20 +786,31 @@ void Interpreter::visitBinaryOperator(BinaryOperator &I) {
}
static GenericValue executeSelectInst(GenericValue Src1, GenericValue Src2,
- GenericValue Src3) {
- return Src1.IntVal == 0 ? Src3 : Src2;
+ GenericValue Src3, const Type *Ty) {
+ GenericValue Dest;
+ if(Ty->isVectorTy()) {
+ assert(Src1.AggregateVal.size() == Src2.AggregateVal.size());
+ assert(Src2.AggregateVal.size() == Src3.AggregateVal.size());
+ Dest.AggregateVal.resize( Src1.AggregateVal.size() );
+ for (size_t i = 0; i < Src1.AggregateVal.size(); ++i)
+ Dest.AggregateVal[i] = (Src1.AggregateVal[i].IntVal == 0) ?
+ Src3.AggregateVal[i] : Src2.AggregateVal[i];
+ } else {
+ Dest = (Src1.IntVal == 0) ? Src3 : Src2;
+ }
+ return Dest;
}
void Interpreter::visitSelectInst(SelectInst &I) {
ExecutionContext &SF = ECStack.back();
+ const Type * Ty = I.getOperand(0)->getType();
GenericValue Src1 = getOperandValue(I.getOperand(0), SF);
GenericValue Src2 = getOperandValue(I.getOperand(1), SF);
GenericValue Src3 = getOperandValue(I.getOperand(2), SF);
- GenericValue R = executeSelectInst(Src1, Src2, Src3);
+ GenericValue R = executeSelectInst(Src1, Src2, Src3, Ty);
SetValue(&I, R, SF);
}
-
//===----------------------------------------------------------------------===//
// Terminator Instruction Implementations
//===----------------------------------------------------------------------===//
@@ -887,40 +898,11 @@ void Interpreter::visitSwitchInst(SwitchInst &I) {
// Check to see if any of the cases match...
BasicBlock *Dest = 0;
for (SwitchInst::CaseIt i = I.case_begin(), e = I.case_end(); i != e; ++i) {
- IntegersSubset& Case = i.getCaseValueEx();
- if (Case.isSingleNumber()) {
- // FIXME: Currently work with ConstantInt based numbers.
- const ConstantInt *CI = Case.getSingleNumber(0).toConstantInt();
- GenericValue Val = getOperandValue(const_cast<ConstantInt*>(CI), SF);
- if (executeICMP_EQ(Val, CondVal, ElTy).IntVal != 0) {
- Dest = cast<BasicBlock>(i.getCaseSuccessor());
- break;
- }
+ GenericValue CaseVal = getOperandValue(i.getCaseValue(), SF);
+ if (executeICMP_EQ(CondVal, CaseVal, ElTy).IntVal != 0) {
+ Dest = cast<BasicBlock>(i.getCaseSuccessor());
+ break;
}
- if (Case.isSingleNumbersOnly()) {
- for (unsigned n = 0, en = Case.getNumItems(); n != en; ++n) {
- // FIXME: Currently work with ConstantInt based numbers.
- const ConstantInt *CI = Case.getSingleNumber(n).toConstantInt();
- GenericValue Val = getOperandValue(const_cast<ConstantInt*>(CI), SF);
- if (executeICMP_EQ(Val, CondVal, ElTy).IntVal != 0) {
- Dest = cast<BasicBlock>(i.getCaseSuccessor());
- break;
- }
- }
- } else
- for (unsigned n = 0, en = Case.getNumItems(); n != en; ++n) {
- IntegersSubset::Range r = Case.getItem(n);
- // FIXME: Currently work with ConstantInt based numbers.
- const ConstantInt *LowCI = r.getLow().toConstantInt();
- const ConstantInt *HighCI = r.getHigh().toConstantInt();
- GenericValue Low = getOperandValue(const_cast<ConstantInt*>(LowCI), SF);
- GenericValue High = getOperandValue(const_cast<ConstantInt*>(HighCI), SF);
- if (executeICMP_ULE(Low, CondVal, ElTy).IntVal != 0 &&
- executeICMP_ULE(CondVal, High, ElTy).IntVal != 0) {
- Dest = cast<BasicBlock>(i.getCaseSuccessor());
- break;
- }
- }
}
if (!Dest) Dest = I.getDefaultDest(); // No cases matched: use default
SwitchToNewBasicBlock(Dest, SF);
@@ -1793,10 +1775,204 @@ void Interpreter::visitExtractElementInst(ExtractElementInst &I) {
SetValue(&I, Dest, SF);
}
+void Interpreter::visitInsertElementInst(InsertElementInst &I) {
+ ExecutionContext &SF = ECStack.back();
+ Type *Ty = I.getType();
+
+ if(!(Ty->isVectorTy()) )
+ llvm_unreachable("Unhandled dest type for insertelement instruction");
+
+ GenericValue Src1 = getOperandValue(I.getOperand(0), SF);
+ GenericValue Src2 = getOperandValue(I.getOperand(1), SF);
+ GenericValue Src3 = getOperandValue(I.getOperand(2), SF);
+ GenericValue Dest;
+
+ Type *TyContained = Ty->getContainedType(0);
+
+ const unsigned indx = unsigned(Src3.IntVal.getZExtValue());
+ Dest.AggregateVal = Src1.AggregateVal;
+
+ if(Src1.AggregateVal.size() <= indx)
+ llvm_unreachable("Invalid index in insertelement instruction");
+ switch (TyContained->getTypeID()) {
+ default:
+ llvm_unreachable("Unhandled dest type for insertelement instruction");
+ case Type::IntegerTyID:
+ Dest.AggregateVal[indx].IntVal = Src2.IntVal;
+ break;
+ case Type::FloatTyID:
+ Dest.AggregateVal[indx].FloatVal = Src2.FloatVal;
+ break;
+ case Type::DoubleTyID:
+ Dest.AggregateVal[indx].DoubleVal = Src2.DoubleVal;
+ break;
+ }
+ SetValue(&I, Dest, SF);
+}
+
+void Interpreter::visitShuffleVectorInst(ShuffleVectorInst &I){
+ ExecutionContext &SF = ECStack.back();
+
+ Type *Ty = I.getType();
+ if(!(Ty->isVectorTy()))
+ llvm_unreachable("Unhandled dest type for shufflevector instruction");
+
+ GenericValue Src1 = getOperandValue(I.getOperand(0), SF);
+ GenericValue Src2 = getOperandValue(I.getOperand(1), SF);
+ GenericValue Src3 = getOperandValue(I.getOperand(2), SF);
+ GenericValue Dest;
+
+ // There is no need to check types of src1 and src2, because the compiled
+ // bytecode can't contain different types for src1 and src2 for a
+ // shufflevector instruction.
+
+ Type *TyContained = Ty->getContainedType(0);
+ unsigned src1Size = (unsigned)Src1.AggregateVal.size();
+ unsigned src2Size = (unsigned)Src2.AggregateVal.size();
+ unsigned src3Size = (unsigned)Src3.AggregateVal.size();
+
+ Dest.AggregateVal.resize(src3Size);
+
+ switch (TyContained->getTypeID()) {
+ default:
+ llvm_unreachable("Unhandled dest type for insertelement instruction");
+ break;
+ case Type::IntegerTyID:
+ for( unsigned i=0; i<src3Size; i++) {
+ unsigned j = Src3.AggregateVal[i].IntVal.getZExtValue();
+ if(j < src1Size)
+ Dest.AggregateVal[i].IntVal = Src1.AggregateVal[j].IntVal;
+ else if(j < src1Size + src2Size)
+ Dest.AggregateVal[i].IntVal = Src2.AggregateVal[j-src1Size].IntVal;
+ else
+ // The selector may not be greater than sum of lengths of first and
+ // second operands and llasm should not allow situation like
+ // %tmp = shufflevector <2 x i32> <i32 3, i32 4>, <2 x i32> undef,
+ // <2 x i32> < i32 0, i32 5 >,
+ // where i32 5 is invalid, but let it be additional check here:
+ llvm_unreachable("Invalid mask in shufflevector instruction");
+ }
+ break;
+ case Type::FloatTyID:
+ for( unsigned i=0; i<src3Size; i++) {
+ unsigned j = Src3.AggregateVal[i].IntVal.getZExtValue();
+ if(j < src1Size)
+ Dest.AggregateVal[i].FloatVal = Src1.AggregateVal[j].FloatVal;
+ else if(j < src1Size + src2Size)
+ Dest.AggregateVal[i].FloatVal = Src2.AggregateVal[j-src1Size].FloatVal;
+ else
+ llvm_unreachable("Invalid mask in shufflevector instruction");
+ }
+ break;
+ case Type::DoubleTyID:
+ for( unsigned i=0; i<src3Size; i++) {
+ unsigned j = Src3.AggregateVal[i].IntVal.getZExtValue();
+ if(j < src1Size)
+ Dest.AggregateVal[i].DoubleVal = Src1.AggregateVal[j].DoubleVal;
+ else if(j < src1Size + src2Size)
+ Dest.AggregateVal[i].DoubleVal =
+ Src2.AggregateVal[j-src1Size].DoubleVal;
+ else
+ llvm_unreachable("Invalid mask in shufflevector instruction");
+ }
+ break;
+ }
+ SetValue(&I, Dest, SF);
+}
+
+void Interpreter::visitExtractValueInst(ExtractValueInst &I) {
+ ExecutionContext &SF = ECStack.back();
+ Value *Agg = I.getAggregateOperand();
+ GenericValue Dest;
+ GenericValue Src = getOperandValue(Agg, SF);
+
+ ExtractValueInst::idx_iterator IdxBegin = I.idx_begin();
+ unsigned Num = I.getNumIndices();
+ GenericValue *pSrc = &Src;
+
+ for (unsigned i = 0 ; i < Num; ++i) {
+ pSrc = &pSrc->AggregateVal[*IdxBegin];
+ ++IdxBegin;
+ }
+
+ Type *IndexedType = ExtractValueInst::getIndexedType(Agg->getType(), I.getIndices());
+ switch (IndexedType->getTypeID()) {
+ default:
+ llvm_unreachable("Unhandled dest type for extractelement instruction");
+ break;
+ case Type::IntegerTyID:
+ Dest.IntVal = pSrc->IntVal;
+ break;
+ case Type::FloatTyID:
+ Dest.FloatVal = pSrc->FloatVal;
+ break;
+ case Type::DoubleTyID:
+ Dest.DoubleVal = pSrc->DoubleVal;
+ break;
+ case Type::ArrayTyID:
+ case Type::StructTyID:
+ case Type::VectorTyID:
+ Dest.AggregateVal = pSrc->AggregateVal;
+ break;
+ case Type::PointerTyID:
+ Dest.PointerVal = pSrc->PointerVal;
+ break;
+ }
+
+ SetValue(&I, Dest, SF);
+}
+
+void Interpreter::visitInsertValueInst(InsertValueInst &I) {
+
+ ExecutionContext &SF = ECStack.back();
+ Value *Agg = I.getAggregateOperand();
+
+ GenericValue Src1 = getOperandValue(Agg, SF);
+ GenericValue Src2 = getOperandValue(I.getOperand(1), SF);
+ GenericValue Dest = Src1; // Dest is a slightly changed Src1
+
+ ExtractValueInst::idx_iterator IdxBegin = I.idx_begin();
+ unsigned Num = I.getNumIndices();
+
+ GenericValue *pDest = &Dest;
+ for (unsigned i = 0 ; i < Num; ++i) {
+ pDest = &pDest->AggregateVal[*IdxBegin];
+ ++IdxBegin;
+ }
+ // pDest points to the target value in the Dest now
+
+ Type *IndexedType = ExtractValueInst::getIndexedType(Agg->getType(), I.getIndices());
+
+ switch (IndexedType->getTypeID()) {
+ default:
+ llvm_unreachable("Unhandled dest type for insertelement instruction");
+ break;
+ case Type::IntegerTyID:
+ pDest->IntVal = Src2.IntVal;
+ break;
+ case Type::FloatTyID:
+ pDest->FloatVal = Src2.FloatVal;
+ break;
+ case Type::DoubleTyID:
+ pDest->DoubleVal = Src2.DoubleVal;
+ break;
+ case Type::ArrayTyID:
+ case Type::StructTyID:
+ case Type::VectorTyID:
+ pDest->AggregateVal = Src2.AggregateVal;
+ break;
+ case Type::PointerTyID:
+ pDest->PointerVal = Src2.PointerVal;
+ break;
+ }
+
+ SetValue(&I, Dest, SF);
+}
+
GenericValue Interpreter::getConstantExprValue (ConstantExpr *CE,
ExecutionContext &SF) {
switch (CE->getOpcode()) {
- case Instruction::Trunc:
+ case Instruction::Trunc:
return executeTruncInst(CE->getOperand(0), CE->getType(), SF);
case Instruction::ZExt:
return executeZExtInst(CE->getOperand(0), CE->getType(), SF);
@@ -1832,7 +2008,8 @@ GenericValue Interpreter::getConstantExprValue (ConstantExpr *CE,
case Instruction::Select:
return executeSelectInst(getOperandValue(CE->getOperand(0), SF),
getOperandValue(CE->getOperand(1), SF),
- getOperandValue(CE->getOperand(2), SF));
+ getOperandValue(CE->getOperand(2), SF),
+ CE->getOperand(0)->getType());
default :
break;
}
diff --git a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
index bef4bbf..a03c7f5 100644
--- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
+++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp
@@ -406,6 +406,7 @@ GenericValue lle_X_sprintf(FunctionType *FT,
break;
}
}
+ return GV;
}
// int printf(const char *, ...) - a very rough implementation to make output
@@ -434,7 +435,7 @@ GenericValue lle_X_sscanf(FunctionType *FT,
GenericValue GV;
GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],
- Args[5], Args[6], Args[7], Args[8], Args[9]));
+ Args[5], Args[6], Args[7], Args[8], Args[9]));
return GV;
}
@@ -450,7 +451,7 @@ GenericValue lle_X_scanf(FunctionType *FT,
GenericValue GV;
GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4],
- Args[5], Args[6], Args[7], Args[8], Args[9]));
+ Args[5], Args[6], Args[7], Args[8], Args[9]));
return GV;
}
@@ -470,6 +471,30 @@ GenericValue lle_X_fprintf(FunctionType *FT,
return GV;
}
+static GenericValue lle_X_memset(FunctionType *FT,
+ const std::vector<GenericValue> &Args) {
+ int val = (int)Args[1].IntVal.getSExtValue();
+ size_t len = (size_t)Args[2].IntVal.getZExtValue();
+ memset((void *)GVTOP(Args[0]), val, len);
+ // llvm.memset.* returns void, lle_X_* returns GenericValue,
+ // so here we return GenericValue with IntVal set to zero
+ GenericValue GV;
+ GV.IntVal = 0;
+ return GV;
+}
+
+static GenericValue lle_X_memcpy(FunctionType *FT,
+ const std::vector<GenericValue> &Args) {
+ memcpy(GVTOP(Args[0]), GVTOP(Args[1]),
+ (size_t)(Args[2].IntVal.getLimitedValue()));
+
+ // llvm.memcpy* returns void, lle_X_* returns GenericValue,
+ // so here we return GenericValue with IntVal set to zero
+ GenericValue GV;
+ GV.IntVal = 0;
+ return GV;
+}
+
void Interpreter::initializeExternalFunctions() {
sys::ScopedLock Writer(*FunctionsLock);
FuncNames["lle_X_atexit"] = lle_X_atexit;
@@ -481,4 +506,6 @@ void Interpreter::initializeExternalFunctions() {
FuncNames["lle_X_sscanf"] = lle_X_sscanf;
FuncNames["lle_X_scanf"] = lle_X_scanf;
FuncNames["lle_X_fprintf"] = lle_X_fprintf;
+ FuncNames["lle_X_memset"] = lle_X_memset;
+ FuncNames["lle_X_memcpy"] = lle_X_memcpy;
}
diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h
index 2952d7e..98269ef 100644
--- a/lib/ExecutionEngine/Interpreter/Interpreter.h
+++ b/lib/ExecutionEngine/Interpreter/Interpreter.h
@@ -179,6 +179,12 @@ public:
void visitVAArgInst(VAArgInst &I);
void visitExtractElementInst(ExtractElementInst &I);
+ void visitInsertElementInst(InsertElementInst &I);
+ void visitShuffleVectorInst(ShuffleVectorInst &I);
+
+ void visitExtractValueInst(ExtractValueInst &I);
+ void visitInsertValueInst(InsertValueInst &I);
+
void visitInstruction(Instruction &I) {
errs() << I << "\n";
llvm_unreachable("Instruction not interpretable yet!");
diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp
index 53ea0a2..246a675 100644
--- a/lib/ExecutionEngine/JIT/JIT.cpp
+++ b/lib/ExecutionEngine/JIT/JIT.cpp
@@ -67,140 +67,6 @@ static struct RegisterJIT {
extern "C" void LLVMLinkInJIT() {
}
-// Determine whether we can register EH tables.
-#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
- !defined(__USING_SJLJ_EXCEPTIONS__))
-#define HAVE_EHTABLE_SUPPORT 1
-#else
-#define HAVE_EHTABLE_SUPPORT 0
-#endif
-
-#if HAVE_EHTABLE_SUPPORT
-
-// libgcc defines the __register_frame function to dynamically register new
-// dwarf frames for exception handling. This functionality is not portable
-// across compilers and is only provided by GCC. We use the __register_frame
-// function here so that code generated by the JIT cooperates with the unwinding
-// runtime of libgcc. When JITting with exception handling enable, LLVM
-// generates dwarf frames and registers it to libgcc with __register_frame.
-//
-// The __register_frame function works with Linux.
-//
-// Unfortunately, this functionality seems to be in libgcc after the unwinding
-// library of libgcc for darwin was written. The code for darwin overwrites the
-// value updated by __register_frame with a value fetched with "keymgr".
-// "keymgr" is an obsolete functionality, which should be rewritten some day.
-// In the meantime, since "keymgr" is on all libgccs shipped with apple-gcc, we
-// need a workaround in LLVM which uses the "keymgr" to dynamically modify the
-// values of an opaque key, used by libgcc to find dwarf tables.
-
-extern "C" void __register_frame(void*);
-extern "C" void __deregister_frame(void*);
-
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
-# define USE_KEYMGR 1
-#else
-# define USE_KEYMGR 0
-#endif
-
-#if USE_KEYMGR
-
-namespace {
-
-// LibgccObject - This is the structure defined in libgcc. There is no #include
-// provided for this structure, so we also define it here. libgcc calls it
-// "struct object". The structure is undocumented in libgcc.
-struct LibgccObject {
- void *unused1;
- void *unused2;
- void *unused3;
-
- /// frame - Pointer to the exception table.
- void *frame;
-
- /// encoding - The encoding of the object?
- union {
- struct {
- unsigned long sorted : 1;
- unsigned long from_array : 1;
- unsigned long mixed_encoding : 1;
- unsigned long encoding : 8;
- unsigned long count : 21;
- } b;
- size_t i;
- } encoding;
-
- /// fde_end - libgcc defines this field only if some macro is defined. We
- /// include this field even if it may not there, to make libgcc happy.
- char *fde_end;
-
- /// next - At least we know it's a chained list!
- struct LibgccObject *next;
-};
-
-// "kemgr" stuff. Apparently, all frame tables are stored there.
-extern "C" void _keymgr_set_and_unlock_processwide_ptr(int, void *);
-extern "C" void *_keymgr_get_and_lock_processwide_ptr(int);
-#define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */
-
-/// LibgccObjectInfo - libgcc defines this struct as km_object_info. It
-/// probably contains all dwarf tables that are loaded.
-struct LibgccObjectInfo {
-
- /// seenObjects - LibgccObjects already parsed by the unwinding runtime.
- ///
- struct LibgccObject* seenObjects;
-
- /// unseenObjects - LibgccObjects not parsed yet by the unwinding runtime.
- ///
- struct LibgccObject* unseenObjects;
-
- unsigned unused[2];
-};
-
-/// darwin_register_frame - Since __register_frame does not work with darwin's
-/// libgcc,we provide our own function, which "tricks" libgcc by modifying the
-/// "Dwarf2 object list" key.
-void DarwinRegisterFrame(void* FrameBegin) {
- // Get the key.
- LibgccObjectInfo* LOI = (struct LibgccObjectInfo*)
- _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
- assert(LOI && "This should be preallocated by the runtime");
-
- // Allocate a new LibgccObject to represent this frame. Deallocation of this
- // object may be impossible: since darwin code in libgcc was written after
- // the ability to dynamically register frames, things may crash if we
- // deallocate it.
- struct LibgccObject* ob = (struct LibgccObject*)
- malloc(sizeof(struct LibgccObject));
-
- // Do like libgcc for the values of the field.
- ob->unused1 = (void *)-1;
- ob->unused2 = 0;
- ob->unused3 = 0;
- ob->frame = FrameBegin;
- ob->encoding.i = 0;
- ob->encoding.b.encoding = llvm::dwarf::DW_EH_PE_omit;
-
- // Put the info on both places, as libgcc uses the first or the second
- // field. Note that we rely on having two pointers here. If fde_end was a
- // char, things would get complicated.
- ob->fde_end = (char*)LOI->unseenObjects;
- ob->next = LOI->unseenObjects;
-
- // Update the key's unseenObjects list.
- LOI->unseenObjects = ob;
-
- // Finally update the "key". Apparently, libgcc requires it.
- _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,
- LOI);
-
-}
-
-}
-#endif // __APPLE__
-#endif // HAVE_EHTABLE_SUPPORT
-
/// createJIT - This is the factory method for creating a JIT for the current
/// machine, it does not fall back to the interpreter. This takes ownership
/// of the module.
@@ -293,33 +159,11 @@ JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji,
report_fatal_error("Target does not support machine code emission!");
}
- // Register routine for informing unwinding runtime about new EH frames
-#if HAVE_EHTABLE_SUPPORT
-#if USE_KEYMGR
- struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*)
- _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
-
- // The key is created on demand, and libgcc creates it the first time an
- // exception occurs. Since we need the key to register frames, we create
- // it now.
- if (!LOI)
- LOI = (LibgccObjectInfo*)calloc(sizeof(struct LibgccObjectInfo), 1);
- _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, LOI);
- InstallExceptionTableRegister(DarwinRegisterFrame);
- // Not sure about how to deregister on Darwin.
-#else
- InstallExceptionTableRegister(__register_frame);
- InstallExceptionTableDeregister(__deregister_frame);
-#endif // __APPLE__
-#endif // HAVE_EHTABLE_SUPPORT
-
// Initialize passes.
PM.doInitialization();
}
JIT::~JIT() {
- // Unregister all exception tables registered by this JIT.
- DeregisterAllTables();
// Cleanup.
AllJits->Remove(this);
delete jitstate;
diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
index 94db245..f58d31b 100644
--- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
+++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
@@ -464,7 +464,7 @@ namespace {
/// allocateCodeSection - Allocate memory for a code section.
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID) {
+ unsigned SectionID, StringRef SectionName) {
// Grow the required block size to account for the block header
Size += sizeof(*CurBlock);
@@ -510,7 +510,8 @@ namespace {
/// allocateDataSection - Allocate memory for a data section.
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID, bool IsReadOnly) {
+ unsigned SectionID, StringRef SectionName,
+ bool IsReadOnly) {
return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
}
@@ -793,7 +794,7 @@ static void runAtExitHandlers() {
// not inlined, and hiding their real definitions in a separate archive file
// that the dynamic linker can't see. For more info, search for
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
-#if defined(__linux__)
+#if defined(__linux__) && defined(__GLIBC__)
/* stat functions are redirecting to __xstat with a version number. On x86-64
* linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat'
* available as an exported symbol, so we have to add it explicitly.
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index 09dd924..195c458 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -14,10 +14,12 @@
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/PassManager.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ErrorHandling.h"
@@ -53,37 +55,63 @@ ExecutionEngine *MCJIT::createJIT(Module *M,
MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM,
bool AllocateGVsWithCode)
- : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM),
- IsLoaded(false), M(m), ObjCache(0) {
+ : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(this, MM), Dyld(&MemMgr),
+ ObjCache(0) {
+ OwnedModules.addModule(m);
setDataLayout(TM->getDataLayout());
}
MCJIT::~MCJIT() {
- if (LoadedObject)
- NotifyFreeingObject(*LoadedObject.get());
- delete MemMgr;
+ MutexGuard locked(lock);
+ // FIXME: We are managing our modules, so we do not want the base class
+ // ExecutionEngine to manage them as well. To avoid double destruction
+ // of the first (and only) module added in ExecutionEngine constructor
+ // we remove it from EE and will destruct it ourselves.
+ //
+ // It may make sense to move our module manager (based on SmallStPtr) back
+ // into EE if the JIT and Interpreter can live with it.
+ // If so, additional functions: addModule, removeModule, FindFunctionNamed,
+ // runStaticConstructorsDestructors could be moved back to EE as well.
+ //
+ Modules.clear();
+ Dyld.deregisterEHFrames();
+
+ LoadedObjectMap::iterator it, end = LoadedObjects.end();
+ for (it = LoadedObjects.begin(); it != end; ++it) {
+ ObjectImage *Obj = it->second;
+ if (Obj) {
+ NotifyFreeingObject(*Obj);
+ delete Obj;
+ }
+ }
+ LoadedObjects.clear();
delete TM;
}
+void MCJIT::addModule(Module *M) {
+ MutexGuard locked(lock);
+ OwnedModules.addModule(M);
+}
+
+bool MCJIT::removeModule(Module *M) {
+ MutexGuard locked(lock);
+ return OwnedModules.removeModule(M);
+}
+
+
+
void MCJIT::setObjectCache(ObjectCache* NewCache) {
+ MutexGuard locked(lock);
ObjCache = NewCache;
}
-ObjectBufferStream* MCJIT::emitObject(Module *m) {
- /// Currently, MCJIT only supports a single module and the module passed to
- /// this function call is expected to be the contained module. The module
- /// is passed as a parameter here to prepare for multiple module support in
- /// the future.
- assert(M == m);
-
- // Get a thread lock to make sure we aren't trying to compile multiple times
+ObjectBufferStream* MCJIT::emitObject(Module *M) {
MutexGuard locked(lock);
- // FIXME: Track compilation state on a per-module basis when multiple modules
- // are supported.
- // Re-compilation is not supported
- assert(!IsLoaded);
+ // This must be a module which has already been added but not loaded to this
+ // MCJIT instance, since these conditions are tested by our caller,
+ // generateCodeForModule.
PassManager PM;
@@ -99,7 +127,7 @@ ObjectBufferStream* MCJIT::emitObject(Module *m) {
}
// Initialize passes.
- PM.run(*m);
+ PM.run(*M);
// Flush the output buffer to get the generated code into memory
CompiledObject->flush();
@@ -109,21 +137,22 @@ ObjectBufferStream* MCJIT::emitObject(Module *m) {
// MemoryBuffer is a thin wrapper around the actual memory, so it's OK
// to create a temporary object here and delete it after the call.
OwningPtr<MemoryBuffer> MB(CompiledObject->getMemBuffer());
- ObjCache->notifyObjectCompiled(m, MB.get());
+ ObjCache->notifyObjectCompiled(M, MB.get());
}
return CompiledObject.take();
}
-void MCJIT::loadObject(Module *M) {
-
+void MCJIT::generateCodeForModule(Module *M) {
// Get a thread lock to make sure we aren't trying to load multiple times
MutexGuard locked(lock);
- // FIXME: Track compilation state on a per-module basis when multiple modules
- // are supported.
+ // This must be a module which has already been added to this MCJIT instance.
+ assert(OwnedModules.ownsModule(M) &&
+ "MCJIT::generateCodeForModule: Unknown module.");
+
// Re-compilation is not supported
- if (IsLoaded)
+ if (OwnedModules.hasModuleBeenLoaded(M))
return;
OwningPtr<ObjectBuffer> ObjectToLoad;
@@ -141,59 +170,137 @@ void MCJIT::loadObject(Module *M) {
}
// Load the object into the dynamic linker.
- // handing off ownership of the buffer
- LoadedObject.reset(Dyld.loadObject(ObjectToLoad.take()));
+ // MCJIT now owns the ObjectImage pointer (via its LoadedObjects map).
+ ObjectImage *LoadedObject = Dyld.loadObject(ObjectToLoad.take());
+ LoadedObjects[M] = LoadedObject;
if (!LoadedObject)
report_fatal_error(Dyld.getErrorString());
- // Resolve any relocations.
- Dyld.resolveRelocations();
-
// FIXME: Make this optional, maybe even move it to a JIT event listener
LoadedObject->registerWithDebugger();
NotifyObjectEmitted(*LoadedObject);
- // FIXME: Add support for per-module compilation state
- IsLoaded = true;
+ OwnedModules.markModuleAsLoaded(M);
}
-// FIXME: Add a parameter to identify which object is being finalized when
-// MCJIT supports multiple modules.
-// FIXME: Provide a way to separate code emission, relocations and page
-// protection in the interface.
+void MCJIT::finalizeLoadedModules() {
+ MutexGuard locked(lock);
+
+ // Resolve any outstanding relocations.
+ Dyld.resolveRelocations();
+
+ OwnedModules.markAllLoadedModulesAsFinalized();
+
+ // Register EH frame data for any module we own which has been loaded
+ Dyld.registerEHFrames();
+
+ // Set page permissions.
+ MemMgr.finalizeMemory();
+}
+
+// FIXME: Rename this.
void MCJIT::finalizeObject() {
- // If the module hasn't been compiled, just do that.
- if (!IsLoaded) {
- // If the call to Dyld.resolveRelocations() is removed from loadObject()
- // we'll need to do that here.
- loadObject(M);
- } else {
- // Resolve any relocations.
- Dyld.resolveRelocations();
+ MutexGuard locked(lock);
+
+ for (ModulePtrSet::iterator I = OwnedModules.begin_added(),
+ E = OwnedModules.end_added();
+ I != E; ++I) {
+ Module *M = *I;
+ generateCodeForModule(M);
}
- StringRef EHData = Dyld.getEHFrameSection();
- if (!EHData.empty())
- MemMgr->registerEHFrames(EHData);
+ finalizeLoadedModules();
+}
- // Set page permissions.
- MemMgr->finalizeMemory();
+void MCJIT::finalizeModule(Module *M) {
+ MutexGuard locked(lock);
+
+ // This must be a module which has already been added to this MCJIT instance.
+ assert(OwnedModules.ownsModule(M) && "MCJIT::finalizeModule: Unknown module.");
+
+ // If the module hasn't been compiled, just do that.
+ if (!OwnedModules.hasModuleBeenLoaded(M))
+ generateCodeForModule(M);
+
+ finalizeLoadedModules();
}
void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
report_fatal_error("not yet implemented");
}
-void *MCJIT::getPointerToFunction(Function *F) {
- // FIXME: This should really return a uint64_t since it's a pointer in the
- // target address space, not our local address space. That's part of the
- // ExecutionEngine interface, though. Fix that when the old JIT finally
- // dies.
+uint64_t MCJIT::getExistingSymbolAddress(const std::string &Name) {
+ // Check with the RuntimeDyld to see if we already have this symbol.
+ if (Name[0] == '\1')
+ return Dyld.getSymbolLoadAddress(Name.substr(1));
+ return Dyld.getSymbolLoadAddress((TM->getMCAsmInfo()->getGlobalPrefix()
+ + Name));
+}
+
+Module *MCJIT::findModuleForSymbol(const std::string &Name,
+ bool CheckFunctionsOnly) {
+ MutexGuard locked(lock);
+
+ // If it hasn't already been generated, see if it's in one of our modules.
+ for (ModulePtrSet::iterator I = OwnedModules.begin_added(),
+ E = OwnedModules.end_added();
+ I != E; ++I) {
+ Module *M = *I;
+ Function *F = M->getFunction(Name);
+ if (F && !F->isDeclaration())
+ return M;
+ if (!CheckFunctionsOnly) {
+ GlobalVariable *G = M->getGlobalVariable(Name);
+ if (G && !G->isDeclaration())
+ return M;
+ // FIXME: Do we need to worry about global aliases?
+ }
+ }
+ // We didn't find the symbol in any of our modules.
+ return NULL;
+}
+
+uint64_t MCJIT::getSymbolAddress(const std::string &Name,
+ bool CheckFunctionsOnly)
+{
+ MutexGuard locked(lock);
+
+ // First, check to see if we already have this symbol.
+ uint64_t Addr = getExistingSymbolAddress(Name);
+ if (Addr)
+ return Addr;
+
+ // If it hasn't already been generated, see if it's in one of our modules.
+ Module *M = findModuleForSymbol(Name, CheckFunctionsOnly);
+ if (!M)
+ return 0;
+
+ generateCodeForModule(M);
+
+ // Check the RuntimeDyld table again, it should be there now.
+ return getExistingSymbolAddress(Name);
+}
- // FIXME: Add support for per-module compilation state
- if (!IsLoaded)
- loadObject(M);
+uint64_t MCJIT::getGlobalValueAddress(const std::string &Name) {
+ MutexGuard locked(lock);
+ uint64_t Result = getSymbolAddress(Name, false);
+ if (Result != 0)
+ finalizeLoadedModules();
+ return Result;
+}
+
+uint64_t MCJIT::getFunctionAddress(const std::string &Name) {
+ MutexGuard locked(lock);
+ uint64_t Result = getSymbolAddress(Name, true);
+ if (Result != 0)
+ finalizeLoadedModules();
+ return Result;
+}
+
+// Deprecated. Use getFunctionAddress instead.
+void *MCJIT::getPointerToFunction(Function *F) {
+ MutexGuard locked(lock);
if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
bool AbortOnFailure = !F->hasExternalWeakLinkage();
@@ -202,6 +309,16 @@ void *MCJIT::getPointerToFunction(Function *F) {
return Addr;
}
+ Module *M = F->getParent();
+ bool HasBeenAddedButNotLoaded = OwnedModules.hasModuleBeenAddedButNotLoaded(M);
+
+ // Make sure the relevant module has been compiled and loaded.
+ if (HasBeenAddedButNotLoaded)
+ generateCodeForModule(M);
+ else if (!OwnedModules.hasModuleBeenLoaded(M))
+ // If this function doesn't belong to one of our modules, we're done.
+ return NULL;
+
// FIXME: Should the Dyld be retaining module information? Probably not.
// FIXME: Should we be using the mangler for this? Probably.
//
@@ -222,6 +339,45 @@ void MCJIT::freeMachineCodeForFunction(Function *F) {
report_fatal_error("not yet implemented");
}
+void MCJIT::runStaticConstructorsDestructorsInModulePtrSet(
+ bool isDtors, ModulePtrSet::iterator I, ModulePtrSet::iterator E) {
+ for (; I != E; ++I) {
+ ExecutionEngine::runStaticConstructorsDestructors(*I, isDtors);
+ }
+}
+
+void MCJIT::runStaticConstructorsDestructors(bool isDtors) {
+ // Execute global ctors/dtors for each module in the program.
+ runStaticConstructorsDestructorsInModulePtrSet(
+ isDtors, OwnedModules.begin_added(), OwnedModules.end_added());
+ runStaticConstructorsDestructorsInModulePtrSet(
+ isDtors, OwnedModules.begin_loaded(), OwnedModules.end_loaded());
+ runStaticConstructorsDestructorsInModulePtrSet(
+ isDtors, OwnedModules.begin_finalized(), OwnedModules.end_finalized());
+}
+
+Function *MCJIT::FindFunctionNamedInModulePtrSet(const char *FnName,
+ ModulePtrSet::iterator I,
+ ModulePtrSet::iterator E) {
+ for (; I != E; ++I) {
+ if (Function *F = (*I)->getFunction(FnName))
+ return F;
+ }
+ return 0;
+}
+
+Function *MCJIT::FindFunctionNamed(const char *FnName) {
+ Function *F = FindFunctionNamedInModulePtrSet(
+ FnName, OwnedModules.begin_added(), OwnedModules.end_added());
+ if (!F)
+ F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_loaded(),
+ OwnedModules.end_loaded());
+ if (!F)
+ F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_finalized(),
+ OwnedModules.end_finalized());
+ return F;
+}
+
GenericValue MCJIT::runFunction(Function *F,
const std::vector<GenericValue> &ArgValues) {
assert(F && "Function *F was null at entry to run()");
@@ -324,12 +480,8 @@ GenericValue MCJIT::runFunction(Function *F,
void *MCJIT::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure) {
- // FIXME: Add support for per-module compilation state
- if (!IsLoaded)
- loadObject(M);
-
- if (!isSymbolSearchingDisabled() && MemMgr) {
- void *ptr = MemMgr->getPointerToNamedFunction(Name, false);
+ if (!isSymbolSearchingDisabled()) {
+ void *ptr = MemMgr.getPointerToNamedFunction(Name, false);
if (ptr)
return ptr;
}
@@ -365,6 +517,7 @@ void MCJIT::UnregisterJITEventListener(JITEventListener *L) {
}
void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) {
MutexGuard locked(lock);
+ MemMgr.notifyObjectLoaded(this, &Obj);
for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
EventListeners[I]->NotifyObjectEmitted(Obj);
}
@@ -375,3 +528,14 @@ void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) {
EventListeners[I]->NotifyFreeingObject(Obj);
}
}
+
+uint64_t LinkingMemoryManager::getSymbolAddress(const std::string &Name) {
+ uint64_t Result = ParentEngine->getSymbolAddress(Name, false);
+ // If the symbols wasn't found and it begins with an underscore, try again
+ // without the underscore.
+ if (!Result && Name[0] == '_')
+ Result = ParentEngine->getSymbolAddress(Name.substr(1), false);
+ if (Result)
+ return Result;
+ return ClientMM->getSymbolAddress(Name);
+}
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h
index a899d4f..86b478b 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.h
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.h
@@ -10,48 +10,235 @@
#ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_H
#define LLVM_LIB_EXECUTIONENGINE_MCJIT_H
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
+#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/Module.h"
namespace llvm {
+class MCJIT;
-class ObjectImage;
+// This is a helper class that the MCJIT execution engine uses for linking
+// functions across modules that it owns. It aggregates the memory manager
+// that is passed in to the MCJIT constructor and defers most functionality
+// to that object.
+class LinkingMemoryManager : public RTDyldMemoryManager {
+public:
+ LinkingMemoryManager(MCJIT *Parent, RTDyldMemoryManager *MM)
+ : ParentEngine(Parent), ClientMM(MM) {}
+
+ virtual uint64_t getSymbolAddress(const std::string &Name);
+
+ // Functions deferred to client memory manager
+ virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, StringRef SectionName) {
+ return ClientMM->allocateCodeSection(Size, Alignment, SectionID, SectionName);
+ }
+
+ virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, StringRef SectionName,
+ bool IsReadOnly) {
+ return ClientMM->allocateDataSection(Size, Alignment,
+ SectionID, SectionName, IsReadOnly);
+ }
+
+ virtual void notifyObjectLoaded(ExecutionEngine *EE,
+ const ObjectImage *Obj) {
+ ClientMM->notifyObjectLoaded(EE, Obj);
+ }
+
+ virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
+ ClientMM->registerEHFrames(Addr, LoadAddr, Size);
+ }
+
+ virtual void deregisterEHFrames(uint8_t *Addr,
+ uint64_t LoadAddr,
+ size_t Size) {
+ ClientMM->deregisterEHFrames(Addr, LoadAddr, Size);
+ }
+
+ virtual bool finalizeMemory(std::string *ErrMsg = 0) {
+ return ClientMM->finalizeMemory(ErrMsg);
+ }
-// FIXME: This makes all kinds of horrible assumptions for the time being,
-// like only having one module, not needing to worry about multi-threading,
-// blah blah. Purely in get-it-up-and-limping mode for now.
+private:
+ MCJIT *ParentEngine;
+ OwningPtr<RTDyldMemoryManager> ClientMM;
+};
+
+// About Module states: added->loaded->finalized.
+//
+// The purpose of the "added" state is having modules in standby. (added=known
+// but not compiled). The idea is that you can add a module to provide function
+// definitions but if nothing in that module is referenced by a module in which
+// a function is executed (note the wording here because it's not exactly the
+// ideal case) then the module never gets compiled. This is sort of lazy
+// compilation.
+//
+// The purpose of the "loaded" state (loaded=compiled and required sections
+// copied into local memory but not yet ready for execution) is to have an
+// intermediate state wherein clients can remap the addresses of sections, using
+// MCJIT::mapSectionAddress, (in preparation for later copying to a new location
+// or an external process) before relocations and page permissions are applied.
+//
+// It might not be obvious at first glance, but the "remote-mcjit" case in the
+// lli tool does this. In that case, the intermediate action is taken by the
+// RemoteMemoryManager in response to the notifyObjectLoaded function being
+// called.
class MCJIT : public ExecutionEngine {
MCJIT(Module *M, TargetMachine *tm, RTDyldMemoryManager *MemMgr,
bool AllocateGVsWithCode);
+ typedef llvm::SmallPtrSet<Module *, 4> ModulePtrSet;
+
+ class OwningModuleContainer {
+ public:
+ OwningModuleContainer() {
+ }
+ ~OwningModuleContainer() {
+ freeModulePtrSet(AddedModules);
+ freeModulePtrSet(LoadedModules);
+ freeModulePtrSet(FinalizedModules);
+ }
+
+ ModulePtrSet::iterator begin_added() { return AddedModules.begin(); }
+ ModulePtrSet::iterator end_added() { return AddedModules.end(); }
+
+ ModulePtrSet::iterator begin_loaded() { return LoadedModules.begin(); }
+ ModulePtrSet::iterator end_loaded() { return LoadedModules.end(); }
+
+ ModulePtrSet::iterator begin_finalized() { return FinalizedModules.begin(); }
+ ModulePtrSet::iterator end_finalized() { return FinalizedModules.end(); }
+
+ void addModule(Module *M) {
+ AddedModules.insert(M);
+ }
+
+ bool removeModule(Module *M) {
+ return AddedModules.erase(M) || LoadedModules.erase(M) ||
+ FinalizedModules.erase(M);
+ }
+
+ bool hasModuleBeenAddedButNotLoaded(Module *M) {
+ return AddedModules.count(M) != 0;
+ }
+
+ bool hasModuleBeenLoaded(Module *M) {
+ // If the module is in either the "loaded" or "finalized" sections it
+ // has been loaded.
+ return (LoadedModules.count(M) != 0 ) || (FinalizedModules.count(M) != 0);
+ }
+
+ bool hasModuleBeenFinalized(Module *M) {
+ return FinalizedModules.count(M) != 0;
+ }
+
+ bool ownsModule(Module* M) {
+ return (AddedModules.count(M) != 0) || (LoadedModules.count(M) != 0) ||
+ (FinalizedModules.count(M) != 0);
+ }
+
+ void markModuleAsLoaded(Module *M) {
+ // This checks against logic errors in the MCJIT implementation.
+ // This function should never be called with either a Module that MCJIT
+ // does not own or a Module that has already been loaded and/or finalized.
+ assert(AddedModules.count(M) &&
+ "markModuleAsLoaded: Module not found in AddedModules");
+
+ // Remove the module from the "Added" set.
+ AddedModules.erase(M);
+
+ // Add the Module to the "Loaded" set.
+ LoadedModules.insert(M);
+ }
+
+ void markModuleAsFinalized(Module *M) {
+ // This checks against logic errors in the MCJIT implementation.
+ // This function should never be called with either a Module that MCJIT
+ // does not own, a Module that has not been loaded or a Module that has
+ // already been finalized.
+ assert(LoadedModules.count(M) &&
+ "markModuleAsFinalized: Module not found in LoadedModules");
+
+ // Remove the module from the "Loaded" section of the list.
+ LoadedModules.erase(M);
+
+ // Add the Module to the "Finalized" section of the list by inserting it
+ // before the 'end' iterator.
+ FinalizedModules.insert(M);
+ }
+
+ void markAllLoadedModulesAsFinalized() {
+ for (ModulePtrSet::iterator I = LoadedModules.begin(),
+ E = LoadedModules.end();
+ I != E; ++I) {
+ Module *M = *I;
+ FinalizedModules.insert(M);
+ }
+ LoadedModules.clear();
+ }
+
+ private:
+ ModulePtrSet AddedModules;
+ ModulePtrSet LoadedModules;
+ ModulePtrSet FinalizedModules;
+
+ void freeModulePtrSet(ModulePtrSet& MPS) {
+ // Go through the module set and delete everything.
+ for (ModulePtrSet::iterator I = MPS.begin(), E = MPS.end(); I != E; ++I) {
+ Module *M = *I;
+ delete M;
+ }
+ MPS.clear();
+ }
+ };
+
TargetMachine *TM;
MCContext *Ctx;
- RTDyldMemoryManager *MemMgr;
+ LinkingMemoryManager MemMgr;
RuntimeDyld Dyld;
SmallVector<JITEventListener*, 2> EventListeners;
- // FIXME: Add support for multiple modules
- bool IsLoaded;
- Module *M;
- OwningPtr<ObjectImage> LoadedObject;
+ OwningModuleContainer OwnedModules;
+
+ typedef DenseMap<Module *, ObjectImage *> LoadedObjectMap;
+ LoadedObjectMap LoadedObjects;
// An optional ObjectCache to be notified of compiled objects and used to
// perform lookup of pre-compiled code to avoid re-compilation.
ObjectCache *ObjCache;
+ Function *FindFunctionNamedInModulePtrSet(const char *FnName,
+ ModulePtrSet::iterator I,
+ ModulePtrSet::iterator E);
+
+ void runStaticConstructorsDestructorsInModulePtrSet(bool isDtors,
+ ModulePtrSet::iterator I,
+ ModulePtrSet::iterator E);
+
public:
~MCJIT();
/// @name ExecutionEngine interface implementation
/// @{
+ virtual void addModule(Module *M);
+ virtual bool removeModule(Module *M);
+
+ /// FindFunctionNamed - Search all of the active modules to find the one that
+ /// defines FnName. This is very slow operation and shouldn't be used for
+ /// general code.
+ virtual Function *FindFunctionNamed(const char *FnName);
/// Sets the object manager that MCJIT should use to avoid compilation.
virtual void setObjectCache(ObjectCache *manager);
+ virtual void generateCodeForModule(Module *M);
+
/// finalizeObject - ensure the module is fully processed and is usable.
///
/// It is the user-level function for completing the process of making the
@@ -59,7 +246,17 @@ public:
/// object have been relocated using mapSectionAddress. When this method is
/// called the MCJIT execution engine will reapply relocations for a loaded
/// object.
+ /// Is it OK to finalize a set of modules, add modules and finalize again.
+ // FIXME: Do we really need both of these?
virtual void finalizeObject();
+ virtual void finalizeModule(Module *);
+ void finalizeLoadedModules();
+
+ /// runStaticConstructorsDestructors - This method is used to execute all of
+ /// the static constructors or destructors for a program.
+ ///
+ /// \param isDtors - Run the destructors instead of constructors.
+ void runStaticConstructorsDestructors(bool isDtors);
virtual void *getPointerToBasicBlock(BasicBlock *BB);
@@ -91,10 +288,15 @@ public:
uint64_t TargetAddress) {
Dyld.mapSectionAddress(LocalAddress, TargetAddress);
}
-
virtual void RegisterJITEventListener(JITEventListener *L);
virtual void UnregisterJITEventListener(JITEventListener *L);
+ // If successful, these function will implicitly finalize all loaded objects.
+ // To get a function address within MCJIT without causing a finalize, use
+ // getSymbolAddress.
+ virtual uint64_t getGlobalValueAddress(const std::string &Name);
+ virtual uint64_t getFunctionAddress(const std::string &Name);
+
/// @}
/// @name (Private) Registration Interfaces
/// @{
@@ -111,6 +313,11 @@ public:
// @}
+ // This is not directly exposed via the ExecutionEngine API, but it is
+ // used by the LinkingMemoryManager.
+ uint64_t getSymbolAddress(const std::string &Name,
+ bool CheckFunctionsOnly);
+
protected:
/// emitObject -- Generate a JITed object in memory from the specified module
/// Currently, MCJIT only supports a single module and the module passed to
@@ -119,10 +326,12 @@ protected:
/// the future.
ObjectBufferStream* emitObject(Module *M);
- void loadObject(Module *M);
-
void NotifyObjectEmitted(const ObjectImage& Obj);
void NotifyFreeingObject(const ObjectImage& Obj);
+
+ uint64_t getExistingSymbolAddress(const std::string &Name);
+ Module *findModuleForSymbol(const std::string &Name,
+ bool CheckFunctionsOnly);
};
} // End llvm namespace
diff --git a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
index 650832e..cf90e77 100644
--- a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
+++ b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
@@ -19,9 +19,10 @@
namespace llvm {
uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
- unsigned Alignment,
- unsigned SectionID,
- bool IsReadOnly) {
+ unsigned Alignment,
+ unsigned SectionID,
+ StringRef SectionName,
+ bool IsReadOnly) {
if (IsReadOnly)
return allocateSection(RODataMem, Size, Alignment);
return allocateSection(RWDataMem, Size, Alignment);
@@ -29,7 +30,8 @@ uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
unsigned Alignment,
- unsigned SectionID) {
+ unsigned SectionID,
+ StringRef SectionName) {
return allocateSection(CodeMem, Size, Alignment);
}
@@ -105,6 +107,9 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
// FIXME: Should in-progress permissions be reverted if an error occurs?
error_code ec;
+ // Don't allow free memory blocks to be used after setting protection flags.
+ CodeMem.FreeMem.clear();
+
// Make code memory executable.
ec = applyMemoryGroupPermissions(CodeMem,
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
@@ -115,6 +120,9 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
return true;
}
+ // Don't allow free memory blocks to be used after setting protection flags.
+ RODataMem.FreeMem.clear();
+
// Make read-only data memory read-only.
ec = applyMemoryGroupPermissions(RODataMem,
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
diff --git a/lib/ExecutionEngine/OProfileJIT/OProfileJITEventListener.cpp b/lib/ExecutionEngine/OProfileJIT/OProfileJITEventListener.cpp
index 38867ec..f11df82 100644
--- a/lib/ExecutionEngine/OProfileJIT/OProfileJITEventListener.cpp
+++ b/lib/ExecutionEngine/OProfileJIT/OProfileJITEventListener.cpp
@@ -20,7 +20,9 @@
#include "llvm/IR/Function.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/ExecutionEngine/OProfileWrapper.h"
+#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Errno.h"
@@ -52,6 +54,10 @@ public:
const JITEvent_EmittedFunctionDetails &Details);
virtual void NotifyFreeingMachineCode(void *OldPtr);
+
+ virtual void NotifyObjectEmitted(const ObjectImage &Obj);
+
+ virtual void NotifyFreeingObject(const ObjectImage &Obj);
};
void OProfileJITEventListener::initialize() {
@@ -159,6 +165,66 @@ void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
}
}
+void OProfileJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
+ if (!Wrapper.isAgentAvailable()) {
+ return;
+ }
+
+ // Use symbol info to iterate functions in the object.
+ error_code ec;
+ for (object::symbol_iterator I = Obj.begin_symbols(),
+ E = Obj.end_symbols();
+ I != E && !ec;
+ I.increment(ec)) {
+ object::SymbolRef::Type SymType;
+ if (I->getType(SymType)) continue;
+ if (SymType == object::SymbolRef::ST_Function) {
+ StringRef Name;
+ uint64_t Addr;
+ uint64_t Size;
+ if (I->getName(Name)) continue;
+ if (I->getAddress(Addr)) continue;
+ if (I->getSize(Size)) continue;
+
+ if (Wrapper.op_write_native_code(Name.data(), Addr, (void*)Addr, Size)
+ == -1) {
+ DEBUG(dbgs() << "Failed to tell OProfile about native function "
+ << Name << " at ["
+ << (void*)Addr << "-" << ((char*)Addr + Size) << "]\n");
+ continue;
+ }
+ // TODO: support line number info (similar to IntelJITEventListener.cpp)
+ }
+ }
+}
+
+void OProfileJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
+ if (!Wrapper.isAgentAvailable()) {
+ return;
+ }
+
+ // Use symbol info to iterate functions in the object.
+ error_code ec;
+ for (object::symbol_iterator I = Obj.begin_symbols(),
+ E = Obj.end_symbols();
+ I != E && !ec;
+ I.increment(ec)) {
+ object::SymbolRef::Type SymType;
+ if (I->getType(SymType)) continue;
+ if (SymType == object::SymbolRef::ST_Function) {
+ uint64_t Addr;
+ if (I->getAddress(Addr)) continue;
+
+ if (Wrapper.op_unload_native_code(Addr) == -1) {
+ DEBUG(dbgs()
+ << "Failed to tell OProfile about unload of native function at "
+ << (void*)Addr << "\n");
+ continue;
+ }
+ }
+ }
+}
+
} // anonymous namespace.
namespace llvm {
diff --git a/lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp b/lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp
index 7c0d395..61d8dc2 100644
--- a/lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp
+++ b/lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp
@@ -13,22 +13,20 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ExecutionEngine/OProfileWrapper.h"
-
#define DEBUG_TYPE "oprofile-wrapper"
+#include "llvm/ExecutionEngine/OProfileWrapper.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/ADT/SmallString.h"
-
-#include <sstream>
#include <cstring>
-#include <stddef.h>
#include <dirent.h>
-#include <sys/stat.h>
#include <fcntl.h>
+#include <sstream>
+#include <stddef.h>
+#include <sys/stat.h>
#include <unistd.h>
namespace {
@@ -143,6 +141,10 @@ bool OProfileWrapper::checkForOProfileProcEntry() {
close(CmdLineFD);
ssize_t Idx = 0;
+ if (ExeName[0] != '/') {
+ BaseName = ExeName;
+ }
+
// Find the terminator for the first string
while (Idx < NumRead-1 && ExeName[Idx] != 0) {
Idx++;
@@ -161,7 +163,8 @@ bool OProfileWrapper::checkForOProfileProcEntry() {
}
// Test this to see if it is the oprofile daemon
- if (BaseName != 0 && !strcmp("oprofiled", BaseName)) {
+ if (BaseName != 0 && (!strcmp("oprofiled", BaseName) ||
+ !strcmp("operf", BaseName))) {
// If it is, we're done
closedir(ProcDir);
return true;
diff --git a/lib/ExecutionEngine/RTDyldMemoryManager.cpp b/lib/ExecutionEngine/RTDyldMemoryManager.cpp
index 4e76457..26e1fdd 100644
--- a/lib/ExecutionEngine/RTDyldMemoryManager.cpp
+++ b/lib/ExecutionEngine/RTDyldMemoryManager.cpp
@@ -33,8 +33,8 @@ namespace llvm {
RTDyldMemoryManager::~RTDyldMemoryManager() {}
// Determine whether we can register EH tables.
-#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
- !defined(__USING_SJLJ_EXCEPTIONS__))
+#if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
+ !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
#define HAVE_EHTABLE_SUPPORT 1
#else
#define HAVE_EHTABLE_SUPPORT 0
@@ -42,35 +42,180 @@ RTDyldMemoryManager::~RTDyldMemoryManager() {}
#if HAVE_EHTABLE_SUPPORT
extern "C" void __register_frame(void*);
+extern "C" void __deregister_frame(void*);
+#else
+// The building compiler does not have __(de)register_frame but
+// it may be found at runtime in a dynamically-loaded library.
+// For example, this happens when building LLVM with Visual C++
+// but using the MingW runtime.
+void __register_frame(void *p) {
+ static bool Searched = false;
+ static void *rf = 0;
+
+ if (!Searched) {
+ Searched = true;
+ rf = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
+ "__register_frame");
+ }
+ if (rf)
+ ((void (*)(void *))rf)(p);
+}
+
+void __deregister_frame(void *p) {
+ static bool Searched = false;
+ static void *df = 0;
+
+ if (!Searched) {
+ Searched = true;
+ df = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
+ "__deregister_frame");
+ }
+ if (df)
+ ((void (*)(void *))df)(p);
+}
+#endif
+
+#ifdef __APPLE__
-static const char *processFDE(const char *Entry) {
+static const char *processFDE(const char *Entry, bool isDeregister) {
const char *P = Entry;
uint32_t Length = *((const uint32_t *)P);
P += 4;
uint32_t Offset = *((const uint32_t *)P);
- if (Offset != 0)
- __register_frame(const_cast<char *>(Entry));
+ if (Offset != 0) {
+ if (isDeregister)
+ __deregister_frame(const_cast<char *>(Entry));
+ else
+ __register_frame(const_cast<char *>(Entry));
+ }
return P + Length;
}
-#endif
-void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {
-#if HAVE_EHTABLE_SUPPORT
- const char *P = SectionData.data();
- const char *End = SectionData.data() + SectionData.size();
+// This implementation handles frame registration for local targets.
+// Memory managers for remote targets should re-implement this function
+// and use the LoadAddr parameter.
+void RTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
+ uint64_t LoadAddr,
+ size_t Size) {
+ // On OS X OS X __register_frame takes a single FDE as an argument.
+ // See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html
+ const char *P = (const char *)Addr;
+ const char *End = P + Size;
do {
- P = processFDE(P);
+ P = processFDE(P, false);
} while(P != End);
-#endif
}
+void RTDyldMemoryManager::deregisterEHFrames(uint8_t *Addr,
+ uint64_t LoadAddr,
+ size_t Size) {
+ const char *P = (const char *)Addr;
+ const char *End = P + Size;
+ do {
+ P = processFDE(P, true);
+ } while(P != End);
+}
+
+#else
+
+void RTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
+ uint64_t LoadAddr,
+ size_t Size) {
+ // On Linux __register_frame takes a single argument:
+ // a pointer to the start of the .eh_frame section.
+
+ // How can it find the end? Because crtendS.o is linked
+ // in and it has an .eh_frame section with four zero chars.
+ __register_frame(Addr);
+}
+
+void RTDyldMemoryManager::deregisterEHFrames(uint8_t *Addr,
+ uint64_t LoadAddr,
+ size_t Size) {
+ __deregister_frame(Addr);
+}
+
+#endif
+
static int jit_noop() {
return 0;
}
-void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
- bool AbortOnFailure) {
-#if defined(__linux__)
+// ARM math functions are statically linked on Android from libgcc.a, but not
+// available at runtime for dynamic linking. On Linux these are usually placed
+// in libgcc_s.so so can be found by normal dynamic lookup.
+#if defined(__BIONIC__) && defined(__arm__)
+// List of functions which are statically linked on Android and can be generated
+// by LLVM. This is done as a nested macro which is used once to declare the
+// imported functions with ARM_MATH_DECL and once to compare them to the
+// user-requested symbol in getSymbolAddress with ARM_MATH_CHECK. The test
+// assumes that all functions start with __aeabi_ and getSymbolAddress must be
+// modified if that changes.
+#define ARM_MATH_IMPORTS(PP) \
+ PP(__aeabi_d2f) \
+ PP(__aeabi_d2iz) \
+ PP(__aeabi_d2lz) \
+ PP(__aeabi_d2uiz) \
+ PP(__aeabi_d2ulz) \
+ PP(__aeabi_dadd) \
+ PP(__aeabi_dcmpeq) \
+ PP(__aeabi_dcmpge) \
+ PP(__aeabi_dcmpgt) \
+ PP(__aeabi_dcmple) \
+ PP(__aeabi_dcmplt) \
+ PP(__aeabi_dcmpun) \
+ PP(__aeabi_ddiv) \
+ PP(__aeabi_dmul) \
+ PP(__aeabi_dsub) \
+ PP(__aeabi_f2d) \
+ PP(__aeabi_f2iz) \
+ PP(__aeabi_f2lz) \
+ PP(__aeabi_f2uiz) \
+ PP(__aeabi_f2ulz) \
+ PP(__aeabi_fadd) \
+ PP(__aeabi_fcmpeq) \
+ PP(__aeabi_fcmpge) \
+ PP(__aeabi_fcmpgt) \
+ PP(__aeabi_fcmple) \
+ PP(__aeabi_fcmplt) \
+ PP(__aeabi_fcmpun) \
+ PP(__aeabi_fdiv) \
+ PP(__aeabi_fmul) \
+ PP(__aeabi_fsub) \
+ PP(__aeabi_i2d) \
+ PP(__aeabi_i2f) \
+ PP(__aeabi_idiv) \
+ PP(__aeabi_idivmod) \
+ PP(__aeabi_l2d) \
+ PP(__aeabi_l2f) \
+ PP(__aeabi_lasr) \
+ PP(__aeabi_ldivmod) \
+ PP(__aeabi_llsl) \
+ PP(__aeabi_llsr) \
+ PP(__aeabi_lmul) \
+ PP(__aeabi_ui2d) \
+ PP(__aeabi_ui2f) \
+ PP(__aeabi_uidiv) \
+ PP(__aeabi_uidivmod) \
+ PP(__aeabi_ul2d) \
+ PP(__aeabi_ul2f) \
+ PP(__aeabi_uldivmod)
+
+// Declare statically linked math functions on ARM. The function declarations
+// here do not have the correct prototypes for each function in
+// ARM_MATH_IMPORTS, but it doesn't matter because only the symbol addresses are
+// needed. In particular the __aeabi_*divmod functions do not have calling
+// conventions which match any C prototype.
+#define ARM_MATH_DECL(name) extern "C" void name();
+ARM_MATH_IMPORTS(ARM_MATH_DECL)
+#undef ARM_MATH_DECL
+#endif
+
+uint64_t RTDyldMemoryManager::getSymbolAddress(const std::string &Name) {
+ // This implementation assumes that the host program is the target.
+ // Clients generating code for a remote target should implement their own
+ // memory manager.
+#if defined(__linux__) && defined(__GLIBC__)
//===--------------------------------------------------------------------===//
// Function stubs that are invoked instead of certain library calls
//
@@ -80,15 +225,26 @@ void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
// not inlined, and hiding their real definitions in a separate archive file
// that the dynamic linker can't see. For more info, search for
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
- if (Name == "stat") return (void*)(intptr_t)&stat;
- if (Name == "fstat") return (void*)(intptr_t)&fstat;
- if (Name == "lstat") return (void*)(intptr_t)&lstat;
- if (Name == "stat64") return (void*)(intptr_t)&stat64;
- if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
- if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
- if (Name == "atexit") return (void*)(intptr_t)&atexit;
- if (Name == "mknod") return (void*)(intptr_t)&mknod;
-#endif // __linux__
+ if (Name == "stat") return (uint64_t)&stat;
+ if (Name == "fstat") return (uint64_t)&fstat;
+ if (Name == "lstat") return (uint64_t)&lstat;
+ if (Name == "stat64") return (uint64_t)&stat64;
+ if (Name == "fstat64") return (uint64_t)&fstat64;
+ if (Name == "lstat64") return (uint64_t)&lstat64;
+ if (Name == "atexit") return (uint64_t)&atexit;
+ if (Name == "mknod") return (uint64_t)&mknod;
+#endif // __linux__ && __GLIBC__
+
+ // See ARM_MATH_IMPORTS definition for explanation
+#if defined(__BIONIC__) && defined(__arm__)
+ if (Name.compare(0, 8, "__aeabi_") == 0) {
+ // Check if the user has requested any of the functions listed in
+ // ARM_MATH_IMPORTS, and if so redirect to the statically linked symbol.
+#define ARM_MATH_CHECK(fn) if (Name == #fn) return (uint64_t)&fn;
+ ARM_MATH_IMPORTS(ARM_MATH_CHECK)
+#undef ARM_MATH_CHECK
+ }
+#endif
// We should not invoke parent's ctors/dtors from generated main()!
// On Mingw and Cygwin, the symbol __main is resolved to
@@ -96,23 +252,31 @@ void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
// (and register wrong callee's dtors with atexit(3)).
// We expect ExecutionEngine::runStaticConstructorsDestructors()
// is called before ExecutionEngine::runFunctionAsMain() is called.
- if (Name == "__main") return (void*)(intptr_t)&jit_noop;
+ if (Name == "__main") return (uint64_t)&jit_noop;
const char *NameStr = Name.c_str();
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
- if (Ptr) return Ptr;
+ if (Ptr)
+ return (uint64_t)Ptr;
// If it wasn't found and if it starts with an underscore ('_') character,
// try again without the underscore.
if (NameStr[0] == '_') {
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
- if (Ptr) return Ptr;
+ if (Ptr)
+ return (uint64_t)Ptr;
}
+ return 0;
+}
- if (AbortOnFailure)
+void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure) {
+ uint64_t Addr = getSymbolAddress(Name);
+
+ if (!Addr && AbortOnFailure)
report_fatal_error("Program used external function '" + Name +
"' which could not be resolved!");
- return 0;
+ return (void*)Addr;
}
} // namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h b/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h
index 69e9dbe..6a514ea 100644
--- a/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h
+++ b/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h
@@ -16,6 +16,7 @@ namespace llvm {
/// Global access point for the JIT debugging interface.
class JITRegistrar {
+ virtual void anchor();
public:
/// Instantiates the JIT service.
JITRegistrar() {}
diff --git a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h
index 89350cc..9cbde5d 100644
--- a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h
+++ b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h
@@ -23,6 +23,7 @@ namespace llvm {
class ObjectImageCommon : public ObjectImage {
ObjectImageCommon(); // = delete
ObjectImageCommon(const ObjectImageCommon &other); // = delete
+ virtual void anchor();
protected:
object::ObjectFile *ObjFile;
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 943622f..161135a 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -13,12 +13,14 @@
#define DEBUG_TYPE "dyld"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
+#include "JITRegistrar.h"
#include "ObjectImageCommon.h"
#include "RuntimeDyldELF.h"
#include "RuntimeDyldImpl.h"
#include "RuntimeDyldMachO.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MutexGuard.h"
#include "llvm/Object/ELF.h"
using namespace llvm;
@@ -27,30 +29,44 @@ using namespace llvm::object;
// Empty out-of-line virtual destructor as the key function.
RuntimeDyldImpl::~RuntimeDyldImpl() {}
+// Pin the JITRegistrar's and ObjectImage*'s vtables to this file.
+void JITRegistrar::anchor() {}
+void ObjectImage::anchor() {}
+void ObjectImageCommon::anchor() {}
+
namespace llvm {
-StringRef RuntimeDyldImpl::getEHFrameSection() {
- return StringRef();
+void RuntimeDyldImpl::registerEHFrames() {
+}
+
+void RuntimeDyldImpl::deregisterEHFrames() {
}
// Resolve the relocations for all symbols we currently know about.
void RuntimeDyldImpl::resolveRelocations() {
+ MutexGuard locked(lock);
+
// First, resolve relocations associated with external symbols.
resolveExternalSymbols();
// Just iterate over the sections we have and resolve all the relocations
// in them. Gross overkill, but it gets the job done.
for (int i = 0, e = Sections.size(); i != e; ++i) {
+ // The Section here (Sections[i]) refers to the section in which the
+ // symbol for the relocation is located. The SectionID in the relocation
+ // entry provides the section to which the relocation will be applied.
uint64_t Addr = Sections[i].LoadAddress;
DEBUG(dbgs() << "Resolving relocations Section #" << i
<< "\t" << format("%p", (uint8_t *)Addr)
<< "\n");
resolveRelocationList(Relocations[i], Addr);
+ Relocations.erase(i);
}
}
void RuntimeDyldImpl::mapSectionAddress(const void *LocalAddress,
uint64_t TargetAddress) {
+ MutexGuard locked(lock);
for (unsigned i = 0, e = Sections.size(); i != e; ++i) {
if (Sections[i].Address == LocalAddress) {
reassignSectionAddress(i, TargetAddress);
@@ -67,11 +83,15 @@ ObjectImage *RuntimeDyldImpl::createObjectImage(ObjectBuffer *InputBuffer) {
}
ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) {
+ MutexGuard locked(lock);
+
OwningPtr<ObjectImage> obj(createObjectImage(InputBuffer));
if (!obj)
report_fatal_error("Unable to create object image from memory buffer!");
+ // Save information about our target
Arch = (Triple::ArchType)obj->getArch();
+ IsTargetLittleEndian = obj->getObjectFile()->isLittleEndian();
// Symbols found in this object
StringMap<SymbolLoc> LocalSymbols;
@@ -166,6 +186,9 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) {
}
}
+ // Give the subclasses a chance to tie-up any loose ends.
+ finalizeLoad(LocalSections);
+
return obj.take();
}
@@ -175,8 +198,8 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
SymbolTableMap &SymbolTable) {
// Allocate memory for the section
unsigned SectionID = Sections.size();
- uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, sizeof(void*),
- SectionID, false);
+ uint8_t *Addr = MemMgr->allocateDataSection(
+ TotalSize, sizeof(void*), SectionID, StringRef(), false);
if (!Addr)
report_fatal_error("Unable to allocate memory for common symbols!");
uint64_t Offset = 0;
@@ -247,6 +270,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
bool IsZeroInit;
bool IsReadOnly;
uint64_t DataSize;
+ unsigned PaddingSize = 0;
StringRef Name;
Check(Section.isRequiredForExecution(IsRequired));
Check(Section.isVirtual(IsVirtual));
@@ -261,6 +285,12 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
StubBufSize += StubAlignment - EndAlignment;
}
+ // The .eh_frame section (at least on Linux) needs an extra four bytes padded
+ // with zeroes added at the end. For MachO objects, this section has a
+ // slightly different name, so this won't have any effect for MachO objects.
+ if (Name == ".eh_frame")
+ PaddingSize = 4;
+
unsigned Allocate;
unsigned SectionID = Sections.size();
uint8_t *Addr;
@@ -269,10 +299,11 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
// Some sections, such as debug info, don't need to be loaded for execution.
// Leave those where they are.
if (IsRequired) {
- Allocate = DataSize + StubBufSize;
+ Allocate = DataSize + PaddingSize + StubBufSize;
Addr = IsCode
- ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID)
- : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, IsReadOnly);
+ ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID, Name)
+ : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, Name,
+ IsReadOnly);
if (!Addr)
report_fatal_error("Unable to allocate section memory!");
@@ -286,6 +317,13 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
else
memcpy(Addr, pData, DataSize);
+ // Fill in any extra bytes we allocated for padding
+ if (PaddingSize != 0) {
+ memset(Addr + DataSize, 0, PaddingSize);
+ // Update the DataSize variable so that the stub offset is set correctly.
+ DataSize += PaddingSize;
+ }
+
DEBUG(dbgs() << "emitSection SectionID: " << SectionID
<< " Name: " << Name
<< " obj addr: " << format("%p", pData)
@@ -421,6 +459,10 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1
// 8-byte address stored at Addr + 8
return Addr;
+ } else if (Arch == Triple::x86_64) {
+ *Addr = 0xFF; // jmp
+ *(Addr+1) = 0x25; // rip
+ // 32-bit PC-relative address of the GOT entry will be stored at Addr+2
}
return Addr;
}
@@ -454,30 +496,52 @@ void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs,
}
void RuntimeDyldImpl::resolveExternalSymbols() {
- StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin(),
- e = ExternalSymbolRelocations.end();
- for (; i != e; i++) {
+ while(!ExternalSymbolRelocations.empty()) {
+ StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin();
+
StringRef Name = i->first();
- RelocationList &Relocs = i->second;
- SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(Name);
- if (Loc == GlobalSymbolTable.end()) {
- if (Name.size() == 0) {
- // This is an absolute symbol, use an address of zero.
- DEBUG(dbgs() << "Resolving absolute relocations." << "\n");
- resolveRelocationList(Relocs, 0);
+ if (Name.size() == 0) {
+ // This is an absolute symbol, use an address of zero.
+ DEBUG(dbgs() << "Resolving absolute relocations." << "\n");
+ RelocationList &Relocs = i->second;
+ resolveRelocationList(Relocs, 0);
+ } else {
+ uint64_t Addr = 0;
+ SymbolTableMap::const_iterator Loc = GlobalSymbolTable.find(Name);
+ if (Loc == GlobalSymbolTable.end()) {
+ // This is an external symbol, try to get its address from
+ // MemoryManager.
+ Addr = MemMgr->getSymbolAddress(Name.data());
+ // The call to getSymbolAddress may have caused additional modules to
+ // be loaded, which may have added new entries to the
+ // ExternalSymbolRelocations map. Consquently, we need to update our
+ // iterator. This is also why retrieval of the relocation list
+ // associated with this symbol is deferred until below this point.
+ // New entries may have been added to the relocation list.
+ i = ExternalSymbolRelocations.find(Name);
} else {
- // This is an external symbol, try to get its address from
- // MemoryManager.
- uint8_t *Addr = (uint8_t*) MemMgr->getPointerToNamedFunction(Name.data(),
- true);
- DEBUG(dbgs() << "Resolving relocations Name: " << Name
- << "\t" << format("%p", Addr)
- << "\n");
- resolveRelocationList(Relocs, (uintptr_t)Addr);
+ // We found the symbol in our global table. It was probably in a
+ // Module that we loaded previously.
+ SymbolLoc SymLoc = Loc->second;
+ Addr = getSectionLoadAddress(SymLoc.first) + SymLoc.second;
}
- } else {
- report_fatal_error("Expected external symbol");
+
+ // FIXME: Implement error handling that doesn't kill the host program!
+ if (!Addr)
+ report_fatal_error("Program used external function '" + Name +
+ "' which could not be resolved!");
+
+ updateGOTEntries(Name, Addr);
+ DEBUG(dbgs() << "Resolving relocations Name: " << Name
+ << "\t" << format("0x%lx", Addr)
+ << "\n");
+ // This list may have been updated when we called getSymbolAddress, so
+ // don't change this code to get the list earlier.
+ RelocationList &Relocs = i->second;
+ resolveRelocationList(Relocs, Addr);
}
+
+ ExternalSymbolRelocations.erase(i);
}
}
@@ -526,8 +590,10 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
case sys::fs::file_magic::bitcode:
case sys::fs::file_magic::archive:
case sys::fs::file_magic::coff_object:
+ case sys::fs::file_magic::coff_import_library:
case sys::fs::file_magic::pecoff_executable:
case sys::fs::file_magic::macho_universal_binary:
+ case sys::fs::file_magic::windows_resource:
report_fatal_error("Incompatible object format!");
}
} else {
@@ -539,10 +605,14 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
}
void *RuntimeDyld::getSymbolAddress(StringRef Name) {
+ if (!Dyld)
+ return NULL;
return Dyld->getSymbolAddress(Name);
}
uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) {
+ if (!Dyld)
+ return 0;
return Dyld->getSymbolLoadAddress(Name);
}
@@ -564,8 +634,14 @@ StringRef RuntimeDyld::getErrorString() {
return Dyld->getErrorString();
}
-StringRef RuntimeDyld::getEHFrameSection() {
- return Dyld->getEHFrameSection();
+void RuntimeDyld::registerEHFrames() {
+ if (Dyld)
+ Dyld->registerEHFrames();
+}
+
+void RuntimeDyld::deregisterEHFrames() {
+ if (Dyld)
+ Dyld->deregisterEHFrames();
}
} // end namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index cd99c3c..f2c69fc 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -22,7 +22,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
-#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/ELF.h"
using namespace llvm;
@@ -151,12 +151,31 @@ void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef,
namespace llvm {
-StringRef RuntimeDyldELF::getEHFrameSection() {
- for (int i = 0, e = Sections.size(); i != e; ++i) {
- if (Sections[i].Name == ".eh_frame")
- return StringRef((const char*)Sections[i].Address, Sections[i].Size);
+void RuntimeDyldELF::registerEHFrames() {
+ if (!MemMgr)
+ return;
+ for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) {
+ SID EHFrameSID = UnregisteredEHFrameSections[i];
+ uint8_t *EHFrameAddr = Sections[EHFrameSID].Address;
+ uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress;
+ size_t EHFrameSize = Sections[EHFrameSID].Size;
+ MemMgr->registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
+ RegisteredEHFrameSections.push_back(EHFrameSID);
}
- return StringRef();
+ UnregisteredEHFrameSections.clear();
+}
+
+void RuntimeDyldELF::deregisterEHFrames() {
+ if (!MemMgr)
+ return;
+ for (int i = 0, e = RegisteredEHFrameSections.size(); i != e; ++i) {
+ SID EHFrameSID = RegisteredEHFrameSections[i];
+ uint8_t *EHFrameAddr = Sections[EHFrameSID].Address;
+ uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress;
+ size_t EHFrameSize = Sections[EHFrameSID].Size;
+ MemMgr->deregisterEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
+ }
+ RegisteredEHFrameSections.clear();
}
ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) {
@@ -202,7 +221,8 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
uint64_t Offset,
uint64_t Value,
uint32_t Type,
- int64_t Addend) {
+ int64_t Addend,
+ uint64_t SymOffset) {
switch (Type) {
default:
llvm_unreachable("Relocation type not implemented yet!");
@@ -227,6 +247,21 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
<< " at " << format("%p\n",Target));
break;
}
+ case ELF::R_X86_64_GOTPCREL: {
+ // findGOTEntry returns the 'G + GOT' part of the relocation calculation
+ // based on the load/target address of the GOT (not the current/local addr).
+ uint64_t GOTAddr = findGOTEntry(Value, SymOffset);
+ uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset);
+ uint64_t FinalAddress = Section.LoadAddress + Offset;
+ // The processRelocationRef method combines the symbol offset and the addend
+ // and in most cases that's what we want. For this relocation type, we need
+ // the raw addend, so we subtract the symbol offset to get it.
+ int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress;
+ assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
+ int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
+ *Target = TruncOffset;
+ break;
+ }
case ELF::R_X86_64_PC32: {
// Get the placeholder value from the generated object since
// a previous relocation attempt may have overwritten the loaded version
@@ -240,6 +275,16 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
*Target = TruncOffset;
break;
}
+ case ELF::R_X86_64_PC64: {
+ // Get the placeholder value from the generated object since
+ // a previous relocation attempt may have overwritten the loaded version
+ uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress
+ + Offset);
+ uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset);
+ uint64_t FinalAddress = Section.LoadAddress + Offset;
+ *Target = *Placeholder + Value + Addend - FinalAddress;
+ break;
+ }
}
}
@@ -304,7 +349,7 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
}
case ELF::R_AARCH64_PREL32: {
uint64_t Result = Value + Addend - FinalAddress;
- assert(static_cast<int64_t>(Result) >= INT32_MIN &&
+ assert(static_cast<int64_t>(Result) >= INT32_MIN &&
static_cast<int64_t>(Result) <= UINT32_MAX);
*TargetPtr = static_cast<uint32_t>(Result & 0xffffffffU);
break;
@@ -316,7 +361,7 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
uint64_t BranchImm = Value + Addend - FinalAddress;
// "Check that -2^27 <= result < 2^27".
- assert(-(1LL << 27) <= static_cast<int64_t>(BranchImm) &&
+ assert(-(1LL << 27) <= static_cast<int64_t>(BranchImm) &&
static_cast<int64_t>(BranchImm) < (1LL << 27));
// AArch64 code is emitted with .rela relocations. The data already in any
@@ -341,7 +386,6 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
case ELF::R_AARCH64_MOVW_UABS_G2_NC: {
uint64_t Result = Value + Addend;
-
// AArch64 code is emitted with .rela relocations. The data already in any
// bits affected by the relocation on entry is garbage.
*TargetPtr &= 0xffe0001fU;
@@ -585,7 +629,7 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
// Finally compares the Symbol value and the target symbol offset
// to check if this .opd entry refers to the symbol the relocation
// points to.
- if (Rel.Addend != (intptr_t)TargetSymbolOffset)
+ if (Rel.Addend != (int64_t)TargetSymbolOffset)
continue;
section_iterator tsi(Obj.end_sections());
@@ -735,20 +779,42 @@ void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
}
}
+// The target location for the relocation is described by RE.SectionID and
+// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
+// SectionEntry has three members describing its location.
+// SectionEntry::Address is the address at which the section has been loaded
+// into memory in the current (host) process. SectionEntry::LoadAddress is the
+// address that the section will have in the target process.
+// SectionEntry::ObjAddress is the address of the bits for this section in the
+// original emitted object image (also in the current address space).
+//
+// Relocations will be applied as if the section were loaded at
+// SectionEntry::LoadAddress, but they will be applied at an address based
+// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to
+// Target memory contents if they are required for value calculations.
+//
+// The Value parameter here is the load address of the symbol for the
+// relocation to be applied. For relocations which refer to symbols in the
+// current object Value will be the LoadAddress of the section in which
+// the symbol resides (RE.Addend provides additional information about the
+// symbol location). For external symbols, Value will be the address of the
+// symbol in the target address space.
void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE,
- uint64_t Value) {
+ uint64_t Value) {
const SectionEntry &Section = Sections[RE.SectionID];
- return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
+ return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
+ RE.SymOffset);
}
void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
uint64_t Offset,
uint64_t Value,
uint32_t Type,
- int64_t Addend) {
+ int64_t Addend,
+ uint64_t SymOffset) {
switch (Arch) {
case Triple::x86_64:
- resolveX86_64Relocation(Section, Offset, Value, Type, Addend);
+ resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset);
break;
case Triple::x86:
resolveX86Relocation(Section, Offset,
@@ -811,6 +877,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
}
if (lsi != Symbols.end()) {
Value.SectionID = lsi->second.first;
+ Value.Offset = lsi->second.second;
Value.Addend = lsi->second.second + Addend;
} else {
// Search for the symbol in the global symbol table
@@ -819,6 +886,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
gsi = GlobalSymbolTable.find(TargetName.data());
if (gsi != GlobalSymbolTable.end()) {
Value.SectionID = gsi->second.first;
+ Value.Offset = gsi->second.second;
Value.Addend = gsi->second.second + Addend;
} else {
switch (SymType) {
@@ -841,9 +909,17 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
Value.Addend = Addend;
break;
}
+ case SymbolRef::ST_Data:
case SymbolRef::ST_Unknown: {
Value.SymbolName = TargetName.data();
Value.Addend = Addend;
+
+ // Absolute relocations will have a zero symbol ID (STN_UNDEF), which
+ // will manifest here as a NULL symbol name.
+ // We can set this as a valid (but empty) symbol name, and rely
+ // on addRelocationForSymbol to handle this.
+ if (!Value.SymbolName)
+ Value.SymbolName = "";
break;
}
default:
@@ -955,8 +1031,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
// Look up for existing stub.
StubMap::const_iterator i = Stubs.find(Value);
if (i != Stubs.end()) {
- resolveRelocation(Section, Offset,
- (uint64_t)Section.Address + i->second, RelType, 0);
+ RelocationEntry RE(SectionID, Offset, RelType, i->second);
+ addRelocationForSection(RE, SectionID);
DEBUG(dbgs() << " Stub function found\n");
} else {
// Create a new stub function.
@@ -981,9 +1057,8 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
addRelocationForSection(RELo, Value.SectionID);
}
- resolveRelocation(Section, Offset,
- (uint64_t)Section.Address + Section.StubOffset,
- RelType, 0);
+ RelocationEntry RE(SectionID, Offset, RelType, Section.StubOffset);
+ addRelocationForSection(RE, SectionID);
Section.StubOffset += getMaxStubSize();
}
} else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) {
@@ -1069,7 +1144,10 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
// Extra check to avoid relocation againt empty symbols (usually
// the R_PPC64_TOC).
- if (Value.SymbolName && !TargetName.empty())
+ if (SymType != SymbolRef::ST_Unknown && TargetName.empty())
+ Value.SymbolName = NULL;
+
+ if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
addRelocationForSection(RE, Value.SectionID);
@@ -1121,8 +1199,67 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
ELF::R_390_PC32DBL, Addend);
else
resolveRelocation(Section, Offset, StubAddress, RelType, Addend);
+ } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) {
+ // The way the PLT relocations normally work is that the linker allocates the
+ // PLT and this relocation makes a PC-relative call into the PLT. The PLT
+ // entry will then jump to an address provided by the GOT. On first call, the
+ // GOT address will point back into PLT code that resolves the symbol. After
+ // the first call, the GOT entry points to the actual function.
+ //
+ // For local functions we're ignoring all of that here and just replacing
+ // the PLT32 relocation type with PC32, which will translate the relocation
+ // into a PC-relative call directly to the function. For external symbols we
+ // can't be sure the function will be within 2^32 bytes of the call site, so
+ // we need to create a stub, which calls into the GOT. This case is
+ // equivalent to the usual PLT implementation except that we use the stub
+ // mechanism in RuntimeDyld (which puts stubs at the end of the section)
+ // rather than allocating a PLT section.
+ if (Value.SymbolName) {
+ // This is a call to an external function.
+ // Look for an existing stub.
+ SectionEntry &Section = Sections[SectionID];
+ StubMap::const_iterator i = Stubs.find(Value);
+ uintptr_t StubAddress;
+ if (i != Stubs.end()) {
+ StubAddress = uintptr_t(Section.Address) + i->second;
+ DEBUG(dbgs() << " Stub function found\n");
+ } else {
+ // Create a new stub function (equivalent to a PLT entry).
+ DEBUG(dbgs() << " Create a new stub function\n");
+
+ uintptr_t BaseAddress = uintptr_t(Section.Address);
+ uintptr_t StubAlignment = getStubAlignment();
+ StubAddress = (BaseAddress + Section.StubOffset +
+ StubAlignment - 1) & -StubAlignment;
+ unsigned StubOffset = StubAddress - BaseAddress;
+ Stubs[Value] = StubOffset;
+ createStubFunction((uint8_t *)StubAddress);
+
+ // Create a GOT entry for the external function.
+ GOTEntries.push_back(Value);
+
+ // Make our stub function a relative call to the GOT entry.
+ RelocationEntry RE(SectionID, StubOffset + 2,
+ ELF::R_X86_64_GOTPCREL, -4);
+ addRelocationForSymbol(RE, Value.SymbolName);
+
+ // Bump our stub offset counter
+ Section.StubOffset = StubOffset + getMaxStubSize();
+ }
+
+ // Make the target call a call into the stub table.
+ resolveRelocation(Section, Offset, StubAddress,
+ ELF::R_X86_64_PC32, Addend);
+ } else {
+ RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend,
+ Value.Offset);
+ addRelocationForSection(RE, Value.SectionID);
+ }
} else {
- RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
+ if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) {
+ GOTEntries.push_back(Value);
+ }
+ RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset);
if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
@@ -1130,6 +1267,137 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
}
}
+void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) {
+
+ SmallVectorImpl<std::pair<SID, GOTRelocations> >::iterator it;
+ SmallVectorImpl<std::pair<SID, GOTRelocations> >::iterator end = GOTs.end();
+
+ for (it = GOTs.begin(); it != end; ++it) {
+ GOTRelocations &GOTEntries = it->second;
+ for (int i = 0, e = GOTEntries.size(); i != e; ++i) {
+ if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName == Name) {
+ GOTEntries[i].Offset = Addr;
+ }
+ }
+ }
+}
+
+size_t RuntimeDyldELF::getGOTEntrySize() {
+ // We don't use the GOT in all of these cases, but it's essentially free
+ // to put them all here.
+ size_t Result = 0;
+ switch (Arch) {
+ case Triple::x86_64:
+ case Triple::aarch64:
+ case Triple::ppc64:
+ case Triple::ppc64le:
+ case Triple::systemz:
+ Result = sizeof(uint64_t);
+ break;
+ case Triple::x86:
+ case Triple::arm:
+ case Triple::thumb:
+ case Triple::mips:
+ case Triple::mipsel:
+ Result = sizeof(uint32_t);
+ break;
+ default: llvm_unreachable("Unsupported CPU type!");
+ }
+ return Result;
+}
+
+uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress,
+ uint64_t Offset) {
+
+ const size_t GOTEntrySize = getGOTEntrySize();
+
+ SmallVectorImpl<std::pair<SID, GOTRelocations> >::const_iterator it;
+ SmallVectorImpl<std::pair<SID, GOTRelocations> >::const_iterator end = GOTs.end();
+
+ int GOTIndex = -1;
+ for (it = GOTs.begin(); it != end; ++it) {
+ SID GOTSectionID = it->first;
+ const GOTRelocations &GOTEntries = it->second;
+
+ // Find the matching entry in our vector.
+ uint64_t SymbolOffset = 0;
+ for (int i = 0, e = GOTEntries.size(); i != e; ++i) {
+ if (GOTEntries[i].SymbolName == 0) {
+ if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress &&
+ GOTEntries[i].Offset == Offset) {
+ GOTIndex = i;
+ SymbolOffset = GOTEntries[i].Offset;
+ break;
+ }
+ } else {
+ // GOT entries for external symbols use the addend as the address when
+ // the external symbol has been resolved.
+ if (GOTEntries[i].Offset == LoadAddress) {
+ GOTIndex = i;
+ // Don't use the Addend here. The relocation handler will use it.
+ break;
+ }
+ }
+ }
+
+ if (GOTIndex != -1) {
+ if (GOTEntrySize == sizeof(uint64_t)) {
+ uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID);
+ // Fill in this entry with the address of the symbol being referenced.
+ LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset;
+ } else {
+ uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID);
+ // Fill in this entry with the address of the symbol being referenced.
+ LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset);
+ }
+
+ // Calculate the load address of this entry
+ return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize);
+ }
+ }
+
+ assert(GOTIndex != -1 && "Unable to find requested GOT entry.");
+ return 0;
+}
+
+void RuntimeDyldELF::finalizeLoad(ObjSectionToIDMap &SectionMap) {
+ // If necessary, allocate the global offset table
+ if (MemMgr) {
+ // Allocate the GOT if necessary
+ size_t numGOTEntries = GOTEntries.size();
+ if (numGOTEntries != 0) {
+ // Allocate memory for the section
+ unsigned SectionID = Sections.size();
+ size_t TotalSize = numGOTEntries * getGOTEntrySize();
+ uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, getGOTEntrySize(),
+ SectionID, ".got", false);
+ if (!Addr)
+ report_fatal_error("Unable to allocate memory for GOT!");
+
+ GOTs.push_back(std::make_pair(SectionID, GOTEntries));
+ Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0));
+ // For now, initialize all GOT entries to zero. We'll fill them in as
+ // needed when GOT-based relocations are applied.
+ memset(Addr, 0, TotalSize);
+ }
+ }
+ else {
+ report_fatal_error("Unable to allocate memory for GOT!");
+ }
+
+ // Look for and record the EH frame section.
+ ObjSectionToIDMap::iterator i, e;
+ for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) {
+ const SectionRef &Section = i->first;
+ StringRef Name;
+ Section.getName(Name);
+ if (Name == ".eh_frame") {
+ UnregisteredEHFrameSections.push_back(i->second);
+ break;
+ }
+ }
+}
+
bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const {
if (Buffer->getBufferSize() < strlen(ELF::ElfMagic))
return false;
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
index 794c7ec..3adf827 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
@@ -15,6 +15,7 @@
#define LLVM_RUNTIME_DYLD_ELF_H
#include "RuntimeDyldImpl.h"
+#include "llvm/ADT/DenseMap.h"
using namespace llvm;
@@ -35,13 +36,15 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
uint64_t Offset,
uint64_t Value,
uint32_t Type,
- int64_t Addend);
+ int64_t Addend,
+ uint64_t SymOffset=0);
void resolveX86_64Relocation(const SectionEntry &Section,
uint64_t Offset,
uint64_t Value,
uint32_t Type,
- int64_t Addend);
+ int64_t Addend,
+ uint64_t SymOffset);
void resolveX86Relocation(const SectionEntry &Section,
uint64_t Offset,
@@ -79,13 +82,55 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
uint32_t Type,
int64_t Addend);
+ unsigned getMaxStubSize() {
+ if (Arch == Triple::aarch64)
+ return 20; // movz; movk; movk; movk; br
+ if (Arch == Triple::arm || Arch == Triple::thumb)
+ return 8; // 32-bit instruction and 32-bit address
+ else if (Arch == Triple::mipsel || Arch == Triple::mips)
+ return 16;
+ else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
+ return 44;
+ else if (Arch == Triple::x86_64)
+ return 6; // 2-byte jmp instruction + 32-bit relative address
+ else if (Arch == Triple::systemz)
+ return 16;
+ else
+ return 0;
+ }
+
+ unsigned getStubAlignment() {
+ if (Arch == Triple::systemz)
+ return 8;
+ else
+ return 1;
+ }
+
uint64_t findPPC64TOC() const;
void findOPDEntrySection(ObjectImage &Obj,
ObjSectionToIDMap &LocalSections,
RelocationValueRef &Rel);
+ uint64_t findGOTEntry(uint64_t LoadAddr, uint64_t Offset);
+ size_t getGOTEntrySize();
+
+ virtual void updateGOTEntries(StringRef Name, uint64_t Addr);
+
+ // Relocation entries for symbols whose position-independant offset is
+ // updated in a global offset table.
+ typedef SmallVector<RelocationValueRef, 2> GOTRelocations;
+ GOTRelocations GOTEntries; // List of entries requiring finalization.
+ SmallVector<std::pair<SID, GOTRelocations>, 8> GOTs; // Allocated tables.
+
+ // When a module is loaded we save the SectionID of the EH frame section
+ // in a table until we receive a request to register all unregistered
+ // EH frame sections with the memory manager.
+ SmallVector<SID, 2> UnregisteredEHFrameSections;
+ SmallVector<SID, 2> RegisteredEHFrameSections;
+
public:
- RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
+ RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm)
+ {}
virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value);
virtual void processRelocationRef(unsigned SectionID,
@@ -96,7 +141,9 @@ public:
StubMap &Stubs);
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
- virtual StringRef getEHFrameSection();
+ virtual void registerEHFrames();
+ virtual void deregisterEHFrames();
+ virtual void finalizeLoad(ObjSectionToIDMap &SectionMap);
virtual ~RuntimeDyldELF();
};
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index 14d945b..3014b30 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -25,6 +25,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/Mutex.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
@@ -80,14 +81,18 @@ public:
unsigned SectionID;
/// Offset - offset into the section.
- uintptr_t Offset;
+ uint64_t Offset;
/// RelType - relocation type.
uint32_t RelType;
/// Addend - the relocation addend encoded in the instruction itself. Also
/// used to make a relocation section relative instead of symbol relative.
- intptr_t Addend;
+ int64_t Addend;
+
+ /// SymOffset - Section offset of the relocation entry's symbol (used for GOT
+ /// lookup).
+ uint64_t SymOffset;
/// True if this is a PCRel relocation (MachO specific).
bool IsPCRel;
@@ -97,26 +102,39 @@ public:
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
- IsPCRel(false), Size(0) {}
+ SymOffset(0), IsPCRel(false), Size(0) {}
+
+ RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,
+ uint64_t symoffset)
+ : SectionID(id), Offset(offset), RelType(type), Addend(addend),
+ SymOffset(symoffset), IsPCRel(false), Size(0) {}
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,
bool IsPCRel, unsigned Size)
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
- IsPCRel(IsPCRel), Size(Size) {}
+ SymOffset(0), IsPCRel(IsPCRel), Size(Size) {}
};
class RelocationValueRef {
public:
unsigned SectionID;
- intptr_t Addend;
+ uint64_t Offset;
+ int64_t Addend;
const char *SymbolName;
- RelocationValueRef(): SectionID(0), Addend(0), SymbolName(0) {}
+ RelocationValueRef(): SectionID(0), Offset(0), Addend(0), SymbolName(0) {}
inline bool operator==(const RelocationValueRef &Other) const {
- return std::memcmp(this, &Other, sizeof(RelocationValueRef)) == 0;
+ return SectionID == Other.SectionID && Offset == Other.Offset &&
+ Addend == Other.Addend && SymbolName == Other.SymbolName;
}
inline bool operator <(const RelocationValueRef &Other) const {
- return std::memcmp(this, &Other, sizeof(RelocationValueRef)) < 0;
+ if (SectionID != Other.SectionID)
+ return SectionID < Other.SectionID;
+ if (Offset != Other.Offset)
+ return Offset < Other.Offset;
+ if (Addend != Other.Addend)
+ return Addend < Other.Addend;
+ return SymbolName < Other.SymbolName;
}
};
@@ -130,6 +148,9 @@ protected:
typedef SmallVector<SectionEntry, 64> SectionList;
SectionList Sections;
+ typedef unsigned SID; // Type for SectionIDs
+ #define RTDYLD_INVALID_SECTION_ID ((SID)(-1))
+
// Keep a map of sections from object file to the SectionID which
// references it.
typedef std::map<SectionRef, unsigned> ObjSectionToIDMap;
@@ -164,30 +185,22 @@ protected:
typedef std::map<RelocationValueRef, uintptr_t> StubMap;
Triple::ArchType Arch;
-
- inline unsigned getMaxStubSize() {
- if (Arch == Triple::aarch64)
- return 20; // movz; movk; movk; movk; br
- if (Arch == Triple::arm || Arch == Triple::thumb)
- return 8; // 32-bit instruction and 32-bit address
- else if (Arch == Triple::mipsel || Arch == Triple::mips)
- return 16;
- else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
- return 44;
- else if (Arch == Triple::x86_64)
- return 8; // GOT
- else if (Arch == Triple::systemz)
- return 16;
- else
- return 0;
- }
-
- inline unsigned getStubAlignment() {
- if (Arch == Triple::systemz)
- return 8;
- else
- return 1;
- }
+ bool IsTargetLittleEndian;
+
+ // This mutex prevents simultaneously loading objects from two different
+ // threads. This keeps us from having to protect individual data structures
+ // and guarantees that section allocation requests to the memory manager
+ // won't be interleaved between modules. It is also used in mapSectionAddress
+ // and resolveRelocations to protect write access to internal data structures.
+ //
+ // loadObject may be called on the same thread during the handling of of
+ // processRelocations, and that's OK. The handling of the relocation lists
+ // is written in such a way as to work correctly if new elements are added to
+ // the end of the list while the list is being processed.
+ sys::Mutex lock;
+
+ virtual unsigned getMaxStubSize() = 0;
+ virtual unsigned getStubAlignment() = 0;
bool HasError;
std::string ErrorStr;
@@ -208,14 +221,14 @@ protected:
}
void writeInt16BE(uint8_t *Addr, uint16_t Value) {
- if (sys::IsLittleEndianHost)
+ if (IsTargetLittleEndian)
Value = sys::SwapByteOrder(Value);
*Addr = (Value >> 8) & 0xFF;
*(Addr+1) = Value & 0xFF;
}
void writeInt32BE(uint8_t *Addr, uint32_t Value) {
- if (sys::IsLittleEndianHost)
+ if (IsTargetLittleEndian)
Value = sys::SwapByteOrder(Value);
*Addr = (Value >> 24) & 0xFF;
*(Addr+1) = (Value >> 16) & 0xFF;
@@ -224,7 +237,7 @@ protected:
}
void writeInt64BE(uint8_t *Addr, uint64_t Value) {
- if (sys::IsLittleEndianHost)
+ if (IsTargetLittleEndian)
Value = sys::SwapByteOrder(Value);
*Addr = (Value >> 56) & 0xFF;
*(Addr+1) = (Value >> 48) & 0xFF;
@@ -292,6 +305,11 @@ protected:
/// \brief Resolve relocations to external symbols.
void resolveExternalSymbols();
+
+ /// \brief Update GOT entries for external symbols.
+ // The base class does nothing. ELF overrides this.
+ virtual void updateGOTEntries(StringRef Name, uint64_t Addr) {}
+
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
public:
RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) {}
@@ -303,18 +321,20 @@ public:
void *getSymbolAddress(StringRef Name) {
// FIXME: Just look up as a function for now. Overly simple of course.
// Work in progress.
- if (GlobalSymbolTable.find(Name) == GlobalSymbolTable.end())
+ SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name);
+ if (pos == GlobalSymbolTable.end())
return 0;
- SymbolLoc Loc = GlobalSymbolTable.lookup(Name);
+ SymbolLoc Loc = pos->second;
return getSectionAddress(Loc.first) + Loc.second;
}
uint64_t getSymbolLoadAddress(StringRef Name) {
// FIXME: Just look up as a function for now. Overly simple of course.
// Work in progress.
- if (GlobalSymbolTable.find(Name) == GlobalSymbolTable.end())
+ SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name);
+ if (pos == GlobalSymbolTable.end())
return 0;
- SymbolLoc Loc = GlobalSymbolTable.lookup(Name);
+ SymbolLoc Loc = pos->second;
return getSectionLoadAddress(Loc.first) + Loc.second;
}
@@ -335,7 +355,11 @@ public:
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0;
- virtual StringRef getEHFrameSection();
+ virtual void registerEHFrames();
+
+ virtual void deregisterEHFrames();
+
+ virtual void finalizeLoad(ObjSectionToIDMap &SectionMap) {}
};
} // end namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
index 0384b32..5b92867 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
@@ -55,35 +55,80 @@ static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) {
return ObjDistance - MemDistance;
}
-StringRef RuntimeDyldMachO::getEHFrameSection() {
- SectionEntry *Text = NULL;
- SectionEntry *EHFrame = NULL;
- SectionEntry *ExceptTab = NULL;
- for (int i = 0, e = Sections.size(); i != e; ++i) {
- if (Sections[i].Name == "__eh_frame")
- EHFrame = &Sections[i];
- else if (Sections[i].Name == "__text")
- Text = &Sections[i];
- else if (Sections[i].Name == "__gcc_except_tab")
- ExceptTab = &Sections[i];
+void RuntimeDyldMachO::registerEHFrames() {
+
+ if (!MemMgr)
+ return;
+ for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) {
+ EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i];
+ if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID ||
+ SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID)
+ continue;
+ SectionEntry *Text = &Sections[SectionInfo.TextSID];
+ SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID];
+ SectionEntry *ExceptTab = NULL;
+ if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID)
+ ExceptTab = &Sections[SectionInfo.ExceptTabSID];
+
+ intptr_t DeltaForText = computeDelta(Text, EHFrame);
+ intptr_t DeltaForEH = 0;
+ if (ExceptTab)
+ DeltaForEH = computeDelta(ExceptTab, EHFrame);
+
+ unsigned char *P = EHFrame->Address;
+ unsigned char *End = P + EHFrame->Size;
+ do {
+ P = processFDE(P, DeltaForText, DeltaForEH);
+ } while(P != End);
+
+ MemMgr->registerEHFrames(EHFrame->Address,
+ EHFrame->LoadAddress,
+ EHFrame->Size);
}
- if (Text == NULL || EHFrame == NULL)
- return StringRef();
-
- intptr_t DeltaForText = computeDelta(Text, EHFrame);
- intptr_t DeltaForEH = 0;
- if (ExceptTab)
- DeltaForEH = computeDelta(ExceptTab, EHFrame);
-
- unsigned char *P = EHFrame->Address;
- unsigned char *End = P + EHFrame->Size;
- do {
- P = processFDE(P, DeltaForText, DeltaForEH);
- } while(P != End);
+ UnregisteredEHFrameSections.clear();
+}
- return StringRef((char*)EHFrame->Address, EHFrame->Size);
+void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) {
+ unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID;
+ unsigned TextSID = RTDYLD_INVALID_SECTION_ID;
+ unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID;
+ ObjSectionToIDMap::iterator i, e;
+ for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) {
+ const SectionRef &Section = i->first;
+ StringRef Name;
+ Section.getName(Name);
+ if (Name == "__eh_frame")
+ EHFrameSID = i->second;
+ else if (Name == "__text")
+ TextSID = i->second;
+ else if (Name == "__gcc_except_tab")
+ ExceptTabSID = i->second;
+ }
+ UnregisteredEHFrameSections.push_back(EHFrameRelatedSections(EHFrameSID,
+ TextSID,
+ ExceptTabSID));
}
+// The target location for the relocation is described by RE.SectionID and
+// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
+// SectionEntry has three members describing its location.
+// SectionEntry::Address is the address at which the section has been loaded
+// into memory in the current (host) process. SectionEntry::LoadAddress is the
+// address that the section will have in the target process.
+// SectionEntry::ObjAddress is the address of the bits for this section in the
+// original emitted object image (also in the current address space).
+//
+// Relocations will be applied as if the section were loaded at
+// SectionEntry::LoadAddress, but they will be applied at an address based
+// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to
+// Target memory contents if they are required for value calculations.
+//
+// The Value parameter here is the load address of the symbol for the
+// relocation to be applied. For relocations which refer to symbols in the
+// current object Value will be the LoadAddress of the section in which
+// the symbol resides (RE.Addend provides additional information about the
+// symbol location). For external symbols, Value will be the address of the
+// symbol in the target address space.
void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE,
uint64_t Value) {
const SectionEntry &Section = Sections[RE.SectionID];
@@ -160,7 +205,7 @@ bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress,
switch (Type) {
default:
llvm_unreachable("Invalid relocation type!");
- case macho::RIT_Vanilla: {
+ case MachO::GENERIC_RELOC_VANILLA: {
uint8_t *p = LocalAddress;
uint64_t ValueToWrite = Value + Addend;
for (unsigned i = 0; i < Size; ++i) {
@@ -169,9 +214,9 @@ bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress,
}
return false;
}
- case macho::RIT_Difference:
- case macho::RIT_Generic_LocalDifference:
- case macho::RIT_Generic_PreboundLazyPointer:
+ case MachO::GENERIC_RELOC_SECTDIFF:
+ case MachO::GENERIC_RELOC_LOCAL_SECTDIFF:
+ case MachO::GENERIC_RELOC_PB_LA_PTR:
return Error("Relocation type not implemented yet!");
}
}
@@ -193,12 +238,12 @@ bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress,
switch(Type) {
default:
llvm_unreachable("Invalid relocation type!");
- case macho::RIT_X86_64_Signed1:
- case macho::RIT_X86_64_Signed2:
- case macho::RIT_X86_64_Signed4:
- case macho::RIT_X86_64_Signed:
- case macho::RIT_X86_64_Unsigned:
- case macho::RIT_X86_64_Branch: {
+ case MachO::X86_64_RELOC_SIGNED_1:
+ case MachO::X86_64_RELOC_SIGNED_2:
+ case MachO::X86_64_RELOC_SIGNED_4:
+ case MachO::X86_64_RELOC_SIGNED:
+ case MachO::X86_64_RELOC_UNSIGNED:
+ case MachO::X86_64_RELOC_BRANCH: {
Value += Addend;
// Mask in the target value a byte at a time (we don't have an alignment
// guarantee for the target address, so this is safest).
@@ -209,10 +254,10 @@ bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress,
}
return false;
}
- case macho::RIT_X86_64_GOTLoad:
- case macho::RIT_X86_64_GOT:
- case macho::RIT_X86_64_Subtractor:
- case macho::RIT_X86_64_TLV:
+ case MachO::X86_64_RELOC_GOT_LOAD:
+ case MachO::X86_64_RELOC_GOT:
+ case MachO::X86_64_RELOC_SUBTRACTOR:
+ case MachO::X86_64_RELOC_TLV:
return Error("Relocation type not implemented yet!");
}
}
@@ -237,7 +282,7 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress,
switch(Type) {
default:
llvm_unreachable("Invalid relocation type!");
- case macho::RIT_Vanilla: {
+ case MachO::ARM_RELOC_VANILLA: {
// Mask in the target value a byte at a time (we don't have an alignment
// guarantee for the target address, so this is safest).
uint8_t *p = (uint8_t*)LocalAddress;
@@ -247,7 +292,7 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress,
}
break;
}
- case macho::RIT_ARM_Branch24Bit: {
+ case MachO::ARM_RELOC_BR24: {
// Mask the value into the target address. We know instructions are
// 32-bit aligned, so we can do it all at once.
uint32_t *p = (uint32_t*)LocalAddress;
@@ -263,14 +308,14 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress,
*p = (*p & ~0xffffff) | Value;
break;
}
- case macho::RIT_ARM_ThumbBranch22Bit:
- case macho::RIT_ARM_ThumbBranch32Bit:
- case macho::RIT_ARM_Half:
- case macho::RIT_ARM_HalfDifference:
- case macho::RIT_Pair:
- case macho::RIT_Difference:
- case macho::RIT_ARM_LocalDifference:
- case macho::RIT_ARM_PreboundLazyPointer:
+ case MachO::ARM_THUMB_RELOC_BR22:
+ case MachO::ARM_THUMB_32BIT_BRANCH:
+ case MachO::ARM_RELOC_HALF:
+ case MachO::ARM_RELOC_HALF_SECTDIFF:
+ case MachO::ARM_RELOC_PAIR:
+ case MachO::ARM_RELOC_SECTDIFF:
+ case MachO::ARM_RELOC_LOCAL_SECTDIFF:
+ case MachO::ARM_RELOC_PB_LA_PTR:
return Error("Relocation type not implemented yet!");
}
return false;
@@ -284,9 +329,19 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
StubMap &Stubs) {
const ObjectFile *OF = Obj.getObjectFile();
const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF);
- macho::RelocationEntry RE = MachO->getRelocation(RelI.getRawDataRefImpl());
+ MachO::any_relocation_info RE= MachO->getRelocation(RelI.getRawDataRefImpl());
uint32_t RelType = MachO->getAnyRelocationType(RE);
+
+ // FIXME: Properly handle scattered relocations.
+ // For now, optimistically skip these: they can often be ignored, as
+ // the static linker will already have applied the relocation, and it
+ // only needs to be reapplied if symbols move relative to one another.
+ // Note: This will fail horribly where the relocations *do* need to be
+ // applied, but that was already the case.
+ if (MachO->isRelocationScattered(RE))
+ return;
+
RelocationValueRef Value;
SectionEntry &Section = Sections[SectionID];
@@ -329,7 +384,8 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
Value.Addend = Addend - Addr;
}
- if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) {
+ if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT ||
+ RelType == MachO::X86_64_RELOC_GOT_LOAD)) {
assert(IsPCRel);
assert(Size == 2);
StubMap::const_iterator i = Stubs.find(Value);
@@ -340,8 +396,7 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
Stubs[Value] = Section.StubOffset;
uint8_t *GOTEntry = Section.Address + Section.StubOffset;
RelocationEntry RE(SectionID, Section.StubOffset,
- macho::RIT_X86_64_Unsigned, Value.Addend - 4, false,
- 3);
+ MachO::X86_64_RELOC_UNSIGNED, 0, false, 3);
if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
@@ -350,9 +405,9 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
Addr = GOTEntry;
}
resolveRelocation(Section, Offset, (uint64_t)Addr,
- macho::RIT_X86_64_Unsigned, 4, true, 2);
+ MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2);
} else if (Arch == Triple::arm &&
- (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) {
+ (RelType & 0xf) == MachO::ARM_RELOC_BR24) {
// This is an ARM branch relocation, need to use a stub function.
// Look up for existing stub.
@@ -367,7 +422,7 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
uint8_t *StubTargetAddr = createStubFunction(Section.Address +
Section.StubOffset);
RelocationEntry RE(SectionID, StubTargetAddr - Section.Address,
- macho::RIT_Vanilla, Value.Addend);
+ MachO::GENERIC_RELOC_VANILLA, Value.Addend);
if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
index df8d3bb..bbf6aa9 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
@@ -54,6 +54,35 @@ class RuntimeDyldMachO : public RuntimeDyldImpl {
int64_t Addend,
bool isPCRel,
unsigned Size);
+
+ unsigned getMaxStubSize() {
+ if (Arch == Triple::arm || Arch == Triple::thumb)
+ return 8; // 32-bit instruction and 32-bit address
+ else if (Arch == Triple::x86_64)
+ return 8; // GOT entry
+ else
+ return 0;
+ }
+
+ unsigned getStubAlignment() {
+ return 1;
+ }
+
+ struct EHFrameRelatedSections {
+ EHFrameRelatedSections() : EHFrameSID(RTDYLD_INVALID_SECTION_ID),
+ TextSID(RTDYLD_INVALID_SECTION_ID),
+ ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {}
+ EHFrameRelatedSections(SID EH, SID T, SID Ex)
+ : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {}
+ SID EHFrameSID;
+ SID TextSID;
+ SID ExceptTabSID;
+ };
+
+ // When a module is loaded we save the SectionID of the EH frame section
+ // in a table until we receive a request to register all unregistered
+ // EH frame sections with the memory manager.
+ SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections;
public:
RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
@@ -65,7 +94,8 @@ public:
const SymbolTableMap &Symbols,
StubMap &Stubs);
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
- virtual StringRef getEHFrameSection();
+ virtual void registerEHFrames();
+ virtual void finalizeLoad(ObjSectionToIDMap &SectionMap);
};
} // end namespace llvm
diff --git a/lib/ExecutionEngine/TargetSelect.cpp b/lib/ExecutionEngine/TargetSelect.cpp
index 558d8b3..9b7d348 100644
--- a/lib/ExecutionEngine/TargetSelect.cpp
+++ b/lib/ExecutionEngine/TargetSelect.cpp
@@ -91,7 +91,7 @@ TargetMachine *EngineBuilder::selectTarget(const Triple &TargetTriple,
// FIXME: non-iOS ARM FastISel is broken with MCJIT.
if (UseMCJIT &&
TheTriple.getArch() == Triple::arm &&
- TheTriple.getOS() != Triple::IOS &&
+ !TheTriple.isiOS() &&
OptLevel == CodeGenOpt::None) {
OptLevel = CodeGenOpt::Less;
}