diff options
Diffstat (limited to 'lib/ExecutionEngine')
18 files changed, 779 insertions, 913 deletions
diff --git a/lib/ExecutionEngine/CMakeLists.txt b/lib/ExecutionEngine/CMakeLists.txt index cb11bfe..3102c7b 100644 --- a/lib/ExecutionEngine/CMakeLists.txt +++ b/lib/ExecutionEngine/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_library(LLVMExecutionEngine ExecutionEngine.cpp ExecutionEngineBindings.cpp + RTDyldMemoryManager.cpp TargetSelect.cpp ) diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index e43ba4f..0191636 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "jit" #include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/ExecutionEngine/GenericValue.h" @@ -47,7 +48,7 @@ ExecutionEngine *(*ExecutionEngine::JITCtor)( ExecutionEngine *(*ExecutionEngine::MCJITCtor)( Module *M, std::string *ErrorStr, - JITMemoryManager *JMM, + RTDyldMemoryManager *MCJMM, bool GVsWithCode, TargetMachine *TM) = 0; ExecutionEngine *(*ExecutionEngine::InterpCtor)(Module *M, @@ -455,10 +456,12 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { if (sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr)) return 0; + assert(!(JMM && MCJMM)); + // If the user specified a memory manager but didn't specify which engine to // create, we assume they only want the JIT, and we fail if they only want // the interpreter. - if (JMM) { + if (JMM || MCJMM) { if (WhichEngine & EngineKind::JIT) WhichEngine = EngineKind::JIT; else { @@ -467,6 +470,14 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { return 0; } } + + if (MCJMM && ! UseMCJIT) { + if (ErrorStr) + *ErrorStr = + "Cannot create a legacy JIT with a runtime dyld memory " + "manager."; + return 0; + } // Unless the interpreter was explicitly selected or the JIT is not linked, // try making a JIT. @@ -480,7 +491,7 @@ ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { if (UseMCJIT && ExecutionEngine::MCJITCtor) { ExecutionEngine *EE = - ExecutionEngine::MCJITCtor(M, ErrorStr, JMM, + ExecutionEngine::MCJITCtor(M, ErrorStr, MCJMM ? MCJMM : JMM, AllocateGVsWithCode, TheTM.take()); if (EE) return EE; } else if (ExecutionEngine::JITCtor) { diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp index f9b08a0..88e73bf 100644 --- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp +++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp @@ -15,6 +15,7 @@ #include "llvm-c/ExecutionEngine.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" #include "llvm/Support/ErrorHandling.h" @@ -157,10 +158,8 @@ LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions) { LLVMMCJITCompilerOptions options; - options.OptLevel = 0; + memset(&options, 0, sizeof(options)); // Most fields are zero by default. options.CodeModel = LLVMCodeModelJITDefault; - options.NoFramePointerElim = false; - options.EnableFastISel = false; memcpy(PassedOptions, &options, std::min(sizeof(options), SizeOfPassedOptions)); @@ -199,6 +198,8 @@ LLVMBool LLVMCreateMCJITCompilerForModule( .setOptLevel((CodeGenOpt::Level)options.OptLevel) .setCodeModel(unwrap(options.CodeModel)) .setTargetOptions(targetOptions); + if (options.MCJMM) + builder.setMCJITMemoryManager(unwrap(options.MCJMM)); if (ExecutionEngine *JIT = builder.create()) { *OutJIT = wrap(JIT); return 0; @@ -332,3 +333,110 @@ void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) { return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global)); } + +/*===-- Operations on memory managers -------------------------------------===*/ + +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); +}; + +class SimpleBindingMemoryManager : public RTDyldMemoryManager { +public: + SimpleBindingMemoryManager(const SimpleBindingMMFunctions& Functions, + void *Opaque); + virtual ~SimpleBindingMemoryManager(); + + virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + bool isReadOnly); + + virtual bool finalizeMemory(std::string *ErrMsg); + +private: + SimpleBindingMMFunctions Functions; + void *Opaque; +}; + +SimpleBindingMemoryManager::SimpleBindingMemoryManager( + const SimpleBindingMMFunctions& Functions, + void *Opaque) + : Functions(Functions), Opaque(Opaque) { + assert(Functions.AllocateCodeSection && + "No AllocateCodeSection function provided!"); + assert(Functions.AllocateDataSection && + "No AllocateDataSection function provided!"); + assert(Functions.FinalizeMemory && + "No FinalizeMemory function provided!"); + assert(Functions.Destroy && + "No Destroy function provided!"); +} + +SimpleBindingMemoryManager::~SimpleBindingMemoryManager() { + Functions.Destroy(Opaque); +} + +uint8_t *SimpleBindingMemoryManager::allocateCodeSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID) { + return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID); +} + +uint8_t *SimpleBindingMemoryManager::allocateDataSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, bool isReadOnly) { + return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID, + isReadOnly); +} + +bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) { + char *errMsgCString = 0; + bool result = Functions.FinalizeMemory(Opaque, &errMsgCString); + assert((result || !errMsgCString) && + "Did not expect an error message if FinalizeMemory succeeded"); + if (errMsgCString) { + if (ErrMsg) + *ErrMsg = errMsgCString; + free(errMsgCString); + } + return result; +} + +} // anonymous namespace + +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)) { + + if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory || + !Destroy) + return NULL; + + SimpleBindingMMFunctions functions; + functions.AllocateCodeSection = AllocateCodeSection; + functions.AllocateDataSection = AllocateDataSection; + functions.FinalizeMemory = FinalizeMemory; + functions.Destroy = Destroy; + return wrap(new SimpleBindingMemoryManager(functions, Opaque)); +} + +void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM) { + delete unwrap(MM); +} + diff --git a/lib/ExecutionEngine/JIT/CMakeLists.txt b/lib/ExecutionEngine/JIT/CMakeLists.txt index 52bb389..e16baed 100644 --- a/lib/ExecutionEngine/JIT/CMakeLists.txt +++ b/lib/ExecutionEngine/JIT/CMakeLists.txt @@ -3,7 +3,6 @@ add_definitions(-DENABLE_X86_JIT) add_llvm_library(LLVMJIT JIT.cpp - JITDwarfEmitter.cpp JITEmitter.cpp JITMemoryManager.cpp ) diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp deleted file mode 100644 index 35d2b8b..0000000 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp +++ /dev/null @@ -1,596 +0,0 @@ -//===----- JITDwarfEmitter.cpp - Write dwarf tables into memory -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a JITDwarfEmitter object that is used by the JIT to -// write dwarf tables to memory. -// -//===----------------------------------------------------------------------===// - -#include "JITDwarfEmitter.h" -#include "JIT.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/CodeGen/JITCodeEmitter.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/ExecutionEngine/JITMemoryManager.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Function.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MachineLocation.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Target/TargetFrameLowering.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegisterInfo.h" -using namespace llvm; - -JITDwarfEmitter::JITDwarfEmitter(JIT& theJit) : MMI(0), Jit(theJit) {} - - -unsigned char* JITDwarfEmitter::EmitDwarfTable(MachineFunction& F, - JITCodeEmitter& jce, - unsigned char* StartFunction, - unsigned char* EndFunction, - unsigned char* &EHFramePtr) { - assert(MMI && "MachineModuleInfo not registered!"); - - const TargetMachine& TM = F.getTarget(); - TD = TM.getDataLayout(); - stackGrowthDirection = TM.getFrameLowering()->getStackGrowthDirection(); - RI = TM.getRegisterInfo(); - MAI = TM.getMCAsmInfo(); - JCE = &jce; - - unsigned char* ExceptionTable = EmitExceptionTable(&F, StartFunction, - EndFunction); - - unsigned char* Result = 0; - - const std::vector<const Function *> Personalities = MMI->getPersonalities(); - EHFramePtr = EmitCommonEHFrame(Personalities[MMI->getPersonalityIndex()]); - - Result = EmitEHFrame(Personalities[MMI->getPersonalityIndex()], EHFramePtr, - StartFunction, EndFunction, ExceptionTable); - - return Result; -} - - -void -JITDwarfEmitter::EmitFrameMoves(intptr_t BaseLabelPtr, - const std::vector<MachineMove> &Moves) const { - unsigned PointerSize = TD->getPointerSize(); - int stackGrowth = stackGrowthDirection == TargetFrameLowering::StackGrowsUp ? - PointerSize : -PointerSize; - MCSymbol *BaseLabel = 0; - - for (unsigned i = 0, N = Moves.size(); i < N; ++i) { - const MachineMove &Move = Moves[i]; - MCSymbol *Label = Move.getLabel(); - - // Throw out move if the label is invalid. - if (Label && (*JCE->getLabelLocations())[Label] == 0) - continue; - - intptr_t LabelPtr = 0; - if (Label) LabelPtr = JCE->getLabelAddress(Label); - - const MachineLocation &Dst = Move.getDestination(); - const MachineLocation &Src = Move.getSource(); - - // Advance row if new location. - if (BaseLabelPtr && Label && BaseLabel != Label) { - JCE->emitByte(dwarf::DW_CFA_advance_loc4); - JCE->emitInt32(LabelPtr - BaseLabelPtr); - - BaseLabel = Label; - BaseLabelPtr = LabelPtr; - } - - // If advancing cfa. - if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { - if (!Src.isReg()) { - if (Src.getReg() == MachineLocation::VirtualFP) { - JCE->emitByte(dwarf::DW_CFA_def_cfa_offset); - } else { - JCE->emitByte(dwarf::DW_CFA_def_cfa); - JCE->emitULEB128Bytes(RI->getDwarfRegNum(Src.getReg(), true)); - } - - JCE->emitULEB128Bytes(-Src.getOffset()); - } else { - llvm_unreachable("Machine move not supported yet."); - } - } else if (Src.isReg() && - Src.getReg() == MachineLocation::VirtualFP) { - if (Dst.isReg()) { - JCE->emitByte(dwarf::DW_CFA_def_cfa_register); - JCE->emitULEB128Bytes(RI->getDwarfRegNum(Dst.getReg(), true)); - } else { - llvm_unreachable("Machine move not supported yet."); - } - } else { - unsigned Reg = RI->getDwarfRegNum(Src.getReg(), true); - int Offset = Dst.getOffset() / stackGrowth; - - if (Offset < 0) { - JCE->emitByte(dwarf::DW_CFA_offset_extended_sf); - JCE->emitULEB128Bytes(Reg); - JCE->emitSLEB128Bytes(Offset); - } else if (Reg < 64) { - JCE->emitByte(dwarf::DW_CFA_offset + Reg); - JCE->emitULEB128Bytes(Offset); - } else { - JCE->emitByte(dwarf::DW_CFA_offset_extended); - JCE->emitULEB128Bytes(Reg); - JCE->emitULEB128Bytes(Offset); - } - } - } -} - -/// SharedTypeIds - How many leading type ids two landing pads have in common. -static unsigned SharedTypeIds(const LandingPadInfo *L, - const LandingPadInfo *R) { - const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds; - unsigned LSize = LIds.size(), RSize = RIds.size(); - unsigned MinSize = LSize < RSize ? LSize : RSize; - unsigned Count = 0; - - for (; Count != MinSize; ++Count) - if (LIds[Count] != RIds[Count]) - return Count; - - return Count; -} - - -/// PadLT - Order landing pads lexicographically by type id. -static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R) { - const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds; - unsigned LSize = LIds.size(), RSize = RIds.size(); - unsigned MinSize = LSize < RSize ? LSize : RSize; - - for (unsigned i = 0; i != MinSize; ++i) - if (LIds[i] != RIds[i]) - return LIds[i] < RIds[i]; - - return LSize < RSize; -} - -namespace { - -/// ActionEntry - Structure describing an entry in the actions table. -struct ActionEntry { - int ValueForTypeID; // The value to write - may not be equal to the type id. - int NextAction; - struct ActionEntry *Previous; -}; - -/// PadRange - Structure holding a try-range and the associated landing pad. -struct PadRange { - // The index of the landing pad. - unsigned PadIndex; - // The index of the begin and end labels in the landing pad's label lists. - unsigned RangeIndex; -}; - -typedef DenseMap<MCSymbol*, PadRange> RangeMapType; - -/// CallSiteEntry - Structure describing an entry in the call-site table. -struct CallSiteEntry { - MCSymbol *BeginLabel; // zero indicates the start of the function. - MCSymbol *EndLabel; // zero indicates the end of the function. - MCSymbol *PadLabel; // zero indicates that there is no landing pad. - unsigned Action; -}; - -} - -unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF, - unsigned char* StartFunction, - unsigned char* EndFunction) const { - assert(MMI && "MachineModuleInfo not registered!"); - - // Map all labels and get rid of any dead landing pads. - MMI->TidyLandingPads(JCE->getLabelLocations()); - - const std::vector<const GlobalVariable *> &TypeInfos = MMI->getTypeInfos(); - const std::vector<unsigned> &FilterIds = MMI->getFilterIds(); - const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); - if (PadInfos.empty()) return 0; - - // Sort the landing pads in order of their type ids. This is used to fold - // duplicate actions. - SmallVector<const LandingPadInfo *, 64> LandingPads; - LandingPads.reserve(PadInfos.size()); - for (unsigned i = 0, N = PadInfos.size(); i != N; ++i) - LandingPads.push_back(&PadInfos[i]); - std::sort(LandingPads.begin(), LandingPads.end(), PadLT); - - // Negative type ids index into FilterIds, positive type ids index into - // TypeInfos. The value written for a positive type id is just the type - // id itself. For a negative type id, however, the value written is the - // (negative) byte offset of the corresponding FilterIds entry. The byte - // offset is usually equal to the type id, because the FilterIds entries - // are written using a variable width encoding which outputs one byte per - // entry as long as the value written is not too large, but can differ. - // This kind of complication does not occur for positive type ids because - // type infos are output using a fixed width encoding. - // FilterOffsets[i] holds the byte offset corresponding to FilterIds[i]. - SmallVector<int, 16> FilterOffsets; - FilterOffsets.reserve(FilterIds.size()); - int Offset = -1; - for(std::vector<unsigned>::const_iterator I = FilterIds.begin(), - E = FilterIds.end(); I != E; ++I) { - FilterOffsets.push_back(Offset); - Offset -= MCAsmInfo::getULEB128Size(*I); - } - - // Compute the actions table and gather the first action index for each - // landing pad site. - SmallVector<ActionEntry, 32> Actions; - SmallVector<unsigned, 64> FirstActions; - FirstActions.reserve(LandingPads.size()); - - int FirstAction = 0; - unsigned SizeActions = 0; - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LP = LandingPads[i]; - const std::vector<int> &TypeIds = LP->TypeIds; - const unsigned NumShared = i ? SharedTypeIds(LP, LandingPads[i-1]) : 0; - unsigned SizeSiteActions = 0; - - if (NumShared < TypeIds.size()) { - unsigned SizeAction = 0; - ActionEntry *PrevAction = 0; - - if (NumShared) { - const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size(); - assert(Actions.size()); - PrevAction = &Actions.back(); - SizeAction = MCAsmInfo::getSLEB128Size(PrevAction->NextAction) + - MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); - for (unsigned j = NumShared; j != SizePrevIds; ++j) { - SizeAction -= MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); - SizeAction += -PrevAction->NextAction; - PrevAction = PrevAction->Previous; - } - } - - // Compute the actions. - for (unsigned I = NumShared, M = TypeIds.size(); I != M; ++I) { - int TypeID = TypeIds[I]; - assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!"); - int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID; - unsigned SizeTypeID = MCAsmInfo::getSLEB128Size(ValueForTypeID); - - int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0; - SizeAction = SizeTypeID + MCAsmInfo::getSLEB128Size(NextAction); - SizeSiteActions += SizeAction; - - ActionEntry Action = {ValueForTypeID, NextAction, PrevAction}; - Actions.push_back(Action); - - PrevAction = &Actions.back(); - } - - // Record the first action of the landing pad site. - FirstAction = SizeActions + SizeSiteActions - SizeAction + 1; - } // else identical - re-use previous FirstAction - - FirstActions.push_back(FirstAction); - - // Compute this sites contribution to size. - SizeActions += SizeSiteActions; - } - - // Compute the call-site table. Entries must be ordered by address. - SmallVector<CallSiteEntry, 64> CallSites; - - RangeMapType PadMap; - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LandingPad = LandingPads[i]; - for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; - assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); - PadRange P = { i, j }; - PadMap[BeginLabel] = P; - } - } - - bool MayThrow = false; - MCSymbol *LastLabel = 0; - for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); - I != E; ++I) { - for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); - MI != E; ++MI) { - if (!MI->isLabel()) { - MayThrow |= MI->isCall(); - continue; - } - - MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol(); - assert(BeginLabel && "Invalid label!"); - - if (BeginLabel == LastLabel) - MayThrow = false; - - RangeMapType::iterator L = PadMap.find(BeginLabel); - - if (L == PadMap.end()) - continue; - - PadRange P = L->second; - const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; - - assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && - "Inconsistent landing pad map!"); - - // If some instruction between the previous try-range and this one may - // throw, create a call-site entry with no landing pad for the region - // between the try-ranges. - if (MayThrow) { - CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0}; - CallSites.push_back(Site); - } - - LastLabel = LandingPad->EndLabels[P.RangeIndex]; - CallSiteEntry Site = {BeginLabel, LastLabel, - LandingPad->LandingPadLabel, FirstActions[P.PadIndex]}; - - assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel && - "Invalid landing pad!"); - - // Try to merge with the previous call-site. - if (CallSites.size()) { - CallSiteEntry &Prev = CallSites.back(); - if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { - // Extend the range of the previous entry. - Prev.EndLabel = Site.EndLabel; - continue; - } - } - - // Otherwise, create a new call-site. - CallSites.push_back(Site); - } - } - // If some instruction between the previous try-range and the end of the - // function may throw, create a call-site entry with no landing pad for the - // region following the try-range. - if (MayThrow) { - CallSiteEntry Site = {LastLabel, 0, 0, 0}; - CallSites.push_back(Site); - } - - // Final tallies. - unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start. - sizeof(int32_t) + // Site length. - sizeof(int32_t)); // Landing pad. - for (unsigned i = 0, e = CallSites.size(); i < e; ++i) - SizeSites += MCAsmInfo::getULEB128Size(CallSites[i].Action); - - unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize(); - - unsigned TypeOffset = sizeof(int8_t) + // Call site format - // Call-site table length - MCAsmInfo::getULEB128Size(SizeSites) + - SizeSites + SizeActions + SizeTypes; - - // Begin the exception table. - JCE->emitAlignmentWithFill(4, 0); - // Asm->EOL("Padding"); - - unsigned char* DwarfExceptionTable = (unsigned char*)JCE->getCurrentPCValue(); - - // Emit the header. - JCE->emitByte(dwarf::DW_EH_PE_omit); - // Asm->EOL("LPStart format (DW_EH_PE_omit)"); - JCE->emitByte(dwarf::DW_EH_PE_absptr); - // Asm->EOL("TType format (DW_EH_PE_absptr)"); - JCE->emitULEB128Bytes(TypeOffset); - // Asm->EOL("TType base offset"); - JCE->emitByte(dwarf::DW_EH_PE_udata4); - // Asm->EOL("Call site format (DW_EH_PE_udata4)"); - JCE->emitULEB128Bytes(SizeSites); - // Asm->EOL("Call-site table length"); - - // Emit the landing pad site information. - for (unsigned i = 0; i < CallSites.size(); ++i) { - CallSiteEntry &S = CallSites[i]; - intptr_t BeginLabelPtr = 0; - intptr_t EndLabelPtr = 0; - - if (!S.BeginLabel) { - BeginLabelPtr = (intptr_t)StartFunction; - JCE->emitInt32(0); - } else { - BeginLabelPtr = JCE->getLabelAddress(S.BeginLabel); - JCE->emitInt32(BeginLabelPtr - (intptr_t)StartFunction); - } - - // Asm->EOL("Region start"); - - if (!S.EndLabel) - EndLabelPtr = (intptr_t)EndFunction; - else - EndLabelPtr = JCE->getLabelAddress(S.EndLabel); - - JCE->emitInt32(EndLabelPtr - BeginLabelPtr); - //Asm->EOL("Region length"); - - if (!S.PadLabel) { - JCE->emitInt32(0); - } else { - unsigned PadLabelPtr = JCE->getLabelAddress(S.PadLabel); - JCE->emitInt32(PadLabelPtr - (intptr_t)StartFunction); - } - // Asm->EOL("Landing pad"); - - JCE->emitULEB128Bytes(S.Action); - // Asm->EOL("Action"); - } - - // Emit the actions. - for (unsigned I = 0, N = Actions.size(); I != N; ++I) { - ActionEntry &Action = Actions[I]; - - JCE->emitSLEB128Bytes(Action.ValueForTypeID); - //Asm->EOL("TypeInfo index"); - JCE->emitSLEB128Bytes(Action.NextAction); - //Asm->EOL("Next action"); - } - - // Emit the type ids. - for (unsigned M = TypeInfos.size(); M; --M) { - const GlobalVariable *GV = TypeInfos[M - 1]; - - if (GV) { - if (TD->getPointerSize() == sizeof(int32_t)) - JCE->emitInt32((intptr_t)Jit.getOrEmitGlobalVariable(GV)); - else - JCE->emitInt64((intptr_t)Jit.getOrEmitGlobalVariable(GV)); - } else { - if (TD->getPointerSize() == sizeof(int32_t)) - JCE->emitInt32(0); - else - JCE->emitInt64(0); - } - // Asm->EOL("TypeInfo"); - } - - // Emit the filter typeids. - for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) { - unsigned TypeID = FilterIds[j]; - JCE->emitULEB128Bytes(TypeID); - //Asm->EOL("Filter TypeInfo index"); - } - - JCE->emitAlignmentWithFill(4, 0); - - return DwarfExceptionTable; -} - -unsigned char* -JITDwarfEmitter::EmitCommonEHFrame(const Function* Personality) const { - unsigned PointerSize = TD->getPointerSize(); - int stackGrowth = stackGrowthDirection == TargetFrameLowering::StackGrowsUp ? - PointerSize : -PointerSize; - - unsigned char* StartCommonPtr = (unsigned char*)JCE->getCurrentPCValue(); - // EH Common Frame header - JCE->allocateSpace(4, 0); - unsigned char* FrameCommonBeginPtr = (unsigned char*)JCE->getCurrentPCValue(); - JCE->emitInt32((int)0); - JCE->emitByte(dwarf::DW_CIE_VERSION); - JCE->emitString(Personality ? "zPLR" : "zR"); - JCE->emitULEB128Bytes(1); - JCE->emitSLEB128Bytes(stackGrowth); - JCE->emitByte(RI->getDwarfRegNum(RI->getRARegister(), true)); - - if (Personality) { - // Augmentation Size: 3 small ULEBs of one byte each, and the personality - // function which size is PointerSize. - JCE->emitULEB128Bytes(3 + PointerSize); - - // We set the encoding of the personality as direct encoding because we use - // the function pointer. The encoding is not relative because the current - // PC value may be bigger than the personality function pointer. - if (PointerSize == 4) { - JCE->emitByte(dwarf::DW_EH_PE_sdata4); - JCE->emitInt32(((intptr_t)Jit.getPointerToGlobal(Personality))); - } else { - JCE->emitByte(dwarf::DW_EH_PE_sdata8); - JCE->emitInt64(((intptr_t)Jit.getPointerToGlobal(Personality))); - } - - // LSDA encoding: This must match the encoding used in EmitEHFrame () - if (PointerSize == 4) - JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); - else - JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8); - JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); - } else { - JCE->emitULEB128Bytes(1); - JCE->emitULEB128Bytes(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); - } - - EmitFrameMoves(0, MAI->getInitialFrameState()); - - JCE->emitAlignmentWithFill(PointerSize, dwarf::DW_CFA_nop); - - JCE->emitInt32At((uintptr_t*)StartCommonPtr, - (uintptr_t)((unsigned char*)JCE->getCurrentPCValue() - - FrameCommonBeginPtr)); - - return StartCommonPtr; -} - - -unsigned char* -JITDwarfEmitter::EmitEHFrame(const Function* Personality, - unsigned char* StartCommonPtr, - unsigned char* StartFunction, - unsigned char* EndFunction, - unsigned char* ExceptionTable) const { - unsigned PointerSize = TD->getPointerSize(); - - // EH frame header. - unsigned char* StartEHPtr = (unsigned char*)JCE->getCurrentPCValue(); - JCE->allocateSpace(4, 0); - unsigned char* FrameBeginPtr = (unsigned char*)JCE->getCurrentPCValue(); - // FDE CIE Offset - JCE->emitInt32(FrameBeginPtr - StartCommonPtr); - JCE->emitInt32(StartFunction - (unsigned char*)JCE->getCurrentPCValue()); - JCE->emitInt32(EndFunction - StartFunction); - - // If there is a personality and landing pads then point to the language - // specific data area in the exception table. - if (Personality) { - JCE->emitULEB128Bytes(PointerSize == 4 ? 4 : 8); - - if (PointerSize == 4) { - if (!MMI->getLandingPads().empty()) - JCE->emitInt32(ExceptionTable-(unsigned char*)JCE->getCurrentPCValue()); - else - JCE->emitInt32((int)0); - } else { - if (!MMI->getLandingPads().empty()) - JCE->emitInt64(ExceptionTable-(unsigned char*)JCE->getCurrentPCValue()); - else - JCE->emitInt64((int)0); - } - } else { - JCE->emitULEB128Bytes(0); - } - - // Indicate locations of function specific callee saved registers in - // frame. - EmitFrameMoves((intptr_t)StartFunction, MMI->getFrameMoves()); - - JCE->emitAlignmentWithFill(PointerSize, dwarf::DW_CFA_nop); - - // Indicate the size of the table - JCE->emitInt32At((uintptr_t*)StartEHPtr, - (uintptr_t)((unsigned char*)JCE->getCurrentPCValue() - - StartEHPtr)); - - // Double zeroes for the unwind runtime - if (PointerSize == 8) { - JCE->emitInt64(0); - JCE->emitInt64(0); - } else { - JCE->emitInt32(0); - JCE->emitInt32(0); - } - - return StartEHPtr; -} diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h deleted file mode 100644 index 98ac340..0000000 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h +++ /dev/null @@ -1,77 +0,0 @@ -//===------ JITDwarfEmitter.h - Write dwarf tables into memory ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a JITDwarfEmitter object that is used by the JIT to -// write dwarf tables to memory. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTION_ENGINE_JIT_DWARFEMITTER_H -#define LLVM_EXECUTION_ENGINE_JIT_DWARFEMITTER_H - -#include "llvm/Support/DataTypes.h" -#include <vector> - -namespace llvm { - -class Function; -class JIT; -class JITCodeEmitter; -class MachineFunction; -class MachineModuleInfo; -class MachineMove; -class MCAsmInfo; -class DataLayout; -class TargetMachine; -class TargetRegisterInfo; - -class JITDwarfEmitter { - const DataLayout* TD; - JITCodeEmitter* JCE; - const TargetRegisterInfo* RI; - const MCAsmInfo *MAI; - MachineModuleInfo* MMI; - JIT& Jit; - bool stackGrowthDirection; - - unsigned char* EmitExceptionTable(MachineFunction* MF, - unsigned char* StartFunction, - unsigned char* EndFunction) const; - - void EmitFrameMoves(intptr_t BaseLabelPtr, - const std::vector<MachineMove> &Moves) const; - - unsigned char* EmitCommonEHFrame(const Function* Personality) const; - - unsigned char* EmitEHFrame(const Function* Personality, - unsigned char* StartBufferPtr, - unsigned char* StartFunction, - unsigned char* EndFunction, - unsigned char* ExceptionTable) const; - -public: - - JITDwarfEmitter(JIT& jit); - - unsigned char* EmitDwarfTable(MachineFunction& F, - JITCodeEmitter& JCE, - unsigned char* StartFunction, - unsigned char* EndFunction, - unsigned char* &EHFramePtr); - - - void setModuleInfo(MachineModuleInfo* Info) { - MMI = Info; - } -}; - - -} // end namespace llvm - -#endif // LLVM_EXECUTION_ENGINE_JIT_DWARFEMITTER_H diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index c273876..acbbfa1 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -14,7 +14,6 @@ #define DEBUG_TYPE "jit" #include "JIT.h" -#include "JITDwarfEmitter.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" @@ -325,9 +324,6 @@ namespace { /// Resolver - This contains info about the currently resolved functions. JITResolver Resolver; - /// DE - The dwarf emitter for the jit. - OwningPtr<JITDwarfEmitter> DE; - /// LabelLocations - This vector is a mapping from Label ID's to their /// address. DenseMap<MCSymbol*, uintptr_t> LabelLocations; @@ -363,22 +359,16 @@ namespace { /// Instance of the JIT JIT *TheJIT; - bool JITExceptionHandling; - public: JITEmitter(JIT &jit, JITMemoryManager *JMM, TargetMachine &TM) : SizeEstimate(0), Resolver(jit, *this), MMI(0), CurFn(0), - EmittedFunctions(this), TheJIT(&jit), - JITExceptionHandling(TM.Options.JITExceptionHandling) { + EmittedFunctions(this), TheJIT(&jit) { MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager(); if (jit.getJITInfo().needsGOT()) { MemMgr->AllocateGOT(); DEBUG(dbgs() << "JIT is managing a GOT\n"); } - if (JITExceptionHandling) { - DE.reset(new JITDwarfEmitter(jit)); - } } ~JITEmitter() { delete MemMgr; @@ -460,7 +450,6 @@ namespace { virtual void setModuleInfo(MachineModuleInfo* Info) { MMI = Info; - if (DE.get()) DE->setModuleInfo(Info); } private: @@ -964,40 +953,6 @@ bool JITEmitter::finishFunction(MachineFunction &F) { } }); - if (JITExceptionHandling) { - uintptr_t ActualSize = 0; - SavedBufferBegin = BufferBegin; - SavedBufferEnd = BufferEnd; - SavedCurBufferPtr = CurBufferPtr; - uint8_t *FrameRegister; - - while (true) { - BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(), - ActualSize); - BufferEnd = BufferBegin+ActualSize; - EmittedFunctions[F.getFunction()].ExceptionTable = BufferBegin; - uint8_t *EhStart; - FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd, EhStart); - - // If the buffer was large enough to hold the table then we are done. - if (CurBufferPtr != BufferEnd) - break; - - // Try again with twice as much space. - ActualSize = (CurBufferPtr - BufferBegin) * 2; - MemMgr->deallocateExceptionTable(BufferBegin); - } - MemMgr->endExceptionTable(F.getFunction(), BufferBegin, CurBufferPtr, - FrameRegister); - BufferBegin = SavedBufferBegin; - BufferEnd = SavedBufferEnd; - CurBufferPtr = SavedCurBufferPtr; - - if (JITExceptionHandling) { - TheJIT->RegisterTable(F.getFunction(), FrameRegister); - } - } - if (MMI) MMI->EndFunction(); @@ -1027,15 +982,10 @@ void JITEmitter::deallocateMemForFunction(const Function *F) { Emitted = EmittedFunctions.find(F); if (Emitted != EmittedFunctions.end()) { MemMgr->deallocateFunctionBody(Emitted->second.FunctionBody); - MemMgr->deallocateExceptionTable(Emitted->second.ExceptionTable); TheJIT->NotifyFreeingMachineCode(Emitted->second.Code); EmittedFunctions.erase(Emitted); } - - if (JITExceptionHandling) { - TheJIT->DeregisterTable(F); - } } diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index 66aeb77..6a1db16 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -509,30 +509,10 @@ namespace { return (uint8_t*)DataAllocator.Allocate(Size, Alignment); } - bool applyPermissions(std::string *ErrMsg) { + bool finalizeMemory(std::string *ErrMsg) { return false; } - /// startExceptionTable - Use startFunctionBody to allocate memory for the - /// function's exception table. - uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) { - return startFunctionBody(F, ActualSize); - } - - /// endExceptionTable - The exception table of F is now allocated, - /// and takes the memory in the range [TableStart,TableEnd). - void endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) { - assert(TableEnd > TableStart); - assert(TableStart == (uint8_t *)(CurBlock+1) && - "Mismatched table start/end!"); - - uintptr_t BlockSize = TableEnd - (uint8_t *)CurBlock; - - // Release the memory at the end of this block that isn't needed. - FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize); - } - uint8_t *getGOTBase() const { return GOTBase; } @@ -557,12 +537,6 @@ namespace { if (Body) deallocateBlock(Body); } - /// deallocateExceptionTable - Deallocate memory for the specified - /// exception table. - void deallocateExceptionTable(void *ET) { - if (ET) deallocateBlock(ET); - } - /// setMemoryWritable - When code generation is in progress, /// the code pages may need permissions changed. void setMemoryWritable() diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp index ccaa72a..e861938 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -39,7 +39,7 @@ extern "C" void LLVMLinkInMCJIT() { ExecutionEngine *MCJIT::createJIT(Module *M, std::string *ErrorStr, - JITMemoryManager *JMM, + RTDyldMemoryManager *MemMgr, bool GVsWithCode, TargetMachine *TM) { // Try to register the program as a source of symbols to resolve against. @@ -47,14 +47,14 @@ ExecutionEngine *MCJIT::createJIT(Module *M, // FIXME: Don't do this here. sys::DynamicLibrary::LoadLibraryPermanently(0, NULL); - return new MCJIT(M, TM, JMM ? JMM : new SectionMemoryManager(), GVsWithCode); + return new MCJIT(M, TM, MemMgr ? MemMgr : new SectionMemoryManager(), + GVsWithCode); } MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM, bool AllocateGVsWithCode) - : ExecutionEngine(m), TM(tm), Ctx(0), - MemMgr(MM ? MM : new SectionMemoryManager()), Dyld(MemMgr), - IsLoaded(false), M(m), ObjCache(0) { + : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM), + IsLoaded(false), M(m), ObjCache(0) { setDataLayout(TM->getDataLayout()); } @@ -168,18 +168,17 @@ void MCJIT::finalizeObject() { // If the call to Dyld.resolveRelocations() is removed from loadObject() // we'll need to do that here. loadObject(M); - - // Set page permissions. - MemMgr->applyPermissions(); - - return; + } else { + // Resolve any relocations. + Dyld.resolveRelocations(); } - // Resolve any relocations. - Dyld.resolveRelocations(); + StringRef EHData = Dyld.getEHFrameSection(); + if (!EHData.empty()) + MemMgr->registerEHFrames(EHData); // Set page permissions. - MemMgr->applyPermissions(); + MemMgr->finalizeMemory(); } void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) { diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h index 8c4bf6e..a899d4f 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -52,6 +52,13 @@ public: /// Sets the object manager that MCJIT should use to avoid compilation. virtual void setObjectCache(ObjectCache *manager); + /// finalizeObject - ensure the module is fully processed and is usable. + /// + /// It is the user-level function for completing the process of making the + /// object usable for execution. It should be called after sections within an + /// object have been relocated using mapSectionAddress. When this method is + /// called the MCJIT execution engine will reapply relocations for a loaded + /// object. virtual void finalizeObject(); virtual void *getPointerToBasicBlock(BasicBlock *BB); @@ -98,7 +105,7 @@ public: static ExecutionEngine *createJIT(Module *M, std::string *ErrorStr, - JITMemoryManager *JMM, + RTDyldMemoryManager *MemMgr, bool GVsWithCode, TargetMachine *TM); diff --git a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp index da93124..650832e 100644 --- a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp +++ b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp @@ -14,19 +14,8 @@ #include "llvm/Config/config.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/MathExtras.h" -#ifdef __linux__ - // These includes used by SectionMemoryManager::getPointerToNamedFunction() - // for Glibc trickery. See comments in this function for more information. - #ifdef HAVE_SYS_STAT_H - #include <sys/stat.h> - #endif - #include <fcntl.h> - #include <unistd.h> -#endif - namespace llvm { uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, @@ -111,7 +100,7 @@ uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, return (uint8_t*)Addr; } -bool SectionMemoryManager::applyPermissions(std::string *ErrMsg) +bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) { // FIXME: Should in-progress permissions be reverted if an error occurs? error_code ec; @@ -167,57 +156,6 @@ void SectionMemoryManager::invalidateInstructionCache() { CodeMem.AllocatedMem[i].size()); } -static int jit_noop() { - return 0; -} - -void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure) { -#if defined(__linux__) - //===--------------------------------------------------------------------===// - // Function stubs that are invoked instead of certain library calls - // - // Force the following functions to be linked in to anything that uses the - // JIT. This is a hack designed to work around the all-too-clever Glibc - // strategy of making these functions work differently when inlined vs. when - // 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__ - - // We should not invoke parent's ctors/dtors from generated main()! - // On Mingw and Cygwin, the symbol __main is resolved to - // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors - // (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; - - const char *NameStr = Name.c_str(); - void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr); - if (Ptr) return 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 (AbortOnFailure) - report_fatal_error("Program used external function '" + Name + - "' which could not be resolved!"); - return 0; -} - SectionMemoryManager::~SectionMemoryManager() { for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); diff --git a/lib/ExecutionEngine/RTDyldMemoryManager.cpp b/lib/ExecutionEngine/RTDyldMemoryManager.cpp new file mode 100644 index 0000000..4e76457 --- /dev/null +++ b/lib/ExecutionEngine/RTDyldMemoryManager.cpp @@ -0,0 +1,118 @@ +//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the runtime dynamic memory manager base class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/ErrorHandling.h" + +#include <cstdlib> + +#ifdef __linux__ + // These includes used by RTDyldMemoryManager::getPointerToNamedFunction() + // for Glibc trickery. See comments in this function for more information. + #ifdef HAVE_SYS_STAT_H + #include <sys/stat.h> + #endif + #include <fcntl.h> + #include <unistd.h> +#endif + +namespace llvm { + +RTDyldMemoryManager::~RTDyldMemoryManager() {} + +// 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 +extern "C" void __register_frame(void*); + +static const char *processFDE(const char *Entry) { + 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)); + 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(); + do { + P = processFDE(P); + } while(P != End); +#endif +} + +static int jit_noop() { + return 0; +} + +void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure) { +#if defined(__linux__) + //===--------------------------------------------------------------------===// + // Function stubs that are invoked instead of certain library calls + // + // Force the following functions to be linked in to anything that uses the + // JIT. This is a hack designed to work around the all-too-clever Glibc + // strategy of making these functions work differently when inlined vs. when + // 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__ + + // We should not invoke parent's ctors/dtors from generated main()! + // On Mingw and Cygwin, the symbol __main is resolved to + // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors + // (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; + + const char *NameStr = Name.c_str(); + void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr); + if (Ptr) return 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 (AbortOnFailure) + report_fatal_error("Program used external function '" + Name + + "' which could not be resolved!"); + return 0; +} + +} // namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 7b32db7..f0bd4e3 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -17,18 +17,22 @@ #include "RuntimeDyldELF.h" #include "RuntimeDyldImpl.h" #include "RuntimeDyldMachO.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/Path.h" +#include "llvm/Object/ELF.h" using namespace llvm; using namespace llvm::object; // Empty out-of-line virtual destructor as the key function. -RTDyldMemoryManager::~RTDyldMemoryManager() {} RuntimeDyldImpl::~RuntimeDyldImpl() {} namespace llvm { +StringRef RuntimeDyldImpl::getEHFrameSection() { + return StringRef(); +} + // Resolve the relocations for all symbols we currently know about. void RuntimeDyldImpl::resolveRelocations() { // First, resolve relocations associated with external symbols. @@ -143,6 +147,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) { bool isFirstRelocation = true; unsigned SectionID = 0; StubMap Stubs; + section_iterator RelocatedSection = si->getRelocatedSection(); for (relocation_iterator i = si->begin_relocations(), e = si->end_relocations(); i != e; i.increment(err)) { @@ -150,7 +155,8 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) { // If it's the first relocation in this section, find its SectionID if (isFirstRelocation) { - SectionID = findOrEmitSection(*obj, *si, true, LocalSections); + SectionID = + findOrEmitSection(*obj, *RelocatedSection, true, LocalSections); DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); isFirstRelocation = false; } @@ -174,7 +180,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, if (!Addr) report_fatal_error("Unable to allocate memory for common symbols!"); uint64_t Offset = 0; - Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, TotalSize, 0)); + Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, 0)); memset(Addr, 0, TotalSize); DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID @@ -211,11 +217,25 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, unsigned StubBufSize = 0, StubSize = getMaxStubSize(); error_code err; + const ObjectFile *ObjFile = Obj.getObjectFile(); + // FIXME: this is an inefficient way to handle this. We should computed the + // necessary section allocation size in loadObject by walking all the sections + // once. if (StubSize > 0) { - for (relocation_iterator i = Section.begin_relocations(), - e = Section.end_relocations(); i != e; i.increment(err), Check(err)) - StubBufSize += StubSize; + for (section_iterator SI = ObjFile->begin_sections(), + SE = ObjFile->end_sections(); + SI != SE; SI.increment(err), Check(err)) { + section_iterator RelSecI = SI->getRelocatedSection(); + if (!(RelSecI == Section)) + continue; + + for (relocation_iterator I = SI->begin_relocations(), + E = SI->end_relocations(); I != E; I.increment(err), Check(err)) { + StubBufSize += StubSize; + } + } } + StringRef data; uint64_t Alignment64; Check(Section.getContents(data)); @@ -234,6 +254,12 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, Check(Section.isReadOnlyData(IsReadOnly)); Check(Section.getSize(DataSize)); Check(Section.getName(Name)); + if (StubSize > 0) { + unsigned StubAlignment = getStubAlignment(); + unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); + if (StubAlignment > EndAlignment) + StubBufSize += StubAlignment - EndAlignment; + } unsigned Allocate; unsigned SectionID = Sections.size(); @@ -286,8 +312,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, << "\n"); } - Sections.push_back(SectionEntry(Name, Addr, Allocate, DataSize, - (uintptr_t)pData)); + Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData)); return SectionID; } @@ -330,7 +355,25 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, } uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { - if (Arch == Triple::arm) { + if (Arch == Triple::aarch64) { + // This stub has to be able to access the full address space, + // since symbol lookup won't necessarily find a handy, in-range, + // PLT stub for functions which could be anywhere. + uint32_t *StubAddr = (uint32_t*)Addr; + + // Stub can use ip0 (== x16) to calculate address + *StubAddr = 0xd2e00010; // movz ip0, #:abs_g3:<addr> + StubAddr++; + *StubAddr = 0xf2c00010; // movk ip0, #:abs_g2_nc:<addr> + StubAddr++; + *StubAddr = 0xf2a00010; // movk ip0, #:abs_g1_nc:<addr> + StubAddr++; + *StubAddr = 0xf2800010; // movk ip0, #:abs_g0_nc:<addr> + StubAddr++; + *StubAddr = 0xd61f0200; // br ip0 + + return Addr; + } else if (Arch == Triple::arm) { // TODO: There is only ARM far stub now. We should add the Thumb stub, // and stubs for branches Thumb - ARM and ARM - Thumb. uint32_t *StubAddr = (uint32_t*)Addr; @@ -371,6 +414,13 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { writeInt32BE(Addr+40, 0x4E800420); // bctr return Addr; + } else if (Arch == Triple::systemz) { + writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8 + writeInt16BE(Addr+2, 0x0000); + writeInt16BE(Addr+4, 0x0004); + writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1 + // 8-byte address stored at Addr + 8 + return Addr; } return Addr; } @@ -451,33 +501,33 @@ RuntimeDyld::~RuntimeDyld() { ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { if (!Dyld) { - sys::LLVMFileType type = sys::IdentifyFileType( - InputBuffer->getBufferStart(), - static_cast<unsigned>(InputBuffer->getBufferSize())); - switch (type) { - case sys::ELF_Relocatable_FileType: - case sys::ELF_Executable_FileType: - case sys::ELF_SharedObject_FileType: - case sys::ELF_Core_FileType: - Dyld = new RuntimeDyldELF(MM); - break; - case sys::Mach_O_Object_FileType: - case sys::Mach_O_Executable_FileType: - case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: - case sys::Mach_O_Core_FileType: - case sys::Mach_O_PreloadExecutable_FileType: - case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: - case sys::Mach_O_DynamicLinker_FileType: - case sys::Mach_O_Bundle_FileType: - case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: - case sys::Mach_O_DSYMCompanion_FileType: - Dyld = new RuntimeDyldMachO(MM); - break; - case sys::Unknown_FileType: - case sys::Bitcode_FileType: - case sys::Archive_FileType: - case sys::COFF_FileType: - report_fatal_error("Incompatible object format!"); + sys::fs::file_magic Type = + sys::fs::identify_magic(InputBuffer->getBuffer()); + switch (Type) { + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::elf_executable: + case sys::fs::file_magic::elf_shared_object: + case sys::fs::file_magic::elf_core: + Dyld = new RuntimeDyldELF(MM); + break; + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::macho_executable: + case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: + case sys::fs::file_magic::macho_core: + case sys::fs::file_magic::macho_preload_executable: + case sys::fs::file_magic::macho_dynamically_linked_shared_lib: + case sys::fs::file_magic::macho_dynamic_linker: + case sys::fs::file_magic::macho_bundle: + case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: + case sys::fs::file_magic::macho_dsym_companion: + Dyld = new RuntimeDyldMachO(MM); + break; + case sys::fs::file_magic::unknown: + case sys::fs::file_magic::bitcode: + case sys::fs::file_magic::archive: + case sys::fs::file_magic::coff_object: + case sys::fs::file_magic::pecoff_executable: + report_fatal_error("Incompatible object format!"); } } else { if (!Dyld->isCompatibleFormat(InputBuffer)) @@ -513,4 +563,8 @@ StringRef RuntimeDyld::getErrorString() { return Dyld->getErrorString(); } +StringRef RuntimeDyld::getEHFrameSection() { + return Dyld->getEHFrameSection(); +} + } // end namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index c5bad8e..722ed10 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -151,6 +151,14 @@ 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); + } + return StringRef(); +} + ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { if (Buffer->getBufferSize() < ELF::EI_NIDENT) llvm_unreachable("Unexpected ELF object size"); @@ -269,12 +277,114 @@ void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, } } +void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, + uint32_t Type, + int64_t Addend) { + uint32_t *TargetPtr = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; + + DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" + << format("%llx", Section.Address + Offset) + << " FinalAddress: 0x" << format("%llx",FinalAddress) + << " Value: 0x" << format("%llx",Value) + << " Type: 0x" << format("%x",Type) + << " Addend: 0x" << format("%llx",Addend) + << "\n"); + + switch (Type) { + default: + llvm_unreachable("Relocation type not implemented yet!"); + break; + case ELF::R_AARCH64_ABS64: { + uint64_t *TargetPtr = reinterpret_cast<uint64_t*>(Section.Address + Offset); + *TargetPtr = Value + Addend; + break; + } + case ELF::R_AARCH64_PREL32: { + uint64_t Result = Value + Addend - FinalAddress; + assert(static_cast<int64_t>(Result) >= INT32_MIN && + static_cast<int64_t>(Result) <= UINT32_MAX); + *TargetPtr = static_cast<uint32_t>(Result & 0xffffffffU); + break; + } + case ELF::R_AARCH64_CALL26: // fallthrough + case ELF::R_AARCH64_JUMP26: { + // Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the + // calculation. + uint64_t BranchImm = Value + Addend - FinalAddress; + + // "Check that -2^27 <= result < 2^27". + 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 + // bits affected by the relocation on entry is garbage. + *TargetPtr &= 0xfc000000U; + // Immediate goes in bits 25:0 of B and BL. + *TargetPtr |= static_cast<uint32_t>(BranchImm & 0xffffffcU) >> 2; + break; + } + case ELF::R_AARCH64_MOVW_UABS_G3: { + 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 &= 0xff80001fU; + // Immediate goes in bits 20:5 of MOVZ/MOVK instruction + *TargetPtr |= Result >> (48 - 5); + // Shift is "lsl #48", in bits 22:21 + *TargetPtr |= 3 << 21; + break; + } + 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 &= 0xff80001fU; + // Immediate goes in bits 20:5 of MOVZ/MOVK instruction + *TargetPtr |= ((Result & 0xffff00000000ULL) >> (32 - 5)); + // Shift is "lsl #32", in bits 22:21 + *TargetPtr |= 2 << 21; + break; + } + case ELF::R_AARCH64_MOVW_UABS_G1_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 &= 0xff80001fU; + // Immediate goes in bits 20:5 of MOVZ/MOVK instruction + *TargetPtr |= ((Result & 0xffff0000U) >> (16 - 5)); + // Shift is "lsl #16", in bits 22:21 + *TargetPtr |= 1 << 21; + break; + } + case ELF::R_AARCH64_MOVW_UABS_G0_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 &= 0xff80001fU; + // Immediate goes in bits 20:5 of MOVZ/MOVK instruction + *TargetPtr |= ((Result & 0xffffU) << 5); + // Shift is "lsl #0", in bits 22:21. No action needed. + break; + } + } +} + void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend) { // TODO: Add Thumb relocations. + uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress + + Offset); uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); Value += Addend; @@ -293,44 +403,51 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, // Write a 32bit value to relocation address, taking into account the // implicit addend encoded in the target. - case ELF::R_ARM_TARGET1 : - case ELF::R_ARM_ABS32 : - *TargetPtr += Value; + case ELF::R_ARM_TARGET1: + case ELF::R_ARM_ABS32: + *TargetPtr = *Placeholder + Value; break; - // Write first 16 bit of 32 bit value to the mov instruction. // Last 4 bit should be shifted. - case ELF::R_ARM_MOVW_ABS_NC : + case ELF::R_ARM_MOVW_ABS_NC: // We are not expecting any other addend in the relocation address. // Using 0x000F0FFF because MOVW has its 16 bit immediate split into 2 // non-contiguous fields. - assert((*TargetPtr & 0x000F0FFF) == 0); + assert((*Placeholder & 0x000F0FFF) == 0); Value = Value & 0xFFFF; - *TargetPtr |= Value & 0xFFF; + *TargetPtr = *Placeholder | (Value & 0xFFF); *TargetPtr |= ((Value >> 12) & 0xF) << 16; break; - // Write last 16 bit of 32 bit value to the mov instruction. // Last 4 bit should be shifted. - case ELF::R_ARM_MOVT_ABS : + case ELF::R_ARM_MOVT_ABS: // We are not expecting any other addend in the relocation address. // Use 0x000F0FFF for the same reason as R_ARM_MOVW_ABS_NC. - assert((*TargetPtr & 0x000F0FFF) == 0); + assert((*Placeholder & 0x000F0FFF) == 0); + Value = (Value >> 16) & 0xFFFF; - *TargetPtr |= Value & 0xFFF; + *TargetPtr = *Placeholder | (Value & 0xFFF); *TargetPtr |= ((Value >> 12) & 0xF) << 16; break; - // Write 24 bit relative value to the branch instruction. case ELF::R_ARM_PC24 : // Fall through. case ELF::R_ARM_CALL : // Fall through. - case ELF::R_ARM_JUMP24 : + case ELF::R_ARM_JUMP24: { int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); RelValue = (RelValue & 0x03FFFFFC) >> 2; + assert((*TargetPtr & 0xFFFFFF) == 0xFFFFFE); *TargetPtr &= 0xFF000000; *TargetPtr |= RelValue; break; } + case ELF::R_ARM_PRIVATE_0: + // This relocation is reserved by the ARM ELF ABI for internal use. We + // appropriate it here to act as an R_ARM_ABS32 without any addend for use + // in the stubs created during JIT (which can't put an addend into the + // original object file). + *TargetPtr = Value; + break; + } } void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, @@ -412,9 +529,13 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, error_code err; for (section_iterator si = Obj.begin_sections(), se = Obj.end_sections(); si != se; si.increment(err)) { - StringRef SectionName; - check(si->getName(SectionName)); - if (SectionName != ".opd") + section_iterator RelSecI = si->getRelocatedSection(); + if (RelSecI == Obj.end_sections()) + continue; + + StringRef RelSectionName; + check(RelSecI->getName(RelSectionName)); + if (RelSectionName != ".opd") continue; for (relocation_iterator i = si->begin_relocations(), @@ -430,12 +551,11 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, continue; } - SymbolRef TargetSymbol; uint64_t TargetSymbolOffset; - int64_t TargetAdditionalInfo; - check(i->getSymbol(TargetSymbol)); + symbol_iterator TargetSymbol = i->getSymbol(); check(i->getOffset(TargetSymbolOffset)); - check(i->getAdditionalInfo(TargetAdditionalInfo)); + int64_t Addend; + check(getELFRelocationAddend(*i, Addend)); i = i.increment(err); if (i == e) @@ -455,9 +575,9 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, continue; section_iterator tsi(Obj.end_sections()); - check(TargetSymbol.getSection(tsi)); + check(TargetSymbol->getSection(tsi)); Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections); - Rel.Addend = (intptr_t)TargetAdditionalInfo; + Rel.Addend = (intptr_t)Addend; return; } } @@ -541,6 +661,11 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, llvm_unreachable("Relocation R_PPC64_REL32 overflow"); writeInt32BE(LocalAddress, delta); } break; + case ELF::R_PPC64_REL64: { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt64BE(LocalAddress, Delta); + } break; case ELF::R_PPC64_ADDR64 : writeInt64BE(LocalAddress, Value + Addend); break; @@ -560,6 +685,42 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, } } +void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, + uint32_t Type, + int64_t Addend) { + uint8_t *LocalAddress = Section.Address + Offset; + switch (Type) { + default: + llvm_unreachable("Relocation type not implemented yet!"); + break; + case ELF::R_390_PC16DBL: + case ELF::R_390_PLT16DBL: { + int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset); + assert(int16_t(Delta / 2) * 2 == Delta && "R_390_PC16DBL overflow"); + writeInt16BE(LocalAddress, Delta / 2); + break; + } + case ELF::R_390_PC32DBL: + case ELF::R_390_PLT32DBL: { + int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset); + assert(int32_t(Delta / 2) * 2 == Delta && "R_390_PC32DBL overflow"); + writeInt32BE(LocalAddress, Delta / 2); + break; + } + case ELF::R_390_PC32: { + int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset); + assert(int32_t(Delta) == Delta && "R_390_PC32 overflow"); + writeInt32BE(LocalAddress, Delta); + break; + } + case ELF::R_390_64: + writeInt64BE(LocalAddress, Value + Addend); + break; + } +} + void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, uint64_t Value) { const SectionEntry &Section = Sections[RE.SectionID]; @@ -580,6 +741,9 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; + case Triple::aarch64: + resolveAArch64Relocation(Section, Offset, Value, Type, Addend); + break; case Triple::arm: // Fall through. case Triple::thumb: resolveARMRelocation(Section, Offset, @@ -595,6 +759,9 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, case Triple::ppc64: resolvePPC64Relocation(Section, Offset, Value, Type, Addend); break; + case Triple::systemz: + resolveSystemZRelocation(Section, Offset, Value, Type, Addend); + break; default: llvm_unreachable("Unsupported CPU type!"); } } @@ -608,29 +775,33 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uint64_t RelType; Check(RelI.getType(RelType)); int64_t Addend; - Check(RelI.getAdditionalInfo(Addend)); - SymbolRef Symbol; - Check(RelI.getSymbol(Symbol)); + Check(getELFRelocationAddend(RelI, Addend)); + symbol_iterator Symbol = RelI.getSymbol(); // Obtain the symbol name which is referenced in the relocation StringRef TargetName; - Symbol.getName(TargetName); + if (Symbol != Obj.end_symbols()) + Symbol->getName(TargetName); DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend << " TargetName: " << TargetName << "\n"); RelocationValueRef Value; // First search for the symbol in the local symbol table - SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); - SymbolRef::Type SymType; - Symbol.getType(SymType); + SymbolTableMap::const_iterator lsi = Symbols.end(); + SymbolRef::Type SymType = SymbolRef::ST_Unknown; + if (Symbol != Obj.end_symbols()) { + lsi = Symbols.find(TargetName.data()); + Symbol->getType(SymType); + } if (lsi != Symbols.end()) { Value.SectionID = lsi->second.first; Value.Addend = lsi->second.second + Addend; } else { // Search for the symbol in the global symbol table - SymbolTableMap::const_iterator gsi = - GlobalSymbolTable.find(TargetName.data()); + SymbolTableMap::const_iterator gsi = GlobalSymbolTable.end(); + if (Symbol != Obj.end_symbols()) + gsi = GlobalSymbolTable.find(TargetName.data()); if (gsi != GlobalSymbolTable.end()) { Value.SectionID = gsi->second.first; Value.Addend = gsi->second.second + Addend; @@ -641,7 +812,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, // and can be changed by another developers. Maybe best way is add // a new symbol type ST_Section to SymbolRef and use it. section_iterator si(Obj.end_sections()); - Symbol.getSection(si); + Symbol->getSection(si); if (si == Obj.end_sections()) llvm_unreachable("Symbol section not found, bad object file format!"); DEBUG(dbgs() << "\t\tThis is section symbol\n"); @@ -672,7 +843,56 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if (Arch == Triple::arm && + if (Arch == Triple::aarch64 && + (RelType == ELF::R_AARCH64_CALL26 || + RelType == ELF::R_AARCH64_JUMP26)) { + // This is an AArch64 branch relocation, need to use a stub function. + DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); + SectionEntry &Section = Sections[SectionID]; + + // Look for an existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + resolveRelocation(Section, Offset, + (uint64_t)Section.Address + i->second, RelType, 0); + DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function. + DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.StubOffset; + uint8_t *StubTargetAddr = createStubFunction(Section.Address + + Section.StubOffset); + + RelocationEntry REmovz_g3(SectionID, + StubTargetAddr - Section.Address, + ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); + RelocationEntry REmovk_g2(SectionID, + StubTargetAddr - Section.Address + 4, + ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); + RelocationEntry REmovk_g1(SectionID, + StubTargetAddr - Section.Address + 8, + ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); + RelocationEntry REmovk_g0(SectionID, + StubTargetAddr - Section.Address + 12, + ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REmovz_g3, Value.SymbolName); + addRelocationForSymbol(REmovk_g2, Value.SymbolName); + addRelocationForSymbol(REmovk_g1, Value.SymbolName); + addRelocationForSymbol(REmovk_g0, Value.SymbolName); + } else { + addRelocationForSection(REmovz_g3, Value.SectionID); + addRelocationForSection(REmovk_g2, Value.SectionID); + addRelocationForSection(REmovk_g1, Value.SectionID); + addRelocationForSection(REmovk_g0, Value.SectionID); + } + resolveRelocation(Section, Offset, + (uint64_t)Section.Address + Section.StubOffset, + RelType, 0); + Section.StubOffset += getMaxStubSize(); + } + } else if (Arch == Triple::arm && (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || RelType == ELF::R_ARM_JUMP24)) { @@ -693,7 +913,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, uint8_t *StubTargetAddr = createStubFunction(Section.Address + Section.StubOffset); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, - ELF::R_ARM_ABS32, Value.Addend); + ELF::R_ARM_PRIVATE_0, Value.Addend); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -839,6 +1059,53 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID, else addRelocationForSection(RE, Value.SectionID); } + } else if (Arch == Triple::systemz && + (RelType == ELF::R_390_PLT32DBL || + RelType == ELF::R_390_GOTENT)) { + // Create function stubs for both PLT and GOT references, regardless of + // whether the GOT reference is to data or code. The stub contains the + // full address of the symbol, as needed by GOT references, and the + // executable part only adds an overhead of 8 bytes. + // + // We could try to conserve space by allocating the code and data + // parts of the stub separately. However, as things stand, we allocate + // a stub for every relocation, so using a GOT in JIT code should be + // no less space efficient than using an explicit constant pool. + DEBUG(dbgs() << "\t\tThis is a SystemZ indirect relocation."); + SectionEntry &Section = Sections[SectionID]; + + // Look for an existing stub. + 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. + 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); + RelocationEntry RE(SectionID, StubOffset + 8, + ELF::R_390_64, Value.Addend - Addend); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + Section.StubOffset = StubOffset + getMaxStubSize(); + } + + if (RelType == ELF::R_390_GOTENT) + resolveRelocation(Section, Offset, StubAddress + 8, + ELF::R_390_PC32DBL, Addend); + else + resolveRelocation(Section, Offset, StubAddress, RelType, Addend); } else { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); if (Value.SymbolName) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 102b1c6..794c7ec 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -49,6 +49,12 @@ class RuntimeDyldELF : public RuntimeDyldImpl { uint32_t Type, int32_t Addend); + void resolveAArch64Relocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, + uint32_t Type, + int64_t Addend); + void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset, uint32_t Value, @@ -67,6 +73,11 @@ class RuntimeDyldELF : public RuntimeDyldImpl { uint32_t Type, int64_t Addend); + void resolveSystemZRelocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, + uint32_t Type, + int64_t Addend); uint64_t findPPC64TOC() const; void findOPDEntrySection(ObjectImage &Obj, @@ -85,6 +96,7 @@ public: StubMap &Stubs); virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); + virtual StringRef getEHFrameSection(); virtual ~RuntimeDyldELF(); }; diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index 51873b1..383ffab 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -49,7 +49,7 @@ public: /// Address - address in the linker's memory where the section resides. uint8_t *Address; - /// Size - section size. + /// Size - section size. Doesn't include the stubs. size_t Size; /// LoadAddress - the address of the section in the target process's memory. @@ -67,9 +67,9 @@ public: uintptr_t ObjAddress; SectionEntry(StringRef name, uint8_t *address, size_t size, - uintptr_t stubOffset, uintptr_t objAddress) + uintptr_t objAddress) : Name(name), Address(address), Size(size), LoadAddress((uintptr_t)address), - StubOffset(stubOffset), ObjAddress(objAddress) {} + StubOffset(size), ObjAddress(objAddress) {} }; /// RelocationEntry - used to represent relocations internally in the dynamic @@ -166,16 +166,29 @@ protected: 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) 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 HasError; std::string ErrorStr; @@ -321,6 +334,8 @@ public: StringRef getErrorString() { return ErrorStr; } virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0; + + virtual StringRef getEHFrameSection(); }; } // end namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index b3467a9..0384b32 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -21,6 +21,69 @@ using namespace llvm::object; namespace llvm { +static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) { + uint32_t Length = *((uint32_t*)P); + P += 4; + unsigned char *Ret = P + Length; + uint32_t Offset = *((uint32_t*)P); + if (Offset == 0) // is a CIE + return Ret; + + P += 4; + intptr_t FDELocation = *((intptr_t*)P); + intptr_t NewLocation = FDELocation - DeltaForText; + *((intptr_t*)P) = NewLocation; + P += sizeof(intptr_t); + + // Skip the FDE address range + P += sizeof(intptr_t); + + uint8_t Augmentationsize = *P; + P += 1; + if (Augmentationsize != 0) { + intptr_t LSDA = *((intptr_t*)P); + intptr_t NewLSDA = LSDA - DeltaForEH; + *((intptr_t*)P) = NewLSDA; + } + + return Ret; +} + +static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { + intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; + intptr_t MemDistance = A->LoadAddress - B->LoadAddress; + 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]; + } + 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); + + return StringRef((char*)EHFrame->Address, EHFrame->Size); +} + void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, uint64_t Value) { const SectionEntry &Section = Sections[RE.SectionID]; @@ -239,10 +302,9 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, if (isExtern) { // Obtain the symbol name which is referenced in the relocation - SymbolRef Symbol; - RelI.getSymbol(Symbol); + symbol_iterator Symbol = RelI.getSymbol(); StringRef TargetName; - Symbol.getName(TargetName); + Symbol->getName(TargetName); // First search for the symbol in the local symbol table SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); if (lsi != Symbols.end()) { @@ -267,7 +329,30 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, Value.Addend = Addend - Addr; } - if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { + if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) { + assert(IsPCRel); + assert(Size == 2); + StubMap::const_iterator i = Stubs.find(Value); + uint8_t *Addr; + if (i != Stubs.end()) { + Addr = Section.Address + i->second; + } else { + 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); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + Section.StubOffset += 8; + Addr = GOTEntry; + } + resolveRelocation(Section, Offset, (uint64_t)Addr, + macho::RIT_X86_64_Unsigned, 4, true, 2); + } else if (Arch == Triple::arm && + (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { // This is an ARM branch relocation, need to use a stub function. // Look up for existing stub. diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 8da6e35..df8d3bb 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -65,6 +65,7 @@ public: const SymbolTableMap &Symbols, StubMap &Stubs); virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; + virtual StringRef getEHFrameSection(); }; } // end namespace llvm |