aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ExecutionEngine/RuntimeDyld
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld')
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp8
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h6
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h23
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp271
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp1348
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h76
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp175
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h10
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h38
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp919
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h174
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h405
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h277
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h261
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h136
15 files changed, 2596 insertions, 1531 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp
index 8546571..dfa3a20 100644
--- a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp
@@ -101,7 +101,7 @@ private:
/// Lock used to serialize all jit registration events, since they
/// modify global variables.
-llvm::sys::Mutex JITDebugLock;
+ManagedStatic<sys::Mutex> JITDebugLock;
/// Do the registration.
void NotifyDebugger(jit_code_entry* JITCodeEntry) {
@@ -121,7 +121,7 @@ void NotifyDebugger(jit_code_entry* JITCodeEntry) {
GDBJITRegistrar::~GDBJITRegistrar() {
// Free all registered object files.
- llvm::MutexGuard locked(JITDebugLock);
+ llvm::MutexGuard locked(*JITDebugLock);
for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end();
I != E; ++I) {
// Call the private method that doesn't update the map so our iterator
@@ -137,7 +137,7 @@ void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) {
size_t Size = Object.getBufferSize();
assert(Buffer && "Attempt to register a null object with a debugger.");
- llvm::MutexGuard locked(JITDebugLock);
+ llvm::MutexGuard locked(*JITDebugLock);
assert(ObjectBufferMap.find(Buffer) == ObjectBufferMap.end() &&
"Second attempt to perform debug registration.");
jit_code_entry* JITCodeEntry = new jit_code_entry();
@@ -156,7 +156,7 @@ void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) {
bool GDBJITRegistrar::deregisterObject(const ObjectBuffer& Object) {
const char *Buffer = Object.getBufferStart();
- llvm::MutexGuard locked(JITDebugLock);
+ llvm::MutexGuard locked(*JITDebugLock);
RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Buffer);
if (I != ObjectBufferMap.end()) {
diff --git a/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h b/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h
index 6a514ea..636011f 100644
--- a/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h
+++ b/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H
-#define LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_JITREGISTRAR_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_JITREGISTRAR_H
#include "llvm/ExecutionEngine/ObjectBuffer.h"
@@ -41,4 +41,4 @@ public:
} // end namespace llvm
-#endif // LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H
+#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h
index c3a2182..9bbf6a0d 100644
--- a/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h
+++ b/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_RUNTIMEDYLD_OBJECTIMAGECOMMON_H
-#define LLVM_RUNTIMEDYLD_OBJECTIMAGECOMMON_H
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_OBJECTIMAGECOMMON_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_OBJECTIMAGECOMMON_H
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
@@ -36,20 +36,17 @@ protected:
// This form of the constructor allows subclasses to use
// format-specific subclasses of ObjectFile directly
- ObjectImageCommon(ObjectBuffer *Input, std::unique_ptr<object::ObjectFile> Obj)
- : ObjectImage(Input), // saves Input as Buffer and takes ownership
- ObjFile(std::move(Obj))
- {
- }
+ ObjectImageCommon(std::unique_ptr<ObjectBuffer> Input,
+ std::unique_ptr<object::ObjectFile> Obj)
+ : ObjectImage(std::move(Input)), ObjFile(std::move(Obj)) {}
public:
- ObjectImageCommon(ObjectBuffer* Input)
- : ObjectImage(Input) // saves Input as Buffer and takes ownership
- {
+ ObjectImageCommon(std::unique_ptr<ObjectBuffer> Input)
+ : ObjectImage(std::move(Input)) {
// FIXME: error checking? createObjectFile returns an ErrorOr<ObjectFile*>
// and should probably be checked for failure.
- std::unique_ptr<MemoryBuffer> Buf(Buffer->getMemBuffer());
- ObjFile.reset(object::ObjectFile::createObjectFile(Buf).get());
+ MemoryBufferRef Buf = Buffer->getMemBuffer();
+ ObjFile = std::move(object::ObjectFile::createObjectFile(Buf).get());
}
ObjectImageCommon(std::unique_ptr<object::ObjectFile> Input)
: ObjectImage(nullptr), ObjFile(std::move(Input)) {}
@@ -86,4 +83,4 @@ public:
} // end namespace llvm
-#endif // LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H
+#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 9dfd167..c7c67f6 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -14,6 +14,7 @@
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "JITRegistrar.h"
#include "ObjectImageCommon.h"
+#include "RuntimeDyldCheckerImpl.h"
#include "RuntimeDyldELF.h"
#include "RuntimeDyldImpl.h"
#include "RuntimeDyldMachO.h"
@@ -40,6 +41,44 @@ void RuntimeDyldImpl::registerEHFrames() {}
void RuntimeDyldImpl::deregisterEHFrames() {}
+#ifndef NDEBUG
+static void dumpSectionMemory(const SectionEntry &S, StringRef State) {
+ dbgs() << "----- Contents of section " << S.Name << " " << State << " -----";
+
+ if (S.Address == nullptr) {
+ dbgs() << "\n <section not emitted>\n";
+ return;
+ }
+
+ const unsigned ColsPerRow = 16;
+
+ uint8_t *DataAddr = S.Address;
+ uint64_t LoadAddr = S.LoadAddress;
+
+ unsigned StartPadding = LoadAddr & (ColsPerRow - 1);
+ unsigned BytesRemaining = S.Size;
+
+ if (StartPadding) {
+ dbgs() << "\n" << format("0x%016" PRIx64, LoadAddr & ~(ColsPerRow - 1)) << ":";
+ while (StartPadding--)
+ dbgs() << " ";
+ }
+
+ while (BytesRemaining > 0) {
+ if ((LoadAddr & (ColsPerRow - 1)) == 0)
+ dbgs() << "\n" << format("0x%016" PRIx64, LoadAddr) << ":";
+
+ dbgs() << " " << format("%02x", *DataAddr);
+
+ ++DataAddr;
+ ++LoadAddr;
+ --BytesRemaining;
+ }
+
+ dbgs() << "\n";
+}
+#endif
+
// Resolve the relocations for all symbols we currently know about.
void RuntimeDyldImpl::resolveRelocations() {
MutexGuard locked(lock);
@@ -55,8 +94,10 @@ void RuntimeDyldImpl::resolveRelocations() {
// 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");
+ << format("0x%x", Addr) << "\n");
+ DEBUG(dumpSectionMemory(Sections[i], "before relocations"));
resolveRelocationList(Relocations[i], Addr);
+ DEBUG(dumpSectionMemory(Sections[i], "after relocations"));
Relocations.erase(i);
}
}
@@ -88,23 +129,20 @@ static std::error_code getOffset(const SymbolRef &Sym, uint64_t &Result) {
if (std::error_code EC = Sym.getSection(SecI))
return EC;
- if (SecI == Obj->section_end()) {
- Result = UnknownAddressOrSize;
- return object_error::success;
- }
-
- uint64_t SectionAddress;
- if (std::error_code EC = SecI->getAddress(SectionAddress))
- return EC;
+ if (SecI == Obj->section_end()) {
+ Result = UnknownAddressOrSize;
+ return object_error::success;
+ }
+ uint64_t SectionAddress = SecI->getAddress();
Result = Address - SectionAddress;
return object_error::success;
}
-ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
+std::unique_ptr<ObjectImage>
+RuntimeDyldImpl::loadObject(std::unique_ptr<ObjectImage> Obj) {
MutexGuard locked(lock);
- std::unique_ptr<ObjectImage> Obj(InputObject);
if (!Obj)
return nullptr;
@@ -158,14 +196,13 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
SymType == object::SymbolRef::ST_Unknown) {
uint64_t SectOffset;
StringRef SectionData;
- bool IsCode;
section_iterator SI = Obj->end_sections();
Check(getOffset(*I, SectOffset));
Check(I->getSection(SI));
if (SI == Obj->end_sections())
continue;
Check(SI->getContents(SectionData));
- Check(SI->isText(IsCode));
+ bool IsCode = SI->isText();
unsigned SectionID =
findOrEmitSection(*Obj, *SI, IsCode, LocalSections);
LocalSymbols[Name.data()] = SymbolLoc(SectionID, SectOffset);
@@ -195,8 +232,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
if (I == E && !ProcessAllSections)
continue;
- bool IsCode = false;
- Check(RelocatedSection->isText(IsCode));
+ bool IsCode = RelocatedSection->isText();
SectionID =
findOrEmitSection(*Obj, *RelocatedSection, IsCode, LocalSections);
DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n");
@@ -204,12 +240,17 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
for (; I != E;)
I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols,
Stubs);
+
+ // If there is an attached checker, notify it about the stubs for this
+ // section so that they can be verified.
+ if (Checker)
+ Checker->registerStubMap(Obj->getImageName(), SectionID, Stubs);
}
// Give the subclasses a chance to tie-up any loose ends.
finalizeLoad(*Obj, LocalSections);
- return Obj.release();
+ return Obj;
}
// A helper method for computeTotalAllocSize.
@@ -245,20 +286,15 @@ void RuntimeDyldImpl::computeTotalAllocSize(ObjectImage &Obj,
SI != SE; ++SI) {
const SectionRef &Section = *SI;
- bool IsRequired;
- Check(Section.isRequiredForExecution(IsRequired));
+ bool IsRequired = Section.isRequiredForExecution();
// Consider only the sections that are required to be loaded for execution
if (IsRequired) {
- uint64_t DataSize = 0;
- uint64_t Alignment64 = 0;
- bool IsCode = false;
- bool IsReadOnly = false;
StringRef Name;
- Check(Section.getSize(DataSize));
- Check(Section.getAlignment(Alignment64));
- Check(Section.isText(IsCode));
- Check(Section.isReadOnlyData(IsReadOnly));
+ uint64_t DataSize = Section.getSize();
+ uint64_t Alignment64 = Section.getAlignment();
+ bool IsCode = Section.isText();
+ bool IsReadOnly = Section.isReadOnlyData();
Check(Section.getName(Name));
unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
@@ -340,10 +376,8 @@ unsigned RuntimeDyldImpl::computeSectionStubBufSize(ObjectImage &Obj,
}
// Get section data size and alignment
- uint64_t Alignment64;
- uint64_t DataSize;
- Check(Section.getSize(DataSize));
- Check(Section.getAlignment(Alignment64));
+ uint64_t DataSize = Section.getSize();
+ uint64_t Alignment64 = Section.getAlignment();
// Add stubbuf size alignment
unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
@@ -354,6 +388,36 @@ unsigned RuntimeDyldImpl::computeSectionStubBufSize(ObjectImage &Obj,
return StubBufSize;
}
+uint64_t RuntimeDyldImpl::readBytesUnaligned(uint8_t *Src,
+ unsigned Size) const {
+ uint64_t Result = 0;
+ if (IsTargetLittleEndian) {
+ Src += Size - 1;
+ while (Size--)
+ Result = (Result << 8) | *Src--;
+ } else
+ while (Size--)
+ Result = (Result << 8) | *Src++;
+
+ return Result;
+}
+
+void RuntimeDyldImpl::writeBytesUnaligned(uint64_t Value, uint8_t *Dst,
+ unsigned Size) const {
+ if (IsTargetLittleEndian) {
+ while (Size--) {
+ *Dst++ = Value & 0xFF;
+ Value >>= 8;
+ }
+ } else {
+ Dst += Size - 1;
+ while (Size--) {
+ *Dst-- = Value & 0xFF;
+ Value >>= 8;
+ }
+ }
+}
+
void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
const CommonSymbolMap &CommonSymbols,
uint64_t TotalSize,
@@ -365,7 +429,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, 0));
+ Sections.push_back(SectionEntry("<common symbols>", Addr, TotalSize, 0));
memset(Addr, 0, TotalSize);
DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID << " new addr: "
@@ -397,24 +461,18 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
const SectionRef &Section, bool IsCode) {
StringRef data;
- uint64_t Alignment64;
Check(Section.getContents(data));
- Check(Section.getAlignment(Alignment64));
+ uint64_t Alignment64 = Section.getAlignment();
unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
- bool IsRequired;
- bool IsVirtual;
- bool IsZeroInit;
- bool IsReadOnly;
- uint64_t DataSize;
unsigned PaddingSize = 0;
unsigned StubBufSize = 0;
StringRef Name;
- Check(Section.isRequiredForExecution(IsRequired));
- Check(Section.isVirtual(IsVirtual));
- Check(Section.isZeroInit(IsZeroInit));
- Check(Section.isReadOnlyData(IsReadOnly));
- Check(Section.getSize(DataSize));
+ bool IsRequired = Section.isRequiredForExecution();
+ bool IsVirtual = Section.isVirtual();
+ bool IsZeroInit = Section.isZeroInit();
+ bool IsReadOnly = Section.isReadOnlyData();
+ uint64_t DataSize = Section.getSize();
Check(Section.getName(Name));
StubBufSize = computeSectionStubBufSize(Obj, Section);
@@ -477,6 +535,10 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
}
Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData));
+
+ if (Checker)
+ Checker->registerSection(Obj.getImageName(), SectionID);
+
return SectionID;
}
@@ -517,34 +579,26 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE,
}
}
-uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
- if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be ||
- Arch == Triple::arm64 || Arch == Triple::arm64_be) {
+uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr,
+ unsigned AbiVariant) {
+ if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) {
// 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
+ writeBytesUnaligned(0xd2e00010, Addr, 4); // movz ip0, #:abs_g3:<addr>
+ writeBytesUnaligned(0xf2c00010, Addr+4, 4); // movk ip0, #:abs_g2_nc:<addr>
+ writeBytesUnaligned(0xf2a00010, Addr+8, 4); // movk ip0, #:abs_g1_nc:<addr>
+ writeBytesUnaligned(0xf2800010, Addr+12, 4); // movk ip0, #:abs_g0_nc:<addr>
+ writeBytesUnaligned(0xd61f0200, Addr+16, 4); // br ip0
return Addr;
} else if (Arch == Triple::arm || Arch == Triple::armeb) {
// 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;
- *StubAddr = 0xe51ff004; // ldr pc,<label>
- return (uint8_t *)++StubAddr;
+ writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc,<label>
+ return Addr + 4;
} else if (Arch == Triple::mipsel || Arch == Triple::mips) {
- uint32_t *StubAddr = (uint32_t *)Addr;
// 0: 3c190000 lui t9,%hi(addr).
// 4: 27390000 addiu t9,t9,%lo(addr).
// 8: 03200008 jr t9.
@@ -552,31 +606,37 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
const unsigned LuiT9Instr = 0x3c190000, AdduiT9Instr = 0x27390000;
const unsigned JrT9Instr = 0x03200008, NopInstr = 0x0;
- *StubAddr = LuiT9Instr;
- StubAddr++;
- *StubAddr = AdduiT9Instr;
- StubAddr++;
- *StubAddr = JrT9Instr;
- StubAddr++;
- *StubAddr = NopInstr;
+ writeBytesUnaligned(LuiT9Instr, Addr, 4);
+ writeBytesUnaligned(AdduiT9Instr, Addr+4, 4);
+ writeBytesUnaligned(JrT9Instr, Addr+8, 4);
+ writeBytesUnaligned(NopInstr, Addr+12, 4);
return Addr;
} else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) {
- // PowerPC64 stub: the address points to a function descriptor
- // instead of the function itself. Load the function address
- // on r11 and sets it to control register. Also loads the function
- // TOC in r2 and environment pointer to r11.
+ // Depending on which version of the ELF ABI is in use, we need to
+ // generate one of two variants of the stub. They both start with
+ // the same sequence to load the target address into r12.
writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr)
writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr)
writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32
writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr)
writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr)
- writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1)
- writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12)
- writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12)
- writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11
- writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2)
- writeInt32BE(Addr+40, 0x4E800420); // bctr
-
+ if (AbiVariant == 2) {
+ // PowerPC64 stub ELFv2 ABI: The address points to the function itself.
+ // The address is already in r12 as required by the ABI. Branch to it.
+ writeInt32BE(Addr+20, 0xF8410018); // std r2, 24(r1)
+ writeInt32BE(Addr+24, 0x7D8903A6); // mtctr r12
+ writeInt32BE(Addr+28, 0x4E800420); // bctr
+ } else {
+ // PowerPC64 stub ELFv1 ABI: The address points to a function descriptor.
+ // Load the function address on r11 and sets it to control register. Also
+ // loads the function TOC in r2 and environment pointer to r11.
+ writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1)
+ writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12)
+ writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12)
+ writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11
+ writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2)
+ writeInt32BE(Addr+40, 0x4E800420); // bctr
+ }
return Addr;
} else if (Arch == Triple::systemz) {
writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8
@@ -609,6 +669,10 @@ void RuntimeDyldImpl::reassignSectionAddress(unsigned SectionID,
// Addr is a uint64_t because we can't assume the pointer width
// of the target is the same as that of the host. Just use a generic
// "big enough" type.
+ DEBUG(dbgs() << "Reassigning address for section "
+ << SectionID << " (" << Sections[SectionID].Name << "): "
+ << format("0x%016" PRIx64, Sections[SectionID].LoadAddress) << " -> "
+ << format("0x%016" PRIx64, Addr) << "\n");
Sections[SectionID].LoadAddress = Addr;
}
@@ -685,25 +749,31 @@ RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) {
Dyld = nullptr;
MM = mm;
ProcessAllSections = false;
+ Checker = nullptr;
}
-RuntimeDyld::~RuntimeDyld() { delete Dyld; }
+RuntimeDyld::~RuntimeDyld() {}
static std::unique_ptr<RuntimeDyldELF>
-createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections) {
+createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections,
+ RuntimeDyldCheckerImpl *Checker) {
std::unique_ptr<RuntimeDyldELF> Dyld(new RuntimeDyldELF(MM));
Dyld->setProcessAllSections(ProcessAllSections);
+ Dyld->setRuntimeDyldChecker(Checker);
return Dyld;
}
static std::unique_ptr<RuntimeDyldMachO>
-createRuntimeDyldMachO(RTDyldMemoryManager *MM, bool ProcessAllSections) {
- std::unique_ptr<RuntimeDyldMachO> Dyld(new RuntimeDyldMachO(MM));
+createRuntimeDyldMachO(Triple::ArchType Arch, RTDyldMemoryManager *MM,
+ bool ProcessAllSections, RuntimeDyldCheckerImpl *Checker) {
+ std::unique_ptr<RuntimeDyldMachO> Dyld(RuntimeDyldMachO::create(Arch, MM));
Dyld->setProcessAllSections(ProcessAllSections);
+ Dyld->setRuntimeDyldChecker(Checker);
return Dyld;
}
-ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) {
+std::unique_ptr<ObjectImage>
+RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) {
std::unique_ptr<ObjectImage> InputImage;
ObjectFile &Obj = *InputObject;
@@ -711,33 +781,37 @@ ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) {
if (InputObject->isELF()) {
InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(std::move(InputObject)));
if (!Dyld)
- Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release();
+ Dyld = createRuntimeDyldELF(MM, ProcessAllSections, Checker);
} else if (InputObject->isMachO()) {
InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(std::move(InputObject)));
if (!Dyld)
- Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release();
+ Dyld = createRuntimeDyldMachO(
+ static_cast<Triple::ArchType>(InputImage->getArch()), MM,
+ ProcessAllSections, Checker);
} else
report_fatal_error("Incompatible object format!");
if (!Dyld->isCompatibleFile(&Obj))
report_fatal_error("Incompatible object format!");
- Dyld->loadObject(InputImage.get());
- return InputImage.release();
+ return Dyld->loadObject(std::move(InputImage));
}
-ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
+std::unique_ptr<ObjectImage>
+RuntimeDyld::loadObject(std::unique_ptr<ObjectBuffer> InputBuffer) {
std::unique_ptr<ObjectImage> InputImage;
sys::fs::file_magic Type = sys::fs::identify_magic(InputBuffer->getBuffer());
+ auto *InputBufferPtr = InputBuffer.get();
switch (Type) {
+ case sys::fs::file_magic::elf:
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:
- InputImage.reset(RuntimeDyldELF::createObjectImage(InputBuffer));
+ InputImage = RuntimeDyldELF::createObjectImage(std::move(InputBuffer));
if (!Dyld)
- Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release();
+ Dyld = createRuntimeDyldELF(MM, ProcessAllSections, Checker);
break;
case sys::fs::file_magic::macho_object:
case sys::fs::file_magic::macho_executable:
@@ -749,9 +823,11 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
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:
- InputImage.reset(RuntimeDyldMachO::createObjectImage(InputBuffer));
+ InputImage = RuntimeDyldMachO::createObjectImage(std::move(InputBuffer));
if (!Dyld)
- Dyld = createRuntimeDyldMachO(MM, ProcessAllSections).release();
+ Dyld = createRuntimeDyldMachO(
+ static_cast<Triple::ArchType>(InputImage->getArch()), MM,
+ ProcessAllSections, Checker);
break;
case sys::fs::file_magic::unknown:
case sys::fs::file_magic::bitcode:
@@ -764,20 +840,19 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
report_fatal_error("Incompatible object format!");
}
- if (!Dyld->isCompatibleFormat(InputBuffer))
+ if (!Dyld->isCompatibleFormat(InputBufferPtr))
report_fatal_error("Incompatible object format!");
- Dyld->loadObject(InputImage.get());
- return InputImage.release();
+ return Dyld->loadObject(std::move(InputImage));
}
-void *RuntimeDyld::getSymbolAddress(StringRef Name) {
+void *RuntimeDyld::getSymbolAddress(StringRef Name) const {
if (!Dyld)
return nullptr;
return Dyld->getSymbolAddress(Name);
}
-uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) {
+uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) const {
if (!Dyld)
return 0;
return Dyld->getSymbolLoadAddress(Name);
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
index 190bbbf..8818349 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
@@ -7,11 +7,13 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
-#include "llvm/Support/StringRefMemoryObject.h"
+#include "llvm/Support/Path.h"
+#include "RuntimeDyldCheckerImpl.h"
#include "RuntimeDyldImpl.h"
#include <cctype>
#include <memory>
@@ -22,579 +24,696 @@ using namespace llvm;
namespace llvm {
- // Helper class that implements the language evaluated by RuntimeDyldChecker.
- class RuntimeDyldCheckerExprEval {
- public:
-
- RuntimeDyldCheckerExprEval(const RuntimeDyldChecker &Checker,
- llvm::raw_ostream &ErrStream)
- : Checker(Checker), ErrStream(ErrStream) {}
-
- bool evaluate(StringRef Expr) const {
- // Expect equality expression of the form 'LHS = RHS'.
- Expr = Expr.trim();
- size_t EQIdx = Expr.find('=');
-
- // Evaluate LHS.
- StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();
- StringRef RemainingExpr;
- EvalResult LHSResult;
- std::tie(LHSResult, RemainingExpr) =
- evalComplexExpr(evalSimpleExpr(LHSExpr));
- if (LHSResult.hasError())
- return handleError(Expr, LHSResult);
- if (RemainingExpr != "")
- return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, ""));
-
- // Evaluate RHS.
- StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim();
- EvalResult RHSResult;
- std::tie(RHSResult, RemainingExpr) =
- evalComplexExpr(evalSimpleExpr(RHSExpr));
- if (RHSResult.hasError())
- return handleError(Expr, RHSResult);
- if (RemainingExpr != "")
- return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, ""));
-
- if (LHSResult.getValue() != RHSResult.getValue()) {
- ErrStream << "Expression '" << Expr << "' is false: "
- << format("0x%lx", LHSResult.getValue()) << " != "
- << format("0x%lx", RHSResult.getValue()) << "\n";
- return false;
- }
- return true;
+// Helper class that implements the language evaluated by RuntimeDyldChecker.
+class RuntimeDyldCheckerExprEval {
+public:
+ RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker,
+ raw_ostream &ErrStream)
+ : Checker(Checker) {}
+
+ bool evaluate(StringRef Expr) const {
+ // Expect equality expression of the form 'LHS = RHS'.
+ Expr = Expr.trim();
+ size_t EQIdx = Expr.find('=');
+
+ ParseContext OutsideLoad(false);
+
+ // Evaluate LHS.
+ StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();
+ StringRef RemainingExpr;
+ EvalResult LHSResult;
+ std::tie(LHSResult, RemainingExpr) =
+ evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad);
+ if (LHSResult.hasError())
+ return handleError(Expr, LHSResult);
+ if (RemainingExpr != "")
+ return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, ""));
+
+ // Evaluate RHS.
+ StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim();
+ EvalResult RHSResult;
+ std::tie(RHSResult, RemainingExpr) =
+ evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad);
+ if (RHSResult.hasError())
+ return handleError(Expr, RHSResult);
+ if (RemainingExpr != "")
+ return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, ""));
+
+ if (LHSResult.getValue() != RHSResult.getValue()) {
+ Checker.ErrStream << "Expression '" << Expr << "' is false: "
+ << format("0x%" PRIx64, LHSResult.getValue())
+ << " != " << format("0x%" PRIx64, RHSResult.getValue())
+ << "\n";
+ return false;
}
+ return true;
+ }
+
+private:
+ // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In
+ // particular, it needs to know whether a symbol is being evaluated in the
+ // context of a load, in which case we want the linker's local address for
+ // the symbol, or outside of a load, in which case we want the symbol's
+ // address in the remote target.
+
+ struct ParseContext {
+ bool IsInsideLoad;
+ ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {}
+ };
+
+ const RuntimeDyldCheckerImpl &Checker;
+
+ enum class BinOpToken : unsigned {
+ Invalid,
+ Add,
+ Sub,
+ BitwiseAnd,
+ BitwiseOr,
+ ShiftLeft,
+ ShiftRight
+ };
+
+ class EvalResult {
+ public:
+ EvalResult() : Value(0), ErrorMsg("") {}
+ EvalResult(uint64_t Value) : Value(Value), ErrorMsg("") {}
+ EvalResult(std::string ErrorMsg) : Value(0), ErrorMsg(ErrorMsg) {}
+ uint64_t getValue() const { return Value; }
+ bool hasError() const { return ErrorMsg != ""; }
+ const std::string &getErrorMsg() const { return ErrorMsg; }
private:
- const RuntimeDyldChecker &Checker;
- llvm::raw_ostream &ErrStream;
-
- enum class BinOpToken : unsigned { Invalid, Add, Sub, BitwiseAnd,
- BitwiseOr, ShiftLeft, ShiftRight };
-
- class EvalResult {
- public:
- EvalResult()
- : Value(0), ErrorMsg("") {}
- EvalResult(uint64_t Value)
- : Value(Value), ErrorMsg("") {}
- EvalResult(std::string ErrorMsg)
- : Value(0), ErrorMsg(ErrorMsg) {}
- uint64_t getValue() const { return Value; }
- bool hasError() const { return ErrorMsg != ""; }
- const std::string& getErrorMsg() const { return ErrorMsg; }
- private:
- uint64_t Value;
- std::string ErrorMsg;
- };
-
- StringRef getTokenForError(StringRef Expr) const {
- if (Expr.empty())
- return "";
-
- StringRef Token, Remaining;
- if (isalpha(Expr[0]))
- std::tie(Token, Remaining) = parseSymbol(Expr);
- else if (isdigit(Expr[0]))
- std::tie(Token, Remaining) = parseNumberString(Expr);
- else {
- unsigned TokLen = 1;
- if (Expr.startswith("<<") || Expr.startswith(">>"))
- TokLen = 2;
- Token = Expr.substr(0, TokLen);
- }
- return Token;
- }
+ uint64_t Value;
+ std::string ErrorMsg;
+ };
- EvalResult unexpectedToken(StringRef TokenStart,
- StringRef SubExpr,
- StringRef ErrText) const {
- std::string ErrorMsg("Encountered unexpected token '");
- ErrorMsg += getTokenForError(TokenStart);
- if (SubExpr != "") {
- ErrorMsg += "' while parsing subexpression '";
- ErrorMsg += SubExpr;
- }
- ErrorMsg += "'";
- if (ErrText != "") {
- ErrorMsg += " ";
- ErrorMsg += ErrText;
- }
- return EvalResult(std::move(ErrorMsg));
+ StringRef getTokenForError(StringRef Expr) const {
+ if (Expr.empty())
+ return "";
+
+ StringRef Token, Remaining;
+ if (isalpha(Expr[0]))
+ std::tie(Token, Remaining) = parseSymbol(Expr);
+ else if (isdigit(Expr[0]))
+ std::tie(Token, Remaining) = parseNumberString(Expr);
+ else {
+ unsigned TokLen = 1;
+ if (Expr.startswith("<<") || Expr.startswith(">>"))
+ TokLen = 2;
+ Token = Expr.substr(0, TokLen);
}
+ return Token;
+ }
- bool handleError(StringRef Expr, const EvalResult &R) const {
- assert(R.hasError() && "Not an error result.");
- ErrStream << "Error evaluating expression '" << Expr << "': "
- << R.getErrorMsg() << "\n";
- return false;
+ EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr,
+ StringRef ErrText) const {
+ std::string ErrorMsg("Encountered unexpected token '");
+ ErrorMsg += getTokenForError(TokenStart);
+ if (SubExpr != "") {
+ ErrorMsg += "' while parsing subexpression '";
+ ErrorMsg += SubExpr;
}
+ ErrorMsg += "'";
+ if (ErrText != "") {
+ ErrorMsg += " ";
+ ErrorMsg += ErrText;
+ }
+ return EvalResult(std::move(ErrorMsg));
+ }
- std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const {
- if (Expr.empty())
- return std::make_pair(BinOpToken::Invalid, "");
-
- // Handle the two 2-character tokens.
- if (Expr.startswith("<<"))
- return std::make_pair(BinOpToken::ShiftLeft,
- Expr.substr(2).ltrim());
- if (Expr.startswith(">>"))
- return std::make_pair(BinOpToken::ShiftRight,
- Expr.substr(2).ltrim());
-
- // Handle one-character tokens.
- BinOpToken Op;
- switch (Expr[0]) {
- default: return std::make_pair(BinOpToken::Invalid, Expr);
- case '+': Op = BinOpToken::Add; break;
- case '-': Op = BinOpToken::Sub; break;
- case '&': Op = BinOpToken::BitwiseAnd; break;
- case '|': Op = BinOpToken::BitwiseOr; break;
- }
+ bool handleError(StringRef Expr, const EvalResult &R) const {
+ assert(R.hasError() && "Not an error result.");
+ Checker.ErrStream << "Error evaluating expression '" << Expr
+ << "': " << R.getErrorMsg() << "\n";
+ return false;
+ }
- return std::make_pair(Op, Expr.substr(1).ltrim());
+ std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const {
+ if (Expr.empty())
+ return std::make_pair(BinOpToken::Invalid, "");
+
+ // Handle the two 2-character tokens.
+ if (Expr.startswith("<<"))
+ return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim());
+ if (Expr.startswith(">>"))
+ return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim());
+
+ // Handle one-character tokens.
+ BinOpToken Op;
+ switch (Expr[0]) {
+ default:
+ return std::make_pair(BinOpToken::Invalid, Expr);
+ case '+':
+ Op = BinOpToken::Add;
+ break;
+ case '-':
+ Op = BinOpToken::Sub;
+ break;
+ case '&':
+ Op = BinOpToken::BitwiseAnd;
+ break;
+ case '|':
+ Op = BinOpToken::BitwiseOr;
+ break;
}
- EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult,
- const EvalResult &RHSResult) const {
- switch (Op) {
- default: llvm_unreachable("Tried to evaluate unrecognized operation.");
- case BinOpToken::Add:
- return EvalResult(LHSResult.getValue() + RHSResult.getValue());
- case BinOpToken::Sub:
- return EvalResult(LHSResult.getValue() - RHSResult.getValue());
- case BinOpToken::BitwiseAnd:
- return EvalResult(LHSResult.getValue() & RHSResult.getValue());
- case BinOpToken::BitwiseOr:
- return EvalResult(LHSResult.getValue() | RHSResult.getValue());
- case BinOpToken::ShiftLeft:
- return EvalResult(LHSResult.getValue() << RHSResult.getValue());
- case BinOpToken::ShiftRight:
- return EvalResult(LHSResult.getValue() >> RHSResult.getValue());
- }
- }
+ return std::make_pair(Op, Expr.substr(1).ltrim());
+ }
- // Parse a symbol and return a (string, string) pair representing the symbol
- // name and expression remaining to be parsed.
- std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const {
- size_t FirstNonSymbol =
- Expr.find_first_not_of("0123456789"
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ":_");
- return std::make_pair(Expr.substr(0, FirstNonSymbol),
- Expr.substr(FirstNonSymbol).ltrim());
+ EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult,
+ const EvalResult &RHSResult) const {
+ switch (Op) {
+ default:
+ llvm_unreachable("Tried to evaluate unrecognized operation.");
+ case BinOpToken::Add:
+ return EvalResult(LHSResult.getValue() + RHSResult.getValue());
+ case BinOpToken::Sub:
+ return EvalResult(LHSResult.getValue() - RHSResult.getValue());
+ case BinOpToken::BitwiseAnd:
+ return EvalResult(LHSResult.getValue() & RHSResult.getValue());
+ case BinOpToken::BitwiseOr:
+ return EvalResult(LHSResult.getValue() | RHSResult.getValue());
+ case BinOpToken::ShiftLeft:
+ return EvalResult(LHSResult.getValue() << RHSResult.getValue());
+ case BinOpToken::ShiftRight:
+ return EvalResult(LHSResult.getValue() >> RHSResult.getValue());
}
+ }
- // Evaluate a call to decode_operand. Decode the instruction operand at the
- // given symbol and get the value of the requested operand.
- // Returns an error if the instruction cannot be decoded, or the requested
- // operand is not an immediate.
- // On success, retuns a pair containing the value of the operand, plus
- // the expression remaining to be evaluated.
- std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const {
- if (!Expr.startswith("("))
- return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
- StringRef RemainingExpr = Expr.substr(1).ltrim();
- StringRef Symbol;
- std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
-
- if (!Checker.checkSymbolIsValidForLoad(Symbol))
- return std::make_pair(EvalResult(("Cannot decode unknown symbol '" +
- Symbol + "'").str()),
- "");
-
- if (!RemainingExpr.startswith(","))
- return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr,
- "expected ','"),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- EvalResult OpIdxExpr;
- std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
- if (OpIdxExpr.hasError())
- return std::make_pair(OpIdxExpr, "");
-
- if (!RemainingExpr.startswith(")"))
- return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr,
- "expected ')'"),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- MCInst Inst;
- uint64_t Size;
- if (!decodeInst(Symbol, Inst, Size))
- return std::make_pair(EvalResult(("Couldn't decode instruction at '" +
- Symbol + "'").str()),
- "");
-
- unsigned OpIdx = OpIdxExpr.getValue();
- if (OpIdx >= Inst.getNumOperands()) {
- std::string ErrMsg;
- raw_string_ostream ErrMsgStream(ErrMsg);
- ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx)
- << " for instruction '" << Symbol
- << ". Instruction has only "
- << format("%i", Inst.getNumOperands()) << " operands.";
- return std::make_pair(EvalResult(ErrMsgStream.str()), "");
- }
+ // Parse a symbol and return a (string, string) pair representing the symbol
+ // name and expression remaining to be parsed.
+ std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const {
+ size_t FirstNonSymbol = Expr.find_first_not_of("0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ ":_.$");
+ return std::make_pair(Expr.substr(0, FirstNonSymbol),
+ Expr.substr(FirstNonSymbol).ltrim());
+ }
- const MCOperand &Op = Inst.getOperand(OpIdx);
- if (!Op.isImm()) {
- std::string ErrMsg;
- raw_string_ostream ErrMsgStream(ErrMsg);
- ErrMsgStream << "Operand '" << format("%i", OpIdx)
- << "' of instruction '" << Symbol
- << "' is not an immediate.\nInstruction is:\n ";
- Inst.dump_pretty(ErrMsgStream,
- Checker.Disassembler->getContext().getAsmInfo(),
- Checker.InstPrinter);
-
- return std::make_pair(EvalResult(ErrMsgStream.str()), "");
- }
+ // Evaluate a call to decode_operand. Decode the instruction operand at the
+ // given symbol and get the value of the requested operand.
+ // Returns an error if the instruction cannot be decoded, or the requested
+ // operand is not an immediate.
+ // On success, retuns a pair containing the value of the operand, plus
+ // the expression remaining to be evaluated.
+ std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const {
+ if (!Expr.startswith("("))
+ return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
+ StringRef RemainingExpr = Expr.substr(1).ltrim();
+ StringRef Symbol;
+ std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
+
+ if (!Checker.isSymbolValid(Symbol))
+ return std::make_pair(
+ EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
+ "");
- return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
- }
+ if (!RemainingExpr.startswith(","))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
- // Evaluate a call to next_pc. Decode the instruction at the given
- // symbol and return the following program counter..
- // Returns an error if the instruction cannot be decoded.
- // On success, returns a pair containing the next PC, plus the length of the
- // expression remaining to be evaluated.
- std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr) const {
- if (!Expr.startswith("("))
- return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
- StringRef RemainingExpr = Expr.substr(1).ltrim();
- StringRef Symbol;
- std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
-
- if (!Checker.checkSymbolIsValidForLoad(Symbol))
- return std::make_pair(EvalResult(("Cannot decode unknown symbol '"
- + Symbol + "'").str()),
- "");
-
- if (!RemainingExpr.startswith(")"))
- return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr,
- "expected ')'"),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- MCInst Inst;
- uint64_t Size;
- if (!decodeInst(Symbol, Inst, Size))
- return std::make_pair(EvalResult(("Couldn't decode instruction at '" +
- Symbol + "'").str()),
- "");
- uint64_t NextPC = Checker.getSymbolAddress(Symbol) + Size;
-
- return std::make_pair(EvalResult(NextPC), RemainingExpr);
- }
+ EvalResult OpIdxExpr;
+ std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
+ if (OpIdxExpr.hasError())
+ return std::make_pair(OpIdxExpr, "");
- // Evaluate an identiefer expr, which may be a symbol, or a call to
- // one of the builtin functions: get_insn_opcode or get_insn_length.
- // Return the result, plus the expression remaining to be parsed.
- std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr) const {
- StringRef Symbol;
- StringRef RemainingExpr;
- std::tie(Symbol, RemainingExpr) = parseSymbol(Expr);
-
- // Check for builtin function calls.
- if (Symbol == "decode_operand")
- return evalDecodeOperand(RemainingExpr);
- else if (Symbol == "next_pc")
- return evalNextPC(RemainingExpr);
-
- // Looks like a plain symbol reference.
- return std::make_pair(EvalResult(Checker.getSymbolAddress(Symbol)),
- RemainingExpr);
- }
+ if (!RemainingExpr.startswith(")"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
- // Parse a number (hexadecimal or decimal) and return a (string, string)
- // pair representing the number and the expression remaining to be parsed.
- std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const {
- size_t FirstNonDigit = StringRef::npos;
- if (Expr.startswith("0x")) {
- FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2);
- if (FirstNonDigit == StringRef::npos)
- FirstNonDigit = Expr.size();
- } else {
- FirstNonDigit = Expr.find_first_not_of("0123456789");
- if (FirstNonDigit == StringRef::npos)
- FirstNonDigit = Expr.size();
- }
- return std::make_pair(Expr.substr(0, FirstNonDigit),
- Expr.substr(FirstNonDigit));
+ MCInst Inst;
+ uint64_t Size;
+ if (!decodeInst(Symbol, Inst, Size))
+ return std::make_pair(
+ EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
+ "");
+
+ unsigned OpIdx = OpIdxExpr.getValue();
+ if (OpIdx >= Inst.getNumOperands()) {
+ std::string ErrMsg;
+ raw_string_ostream ErrMsgStream(ErrMsg);
+ ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx)
+ << "' for instruction '" << Symbol
+ << "'. Instruction has only "
+ << format("%i", Inst.getNumOperands())
+ << " operands.\nInstruction is:\n ";
+ Inst.dump_pretty(ErrMsgStream,
+ Checker.Disassembler->getContext().getAsmInfo(),
+ Checker.InstPrinter);
+ return std::make_pair(EvalResult(ErrMsgStream.str()), "");
}
- // Evaluate a constant numeric expression (hexidecimal or decimal) and
- // return a pair containing the result, and the expression remaining to be
- // evaluated.
- std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const {
- StringRef ValueStr;
- StringRef RemainingExpr;
- std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);
-
- if (ValueStr.empty() || !isdigit(ValueStr[0]))
- return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr,
- "expected number"),
- "");
- uint64_t Value;
- ValueStr.getAsInteger(0, Value);
- return std::make_pair(EvalResult(Value), RemainingExpr);
+ const MCOperand &Op = Inst.getOperand(OpIdx);
+ if (!Op.isImm()) {
+ std::string ErrMsg;
+ raw_string_ostream ErrMsgStream(ErrMsg);
+ ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '"
+ << Symbol << "' is not an immediate.\nInstruction is:\n ";
+ Inst.dump_pretty(ErrMsgStream,
+ Checker.Disassembler->getContext().getAsmInfo(),
+ Checker.InstPrinter);
+
+ return std::make_pair(EvalResult(ErrMsgStream.str()), "");
}
- // Evaluate an expression of the form "(<expr>)" and return a pair
- // containing the result of evaluating <expr>, plus the expression
- // remaining to be parsed.
- std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr) const {
- assert(Expr.startswith("(") && "Not a parenthesized expression");
- EvalResult SubExprResult;
- StringRef RemainingExpr;
- std::tie(SubExprResult, RemainingExpr) =
- evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim()));
- if (SubExprResult.hasError())
- return std::make_pair(SubExprResult, "");
- if (!RemainingExpr.startswith(")"))
- return std::make_pair(unexpectedToken(RemainingExpr, Expr,
- "expected ')'"),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
- return std::make_pair(SubExprResult, RemainingExpr);
- }
+ return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
+ }
- // Evaluate an expression in one of the following forms:
- // *{<number>}<symbol>
- // *{<number>}(<symbol> + <number>)
- // *{<number>}(<symbol> - <number>)
- // Return a pair containing the result, plus the expression remaining to be
- // parsed.
- std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {
- assert(Expr.startswith("*") && "Not a load expression");
- StringRef RemainingExpr = Expr.substr(1).ltrim();
- // Parse read size.
- if (!RemainingExpr.startswith("{"))
- return std::make_pair(EvalResult("Expected '{' following '*'."), "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
- EvalResult ReadSizeExpr;
- std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
- if (ReadSizeExpr.hasError())
- return std::make_pair(ReadSizeExpr, RemainingExpr);
- uint64_t ReadSize = ReadSizeExpr.getValue();
- if (ReadSize < 1 || ReadSize > 8)
- return std::make_pair(EvalResult("Invalid size for dereference."), "");
- if (!RemainingExpr.startswith("}"))
- return std::make_pair(EvalResult("Missing '}' for dereference."), "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- // Check for '(symbol +/- constant)' form.
- bool SymbolPlusConstant = false;
- if (RemainingExpr.startswith("(")) {
- SymbolPlusConstant = true;
- RemainingExpr = RemainingExpr.substr(1).ltrim();
- }
+ // Evaluate a call to next_pc.
+ // Decode the instruction at the given symbol and return the following program
+ // counter.
+ // Returns an error if the instruction cannot be decoded.
+ // On success, returns a pair containing the next PC, plus of the
+ // expression remaining to be evaluated.
+ std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr,
+ ParseContext PCtx) const {
+ if (!Expr.startswith("("))
+ return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
+ StringRef RemainingExpr = Expr.substr(1).ltrim();
+ StringRef Symbol;
+ std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
+
+ if (!Checker.isSymbolValid(Symbol))
+ return std::make_pair(
+ EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
+ "");
+
+ if (!RemainingExpr.startswith(")"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ MCInst Inst;
+ uint64_t InstSize;
+ if (!decodeInst(Symbol, Inst, InstSize))
+ return std::make_pair(
+ EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
+ "");
+
+ uint64_t SymbolAddr = PCtx.IsInsideLoad
+ ? Checker.getSymbolLinkerAddr(Symbol)
+ : Checker.getSymbolRemoteAddr(Symbol);
+ uint64_t NextPC = SymbolAddr + InstSize;
- // Read symbol.
- StringRef Symbol;
- std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
+ return std::make_pair(EvalResult(NextPC), RemainingExpr);
+ }
- if (!Checker.checkSymbolIsValidForLoad(Symbol))
- return std::make_pair(EvalResult(("Cannot dereference unknown symbol '"
- + Symbol + "'").str()),
- "");
+ // Evaluate a call to stub_addr.
+ // Look up and return the address of the stub for the given
+ // (<file name>, <section name>, <symbol name>) tuple.
+ // On success, returns a pair containing the stub address, plus the expression
+ // remaining to be evaluated.
+ std::pair<EvalResult, StringRef> evalStubAddr(StringRef Expr,
+ ParseContext PCtx) const {
+ if (!Expr.startswith("("))
+ return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
+ StringRef RemainingExpr = Expr.substr(1).ltrim();
+
+ // Handle file-name specially, as it may contain characters that aren't
+ // legal for symbols.
+ StringRef FileName;
+ size_t ComaIdx = RemainingExpr.find(',');
+ FileName = RemainingExpr.substr(0, ComaIdx).rtrim();
+ RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
+
+ if (!RemainingExpr.startswith(","))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
- // Set up defaut offset.
- int64_t Offset = 0;
+ StringRef SectionName;
+ std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr);
- // Handle "+/- constant)" portion if necessary.
- if (SymbolPlusConstant) {
- char OpChar = RemainingExpr[0];
- if (OpChar != '+' && OpChar != '-')
- return std::make_pair(EvalResult("Invalid operator in load address."),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
+ if (!RemainingExpr.startswith(","))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
- EvalResult OffsetExpr;
- std::tie(OffsetExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
+ StringRef Symbol;
+ std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
- Offset = (OpChar == '+') ?
- OffsetExpr.getValue() : -1 * OffsetExpr.getValue();
+ if (!RemainingExpr.startswith(")"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
- if (!RemainingExpr.startswith(")"))
- return std::make_pair(EvalResult("Missing ')' in load address."),
- "");
+ uint64_t StubAddr;
+ std::string ErrorMsg = "";
+ std::tie(StubAddr, ErrorMsg) = Checker.getStubAddrFor(
+ FileName, SectionName, Symbol, PCtx.IsInsideLoad);
- RemainingExpr = RemainingExpr.substr(1).ltrim();
- }
+ if (ErrorMsg != "")
+ return std::make_pair(EvalResult(ErrorMsg), "");
+ return std::make_pair(EvalResult(StubAddr), RemainingExpr);
+ }
+
+ std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr,
+ ParseContext PCtx) const {
+ if (!Expr.startswith("("))
+ return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
+ StringRef RemainingExpr = Expr.substr(1).ltrim();
+
+ // Handle file-name specially, as it may contain characters that aren't
+ // legal for symbols.
+ StringRef FileName;
+ size_t ComaIdx = RemainingExpr.find(',');
+ FileName = RemainingExpr.substr(0, ComaIdx).rtrim();
+ RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
+
+ if (!RemainingExpr.startswith(","))
return std::make_pair(
- EvalResult(Checker.readMemoryAtSymbol(Symbol, Offset, ReadSize)),
- RemainingExpr);
+ unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ StringRef SectionName;
+ std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr);
+
+ if (!RemainingExpr.startswith(")"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ uint64_t StubAddr;
+ std::string ErrorMsg = "";
+ std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr(
+ FileName, SectionName, PCtx.IsInsideLoad);
+
+ if (ErrorMsg != "")
+ return std::make_pair(EvalResult(ErrorMsg), "");
+
+ return std::make_pair(EvalResult(StubAddr), RemainingExpr);
+ }
+
+ // Evaluate an identiefer expr, which may be a symbol, or a call to
+ // one of the builtin functions: get_insn_opcode or get_insn_length.
+ // Return the result, plus the expression remaining to be parsed.
+ std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr,
+ ParseContext PCtx) const {
+ StringRef Symbol;
+ StringRef RemainingExpr;
+ std::tie(Symbol, RemainingExpr) = parseSymbol(Expr);
+
+ // Check for builtin function calls.
+ if (Symbol == "decode_operand")
+ return evalDecodeOperand(RemainingExpr);
+ else if (Symbol == "next_pc")
+ return evalNextPC(RemainingExpr, PCtx);
+ else if (Symbol == "stub_addr")
+ return evalStubAddr(RemainingExpr, PCtx);
+ else if (Symbol == "section_addr")
+ return evalSectionAddr(RemainingExpr, PCtx);
+
+ if (!Checker.isSymbolValid(Symbol)) {
+ std::string ErrMsg("No known address for symbol '");
+ ErrMsg += Symbol;
+ ErrMsg += "'";
+ if (Symbol.startswith("L"))
+ ErrMsg += " (this appears to be an assembler local label - "
+ " perhaps drop the 'L'?)";
+
+ return std::make_pair(EvalResult(ErrMsg), "");
}
- // Evaluate a "simple" expression. This is any expression that _isn't_ an
- // un-parenthesized binary expression.
- //
- // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
- //
- // Returns a pair containing the result of the evaluation, plus the
- // expression remaining to be parsed.
- std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr) const {
- EvalResult SubExprResult;
- StringRef RemainingExpr;
-
- if (Expr.empty())
- return std::make_pair(EvalResult("Unexpected end of expression"), "");
-
- if (Expr[0] == '(')
- std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr);
- else if (Expr[0] == '*')
- std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);
- else if (isalpha(Expr[0]))
- std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr);
- else if (isdigit(Expr[0]))
- std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
-
- if (SubExprResult.hasError())
- return std::make_pair(SubExprResult, RemainingExpr);
-
- // Evaluate bit-slice if present.
- if (RemainingExpr.startswith("["))
- std::tie(SubExprResult, RemainingExpr) =
- evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
+ // The value for the symbol depends on the context we're evaluating in:
+ // Inside a load this is the address in the linker's memory, outside a
+ // load it's the address in the target processes memory.
+ uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLinkerAddr(Symbol)
+ : Checker.getSymbolRemoteAddr(Symbol);
- return std::make_pair(SubExprResult, RemainingExpr);
+ // Looks like a plain symbol reference.
+ return std::make_pair(EvalResult(Value), RemainingExpr);
+ }
+
+ // Parse a number (hexadecimal or decimal) and return a (string, string)
+ // pair representing the number and the expression remaining to be parsed.
+ std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const {
+ size_t FirstNonDigit = StringRef::npos;
+ if (Expr.startswith("0x")) {
+ FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2);
+ if (FirstNonDigit == StringRef::npos)
+ FirstNonDigit = Expr.size();
+ } else {
+ FirstNonDigit = Expr.find_first_not_of("0123456789");
+ if (FirstNonDigit == StringRef::npos)
+ FirstNonDigit = Expr.size();
}
+ return std::make_pair(Expr.substr(0, FirstNonDigit),
+ Expr.substr(FirstNonDigit));
+ }
+
+ // Evaluate a constant numeric expression (hexidecimal or decimal) and
+ // return a pair containing the result, and the expression remaining to be
+ // evaluated.
+ std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const {
+ StringRef ValueStr;
+ StringRef RemainingExpr;
+ std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);
+
+ if (ValueStr.empty() || !isdigit(ValueStr[0]))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), "");
+ uint64_t Value;
+ ValueStr.getAsInteger(0, Value);
+ return std::make_pair(EvalResult(Value), RemainingExpr);
+ }
+
+ // Evaluate an expression of the form "(<expr>)" and return a pair
+ // containing the result of evaluating <expr>, plus the expression
+ // remaining to be parsed.
+ std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr,
+ ParseContext PCtx) const {
+ assert(Expr.startswith("(") && "Not a parenthesized expression");
+ EvalResult SubExprResult;
+ StringRef RemainingExpr;
+ std::tie(SubExprResult, RemainingExpr) =
+ evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx);
+ if (SubExprResult.hasError())
+ return std::make_pair(SubExprResult, "");
+ if (!RemainingExpr.startswith(")"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+ return std::make_pair(SubExprResult, RemainingExpr);
+ }
- // Evaluate a bit-slice of an expression.
- // A bit-slice has the form "<expr>[high:low]". The result of evaluating a
- // slice is the bits between high and low (inclusive) in the original
- // expression, right shifted so that the "low" bit is in position 0 in the
+ // Evaluate an expression in one of the following forms:
+ // *{<number>}<expr>
+ // Return a pair containing the result, plus the expression remaining to be
+ // parsed.
+ std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {
+ assert(Expr.startswith("*") && "Not a load expression");
+ StringRef RemainingExpr = Expr.substr(1).ltrim();
+
+ // Parse read size.
+ if (!RemainingExpr.startswith("{"))
+ return std::make_pair(EvalResult("Expected '{' following '*'."), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+ EvalResult ReadSizeExpr;
+ std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
+ if (ReadSizeExpr.hasError())
+ return std::make_pair(ReadSizeExpr, RemainingExpr);
+ uint64_t ReadSize = ReadSizeExpr.getValue();
+ if (ReadSize < 1 || ReadSize > 8)
+ return std::make_pair(EvalResult("Invalid size for dereference."), "");
+ if (!RemainingExpr.startswith("}"))
+ return std::make_pair(EvalResult("Missing '}' for dereference."), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ // Evaluate the expression representing the load address.
+ ParseContext LoadCtx(true);
+ EvalResult LoadAddrExprResult;
+ std::tie(LoadAddrExprResult, RemainingExpr) =
+ evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx);
+
+ if (LoadAddrExprResult.hasError())
+ return std::make_pair(LoadAddrExprResult, "");
+
+ uint64_t LoadAddr = LoadAddrExprResult.getValue();
+
+ return std::make_pair(
+ EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)),
+ RemainingExpr);
+ }
+
+ // Evaluate a "simple" expression. This is any expression that _isn't_ an
+ // un-parenthesized binary expression.
+ //
+ // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
+ //
+ // Returns a pair containing the result of the evaluation, plus the
+ // expression remaining to be parsed.
+ std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr,
+ ParseContext PCtx) const {
+ EvalResult SubExprResult;
+ StringRef RemainingExpr;
+
+ if (Expr.empty())
+ return std::make_pair(EvalResult("Unexpected end of expression"), "");
+
+ if (Expr[0] == '(')
+ std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx);
+ else if (Expr[0] == '*')
+ std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);
+ else if (isalpha(Expr[0]) || Expr[0] == '_')
+ std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx);
+ else if (isdigit(Expr[0]))
+ std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
+ else
+ return std::make_pair(
+ unexpectedToken(Expr, Expr,
+ "expected '(', '*', identifier, or number"), "");
+
+ if (SubExprResult.hasError())
+ return std::make_pair(SubExprResult, RemainingExpr);
+
+ // Evaluate bit-slice if present.
+ if (RemainingExpr.startswith("["))
+ std::tie(SubExprResult, RemainingExpr) =
+ evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
+
+ return std::make_pair(SubExprResult, RemainingExpr);
+ }
+
+ // Evaluate a bit-slice of an expression.
+ // A bit-slice has the form "<expr>[high:low]". The result of evaluating a
+ // slice is the bits between high and low (inclusive) in the original
+ // expression, right shifted so that the "low" bit is in position 0 in the
+ // result.
+ // Returns a pair containing the result of the slice operation, plus the
+ // expression remaining to be parsed.
+ std::pair<EvalResult, StringRef>
+ evalSliceExpr(std::pair<EvalResult, StringRef> Ctx) const {
+ EvalResult SubExprResult;
+ StringRef RemainingExpr;
+ std::tie(SubExprResult, RemainingExpr) = Ctx;
+
+ assert(RemainingExpr.startswith("[") && "Not a slice expr.");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ EvalResult HighBitExpr;
+ std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
+
+ if (HighBitExpr.hasError())
+ return std::make_pair(HighBitExpr, RemainingExpr);
+
+ if (!RemainingExpr.startswith(":"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ EvalResult LowBitExpr;
+ std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
+
+ if (LowBitExpr.hasError())
+ return std::make_pair(LowBitExpr, RemainingExpr);
+
+ if (!RemainingExpr.startswith("]"))
+ return std::make_pair(
+ unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), "");
+ RemainingExpr = RemainingExpr.substr(1).ltrim();
+
+ unsigned HighBit = HighBitExpr.getValue();
+ unsigned LowBit = LowBitExpr.getValue();
+ uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1;
+ uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask;
+ return std::make_pair(EvalResult(SlicedValue), RemainingExpr);
+ }
+
+ // Evaluate a "complex" expression.
+ // Takes an already evaluated subexpression and checks for the presence of a
+ // binary operator, computing the result of the binary operation if one is
+ // found. Used to make arithmetic expressions left-associative.
+ // Returns a pair containing the ultimate result of evaluating the
+ // expression, plus the expression remaining to be evaluated.
+ std::pair<EvalResult, StringRef>
+ evalComplexExpr(std::pair<EvalResult, StringRef> LHSAndRemaining,
+ ParseContext PCtx) const {
+ EvalResult LHSResult;
+ StringRef RemainingExpr;
+ std::tie(LHSResult, RemainingExpr) = LHSAndRemaining;
+
+ // If there was an error, or there's nothing left to evaluate, return the
// result.
- // Returns a pair containing the result of the slice operation, plus the
- // expression remaining to be parsed.
- std::pair<EvalResult, StringRef> evalSliceExpr(
- std::pair<EvalResult, StringRef> Ctx) const{
- EvalResult SubExprResult;
- StringRef RemainingExpr;
- std::tie(SubExprResult, RemainingExpr) = Ctx;
-
- assert(RemainingExpr.startswith("[") && "Not a slice expr.");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- EvalResult HighBitExpr;
- std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
-
- if (HighBitExpr.hasError())
- return std::make_pair(HighBitExpr, RemainingExpr);
-
- if (!RemainingExpr.startswith(":"))
- return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr,
- "expected ':'"),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- EvalResult LowBitExpr;
- std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
-
- if (LowBitExpr.hasError())
- return std::make_pair(LowBitExpr, RemainingExpr);
-
- if (!RemainingExpr.startswith("]"))
- return std::make_pair(unexpectedToken(RemainingExpr, RemainingExpr,
- "expected ']'"),
- "");
- RemainingExpr = RemainingExpr.substr(1).ltrim();
-
- unsigned HighBit = HighBitExpr.getValue();
- unsigned LowBit = LowBitExpr.getValue();
- uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1;
- uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask;
- return std::make_pair(EvalResult(SlicedValue), RemainingExpr);
- }
+ if (LHSResult.hasError() || RemainingExpr == "")
+ return std::make_pair(LHSResult, RemainingExpr);
- // Evaluate a "complex" expression.
- // Takes an already evaluated subexpression and checks for the presence of a
- // binary operator, computing the result of the binary operation if one is
- // found. Used to make arithmetic expressions left-associative.
- // Returns a pair containing the ultimate result of evaluating the
- // expression, plus the expression remaining to be evaluated.
- std::pair<EvalResult, StringRef> evalComplexExpr(
- std::pair<EvalResult, StringRef> Ctx) const {
- EvalResult LHSResult;
- StringRef RemainingExpr;
- std::tie(LHSResult, RemainingExpr) = Ctx;
-
- // If there was an error, or there's nothing left to evaluate, return the
- // result.
- if (LHSResult.hasError() || RemainingExpr == "")
- return std::make_pair(LHSResult, RemainingExpr);
-
- // Otherwise check if this is a binary expressioan.
- BinOpToken BinOp;
- std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
-
- // If this isn't a recognized expression just return.
- if (BinOp == BinOpToken::Invalid)
- return std::make_pair(LHSResult, RemainingExpr);
-
- // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
- EvalResult RHSResult;
- std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr);
-
- // If there was an error evaluating the RHS, return it.
- if (RHSResult.hasError())
- return std::make_pair(RHSResult, RemainingExpr);
-
- // This is a binary expression - evaluate and try to continue as a
- // complex expr.
- EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));
-
- return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr));
- }
+ // Otherwise check if this is a binary expressioan.
+ BinOpToken BinOp;
+ std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
- bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const {
- MCDisassembler *Dis = Checker.Disassembler;
- StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol);
- StringRefMemoryObject SectionBytes(SectionMem, 0);
+ // If this isn't a recognized expression just return.
+ if (BinOp == BinOpToken::Invalid)
+ return std::make_pair(LHSResult, RemainingExpr);
- MCDisassembler::DecodeStatus S =
- Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls());
+ // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
+ EvalResult RHSResult;
+ std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx);
- return (S == MCDisassembler::Success);
- }
+ // If there was an error evaluating the RHS, return it.
+ if (RHSResult.hasError())
+ return std::make_pair(RHSResult, RemainingExpr);
- };
+ // This is a binary expression - evaluate and try to continue as a
+ // complex expr.
+ EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));
+
+ return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx);
+ }
+ bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const {
+ MCDisassembler *Dis = Checker.Disassembler;
+ StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol);
+ ArrayRef<uint8_t> SectionBytes(
+ reinterpret_cast<const uint8_t *>(SectionMem.data()),
+ SectionMem.size());
+
+ MCDisassembler::DecodeStatus S =
+ Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls());
+
+ return (S == MCDisassembler::Success);
+ }
+};
}
-bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
+RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld,
+ MCDisassembler *Disassembler,
+ MCInstPrinter *InstPrinter,
+ raw_ostream &ErrStream)
+ : RTDyld(RTDyld), Disassembler(Disassembler), InstPrinter(InstPrinter),
+ ErrStream(ErrStream) {
+ RTDyld.Checker = this;
+}
+
+bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const {
CheckExpr = CheckExpr.trim();
- DEBUG(llvm::dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
- << "'...\n");
+ DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr << "'...\n");
RuntimeDyldCheckerExprEval P(*this, ErrStream);
bool Result = P.evaluate(CheckExpr);
(void)Result;
- DEBUG(llvm::dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
- << (Result ? "passed" : "FAILED") << ".\n");
+ DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
+ << (Result ? "passed" : "FAILED") << ".\n");
return Result;
}
-bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
- MemoryBuffer* MemBuf) const {
+bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix,
+ MemoryBuffer *MemBuf) const {
bool DidAllTestsPass = true;
unsigned NumRules = 0;
const char *LineStart = MemBuf->getBufferStart();
// Eat whitespace.
- while (LineStart != MemBuf->getBufferEnd() &&
- std::isspace(*LineStart))
+ while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart))
++LineStart;
while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') {
const char *LineEnd = LineStart;
- while (LineEnd != MemBuf->getBufferEnd() &&
- *LineEnd != '\r' && *LineEnd != '\n')
+ while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' &&
+ *LineEnd != '\n')
++LineEnd;
StringRef Line(LineStart, LineEnd - LineStart);
@@ -605,37 +724,210 @@ bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
// Eat whitespace.
LineStart = LineEnd;
- while (LineStart != MemBuf->getBufferEnd() &&
- std::isspace(*LineStart))
+ while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart))
++LineStart;
}
return DidAllTestsPass && (NumRules != 0);
}
-bool RuntimeDyldChecker::checkSymbolIsValidForLoad(StringRef Symbol) const {
- return RTDyld.getSymbolAddress(Symbol) != nullptr;
+bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
+ return getRTDyld().getSymbolAddress(Symbol) != nullptr;
}
-uint64_t RuntimeDyldChecker::getSymbolAddress(StringRef Symbol) const {
- return RTDyld.getAnySymbolRemoteAddress(Symbol);
+uint64_t RuntimeDyldCheckerImpl::getSymbolLinkerAddr(StringRef Symbol) const {
+ return static_cast<uint64_t>(
+ reinterpret_cast<uintptr_t>(getRTDyld().getSymbolAddress(Symbol)));
}
-uint64_t RuntimeDyldChecker::readMemoryAtSymbol(StringRef Symbol,
- int64_t Offset,
- unsigned Size) const {
- uint8_t *Src = RTDyld.getSymbolAddress(Symbol);
- uint64_t Result = 0;
- memcpy(&Result, Src + Offset, Size);
- return Result;
+uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
+ return getRTDyld().getAnySymbolRemoteAddress(Symbol);
+}
+
+uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr,
+ unsigned Size) const {
+ uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr);
+ assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range.");
+ uint8_t *Src = reinterpret_cast<uint8_t*>(PtrSizedAddr);
+ return getRTDyld().readBytesUnaligned(Src, Size);
}
-StringRef RuntimeDyldChecker::getSubsectionStartingAt(StringRef Name) const {
+
+std::pair<const RuntimeDyldCheckerImpl::SectionAddressInfo*, std::string>
+RuntimeDyldCheckerImpl::findSectionAddrInfo(StringRef FileName,
+ StringRef SectionName) const {
+
+ auto SectionMapItr = Stubs.find(FileName);
+ if (SectionMapItr == Stubs.end()) {
+ std::string ErrorMsg = "File '";
+ ErrorMsg += FileName;
+ ErrorMsg += "' not found. ";
+ if (Stubs.empty())
+ ErrorMsg += "No stubs registered.";
+ else {
+ ErrorMsg += "Available files are:";
+ for (const auto& StubEntry : Stubs) {
+ ErrorMsg += " '";
+ ErrorMsg += StubEntry.first;
+ ErrorMsg += "'";
+ }
+ }
+ ErrorMsg += "\n";
+ return std::make_pair(nullptr, ErrorMsg);
+ }
+
+ auto SectionInfoItr = SectionMapItr->second.find(SectionName);
+ if (SectionInfoItr == SectionMapItr->second.end())
+ return std::make_pair(nullptr,
+ ("Section '" + SectionName + "' not found in file '" +
+ FileName + "'\n").str());
+
+ return std::make_pair(&SectionInfoItr->second, std::string(""));
+}
+
+std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
+ StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {
+
+ const SectionAddressInfo *SectionInfo = nullptr;
+ {
+ std::string ErrorMsg;
+ std::tie(SectionInfo, ErrorMsg) =
+ findSectionAddrInfo(FileName, SectionName);
+ if (ErrorMsg != "")
+ return std::make_pair(0, ErrorMsg);
+ }
+
+ unsigned SectionID = SectionInfo->SectionID;
+ uint64_t Addr;
+ if (IsInsideLoad)
+ Addr =
+ static_cast<uint64_t>(
+ reinterpret_cast<uintptr_t>(getRTDyld().Sections[SectionID].Address));
+ else
+ Addr = getRTDyld().Sections[SectionID].LoadAddress;
+
+ return std::make_pair(Addr, std::string(""));
+}
+
+std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubAddrFor(
+ StringRef FileName, StringRef SectionName, StringRef SymbolName,
+ bool IsInsideLoad) const {
+
+ const SectionAddressInfo *SectionInfo = nullptr;
+ {
+ std::string ErrorMsg;
+ std::tie(SectionInfo, ErrorMsg) =
+ findSectionAddrInfo(FileName, SectionName);
+ if (ErrorMsg != "")
+ return std::make_pair(0, ErrorMsg);
+ }
+
+ unsigned SectionID = SectionInfo->SectionID;
+ const StubOffsetsMap &SymbolStubs = SectionInfo->StubOffsets;
+ auto StubOffsetItr = SymbolStubs.find(SymbolName);
+ if (StubOffsetItr == SymbolStubs.end())
+ return std::make_pair(0,
+ ("Stub for symbol '" + SymbolName + "' not found. "
+ "If '" + SymbolName + "' is an internal symbol this "
+ "may indicate that the stub target offset is being "
+ "computed incorrectly.\n").str());
+
+ uint64_t StubOffset = StubOffsetItr->second;
+
+ uint64_t Addr;
+ if (IsInsideLoad) {
+ uintptr_t SectionBase =
+ reinterpret_cast<uintptr_t>(getRTDyld().Sections[SectionID].Address);
+ Addr = static_cast<uint64_t>(SectionBase) + StubOffset;
+ } else {
+ uint64_t SectionBase = getRTDyld().Sections[SectionID].LoadAddress;
+ Addr = SectionBase + StubOffset;
+ }
+
+ return std::make_pair(Addr, std::string(""));
+}
+
+StringRef
+RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const {
RuntimeDyldImpl::SymbolTableMap::const_iterator pos =
- RTDyld.GlobalSymbolTable.find(Name);
- if (pos == RTDyld.GlobalSymbolTable.end())
+ getRTDyld().GlobalSymbolTable.find(Name);
+ if (pos == getRTDyld().GlobalSymbolTable.end())
return StringRef();
RuntimeDyldImpl::SymbolLoc Loc = pos->second;
- uint8_t *SectionAddr = RTDyld.getSectionAddress(Loc.first);
- return StringRef(reinterpret_cast<const char*>(SectionAddr) + Loc.second,
- RTDyld.Sections[Loc.first].Size - Loc.second);
+ uint8_t *SectionAddr = getRTDyld().getSectionAddress(Loc.first);
+ return StringRef(reinterpret_cast<const char *>(SectionAddr) + Loc.second,
+ getRTDyld().Sections[Loc.first].Size - Loc.second);
+}
+
+void RuntimeDyldCheckerImpl::registerSection(
+ StringRef FilePath, unsigned SectionID) {
+ StringRef FileName = sys::path::filename(FilePath);
+ const SectionEntry &Section = getRTDyld().Sections[SectionID];
+ StringRef SectionName = Section.Name;
+
+ Stubs[FileName][SectionName].SectionID = SectionID;
+}
+
+void RuntimeDyldCheckerImpl::registerStubMap(
+ StringRef FilePath, unsigned SectionID,
+ const RuntimeDyldImpl::StubMap &RTDyldStubs) {
+ StringRef FileName = sys::path::filename(FilePath);
+ const SectionEntry &Section = getRTDyld().Sections[SectionID];
+ StringRef SectionName = Section.Name;
+
+ Stubs[FileName][SectionName].SectionID = SectionID;
+
+ for (auto &StubMapEntry : RTDyldStubs) {
+ std::string SymbolName = "";
+
+ if (StubMapEntry.first.SymbolName)
+ SymbolName = StubMapEntry.first.SymbolName;
+ else {
+ // If this is a (Section, Offset) pair, do a reverse lookup in the
+ // global symbol table to find the name.
+ for (auto &GSTEntry : getRTDyld().GlobalSymbolTable) {
+ if (GSTEntry.second.first == StubMapEntry.first.SectionID &&
+ GSTEntry.second.second ==
+ static_cast<uint64_t>(StubMapEntry.first.Offset)) {
+ SymbolName = GSTEntry.first();
+ break;
+ }
+ }
+ }
+
+ if (SymbolName != "")
+ Stubs[FileName][SectionName].StubOffsets[SymbolName] =
+ StubMapEntry.second;
+ }
+}
+
+RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld,
+ MCDisassembler *Disassembler,
+ MCInstPrinter *InstPrinter,
+ raw_ostream &ErrStream)
+ : Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler,
+ InstPrinter, ErrStream)) {}
+
+RuntimeDyldChecker::~RuntimeDyldChecker() {}
+
+RuntimeDyld& RuntimeDyldChecker::getRTDyld() {
+ return Impl->RTDyld;
+}
+
+const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const {
+ return Impl->RTDyld;
+}
+
+bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
+ return Impl->check(CheckExpr);
+}
+
+bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
+ MemoryBuffer *MemBuf) const {
+ return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);
+}
+
+std::pair<uint64_t, std::string>
+RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName,
+ bool LinkerAddress) {
+ return Impl->getSectionAddr(FileName, SectionName, LinkerAddress);
}
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
new file mode 100644
index 0000000..de20c1e
--- /dev/null
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
@@ -0,0 +1,76 @@
+//===-- RuntimeDyldCheckerImpl.h -- RuntimeDyld test framework --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H
+
+#include "RuntimeDyldImpl.h"
+#include <set>
+
+namespace llvm {
+
+class RuntimeDyldCheckerImpl {
+ friend class RuntimeDyldChecker;
+ friend class RuntimeDyldImpl;
+ friend class RuntimeDyldCheckerExprEval;
+
+public:
+ RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, MCDisassembler *Disassembler,
+ MCInstPrinter *InstPrinter,
+ llvm::raw_ostream &ErrStream);
+
+ bool check(StringRef CheckExpr) const;
+ bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
+
+private:
+
+ // StubMap typedefs.
+ typedef std::map<std::string, uint64_t> StubOffsetsMap;
+ struct SectionAddressInfo {
+ uint64_t SectionID;
+ StubOffsetsMap StubOffsets;
+ };
+ typedef std::map<std::string, SectionAddressInfo> SectionMap;
+ typedef std::map<std::string, SectionMap> StubMap;
+
+ RuntimeDyldImpl &getRTDyld() const { return *RTDyld.Dyld; }
+
+ bool isSymbolValid(StringRef Symbol) const;
+ uint64_t getSymbolLinkerAddr(StringRef Symbol) const;
+ uint64_t getSymbolRemoteAddr(StringRef Symbol) const;
+ uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const;
+
+ std::pair<const SectionAddressInfo*, std::string> findSectionAddrInfo(
+ StringRef FileName,
+ StringRef SectionName) const;
+
+ std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName,
+ StringRef SectionName,
+ bool IsInsideLoad) const;
+
+ std::pair<uint64_t, std::string> getStubAddrFor(StringRef FileName,
+ StringRef SectionName,
+ StringRef Symbol,
+ bool IsInsideLoad) const;
+ StringRef getSubsectionStartingAt(StringRef Name) const;
+
+ void registerSection(StringRef FilePath, unsigned SectionID);
+ void registerStubMap(StringRef FilePath, unsigned SectionID,
+ const RuntimeDyldImpl::StubMap &RTDyldStubs);
+
+ RuntimeDyld &RTDyld;
+ MCDisassembler *Disassembler;
+ MCInstPrinter *InstPrinter;
+ llvm::raw_ostream &ErrStream;
+
+ StubMap Stubs;
+};
+}
+
+#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 80e489c..d95cffe 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -23,6 +23,7 @@
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace llvm;
@@ -55,9 +56,9 @@ template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> {
public:
DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile,
- std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec);
+ MemoryBufferRef Wrapper, std::error_code &ec);
- DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper, std::error_code &ec);
+ DyldELFObject(MemoryBufferRef Wrapper, std::error_code &ec);
void updateSectionAddress(const SectionRef &Sec, uint64_t Addr);
void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr);
@@ -76,8 +77,10 @@ template <class ELFT> class ELFObjectImage : public ObjectImageCommon {
bool Registered;
public:
- ELFObjectImage(ObjectBuffer *Input, std::unique_ptr<DyldELFObject<ELFT>> Obj)
- : ObjectImageCommon(Input, std::move(Obj)), Registered(false) {}
+ ELFObjectImage(std::unique_ptr<ObjectBuffer> Input,
+ std::unique_ptr<DyldELFObject<ELFT>> Obj)
+ : ObjectImageCommon(std::move(Input), std::move(Obj)), Registered(false) {
+ }
virtual ~ELFObjectImage() {
if (Registered)
@@ -109,17 +112,15 @@ public:
// actual memory. Ultimately, the Binary parent class will take ownership of
// this MemoryBuffer object but not the underlying memory.
template <class ELFT>
-DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<MemoryBuffer> Wrapper,
- std::error_code &EC)
- : ELFObjectFile<ELFT>(std::move(Wrapper), EC) {
+DyldELFObject<ELFT>::DyldELFObject(MemoryBufferRef Wrapper, std::error_code &EC)
+ : ELFObjectFile<ELFT>(Wrapper, EC) {
this->isDyldELFObject = true;
}
template <class ELFT>
DyldELFObject<ELFT>::DyldELFObject(std::unique_ptr<ObjectFile> UnderlyingFile,
- std::unique_ptr<MemoryBuffer> Wrapper,
- std::error_code &EC)
- : ELFObjectFile<ELFT>(std::move(Wrapper), EC),
+ MemoryBufferRef Wrapper, std::error_code &EC)
+ : ELFObjectFile<ELFT>(Wrapper, EC),
UnderlyingFile(std::move(UnderlyingFile)) {
this->isDyldELFObject = true;
}
@@ -185,36 +186,36 @@ RuntimeDyldELF::createObjectImageFromFile(std::unique_ptr<object::ObjectFile> Ob
return nullptr;
std::error_code ec;
- std::unique_ptr<MemoryBuffer> Buffer(
- MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false));
+ MemoryBufferRef Buffer = ObjFile->getMemoryBufferRef();
if (ObjFile->getBytesInAddress() == 4 && ObjFile->isLittleEndian()) {
auto Obj =
llvm::make_unique<DyldELFObject<ELFType<support::little, 2, false>>>(
- std::move(ObjFile), std::move(Buffer), ec);
+ std::move(ObjFile), Buffer, ec);
return new ELFObjectImage<ELFType<support::little, 2, false>>(
nullptr, std::move(Obj));
} else if (ObjFile->getBytesInAddress() == 4 && !ObjFile->isLittleEndian()) {
auto Obj =
llvm::make_unique<DyldELFObject<ELFType<support::big, 2, false>>>(
- std::move(ObjFile), std::move(Buffer), ec);
+ std::move(ObjFile), Buffer, ec);
return new ELFObjectImage<ELFType<support::big, 2, false>>(nullptr, std::move(Obj));
} else if (ObjFile->getBytesInAddress() == 8 && !ObjFile->isLittleEndian()) {
auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 2, true>>>(
- std::move(ObjFile), std::move(Buffer), ec);
+ std::move(ObjFile), Buffer, ec);
return new ELFObjectImage<ELFType<support::big, 2, true>>(nullptr,
std::move(Obj));
} else if (ObjFile->getBytesInAddress() == 8 && ObjFile->isLittleEndian()) {
auto Obj =
llvm::make_unique<DyldELFObject<ELFType<support::little, 2, true>>>(
- std::move(ObjFile), std::move(Buffer), ec);
+ std::move(ObjFile), Buffer, ec);
return new ELFObjectImage<ELFType<support::little, 2, true>>(
nullptr, std::move(Obj));
} else
llvm_unreachable("Unexpected ELF format");
}
-ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) {
+std::unique_ptr<ObjectImage>
+RuntimeDyldELF::createObjectImage(std::unique_ptr<ObjectBuffer> Buffer) {
if (Buffer->getBufferSize() < ELF::EI_NIDENT)
llvm_unreachable("Unexpected ELF object size");
std::pair<unsigned char, unsigned char> Ident =
@@ -222,34 +223,36 @@ ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) {
(uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]);
std::error_code ec;
- std::unique_ptr<MemoryBuffer> Buf(Buffer->getMemBuffer());
+ MemoryBufferRef Buf = Buffer->getMemBuffer();
if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) {
auto Obj =
llvm::make_unique<DyldELFObject<ELFType<support::little, 4, false>>>(
- std::move(Buf), ec);
- return new ELFObjectImage<ELFType<support::little, 4, false>>(
- Buffer, std::move(Obj));
- } else if (Ident.first == ELF::ELFCLASS32 &&
- Ident.second == ELF::ELFDATA2MSB) {
+ Buf, ec);
+ return llvm::make_unique<
+ ELFObjectImage<ELFType<support::little, 4, false>>>(std::move(Buffer),
+ std::move(Obj));
+ }
+ if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) {
auto Obj =
- llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>(
- std::move(Buf), ec);
- return new ELFObjectImage<ELFType<support::big, 4, false>>(Buffer,
- std::move(Obj));
- } else if (Ident.first == ELF::ELFCLASS64 &&
- Ident.second == ELF::ELFDATA2MSB) {
+ llvm::make_unique<DyldELFObject<ELFType<support::big, 4, false>>>(Buf,
+ ec);
+ return llvm::make_unique<ELFObjectImage<ELFType<support::big, 4, false>>>(
+ std::move(Buffer), std::move(Obj));
+ }
+ if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) {
auto Obj = llvm::make_unique<DyldELFObject<ELFType<support::big, 8, true>>>(
- std::move(Buf), ec);
- return new ELFObjectImage<ELFType<support::big, 8, true>>(Buffer, std::move(Obj));
- } else if (Ident.first == ELF::ELFCLASS64 &&
- Ident.second == ELF::ELFDATA2LSB) {
- auto Obj =
- llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>(
- std::move(Buf), ec);
- return new ELFObjectImage<ELFType<support::little, 8, true>>(Buffer, std::move(Obj));
- } else
- llvm_unreachable("Unexpected ELF format");
+ Buf, ec);
+ return llvm::make_unique<ELFObjectImage<ELFType<support::big, 8, true>>>(
+ std::move(Buffer), std::move(Obj));
+ }
+ assert(Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB &&
+ "Unexpected ELF format");
+ auto Obj =
+ llvm::make_unique<DyldELFObject<ELFType<support::little, 8, true>>>(Buf,
+ ec);
+ return llvm::make_unique<ELFObjectImage<ELFType<support::little, 8, true>>>(
+ std::move(Buffer), std::move(Obj));
}
RuntimeDyldELF::~RuntimeDyldELF() {}
@@ -263,10 +266,9 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
llvm_unreachable("Relocation type not implemented yet!");
break;
case ELF::R_X86_64_64: {
- uint64_t *Target = reinterpret_cast<uint64_t *>(Section.Address + Offset);
- *Target = Value + Addend;
+ support::ulittle64_t::ref(Section.Address + Offset) = Value + Addend;
DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at "
- << format("%p\n", Target));
+ << format("%p\n", Section.Address + Offset));
break;
}
case ELF::R_X86_64_32:
@@ -276,17 +278,15 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
(Type == ELF::R_X86_64_32S &&
((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN)));
uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
- uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset);
- *Target = TruncatedAddr;
+ support::ulittle32_t::ref(Section.Address + Offset) = TruncatedAddr;
DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at "
- << format("%p\n", Target));
+ << format("%p\n", Section.Address + Offset));
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
@@ -294,30 +294,29 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress;
assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
- *Target = TruncOffset;
+ support::ulittle32_t::ref(Section.Address + Offset) = 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
- uint32_t *Placeholder =
- reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset);
- uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset);
+ support::ulittle32_t::ref Placeholder(
+ (void *)(Section.ObjAddress + Offset));
uint64_t FinalAddress = Section.LoadAddress + Offset;
- int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
+ int64_t RealOffset = Placeholder + Value + Addend - FinalAddress;
assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
- *Target = TruncOffset;
+ support::ulittle32_t::ref(Section.Address + Offset) = 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);
+ support::ulittle64_t::ref Placeholder(
+ (void *)(Section.ObjAddress + Offset));
uint64_t FinalAddress = Section.LoadAddress + Offset;
- *Target = *Placeholder + Value + Addend - FinalAddress;
+ support::ulittle64_t::ref(Section.Address + Offset) =
+ Placeholder + Value + Addend - FinalAddress;
break;
}
}
@@ -330,21 +329,20 @@ void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section,
case ELF::R_386_32: {
// Get the placeholder value from the generated object since
// a previous relocation attempt may have overwritten the loaded version
- uint32_t *Placeholder =
- reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset);
- uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset);
- *Target = *Placeholder + Value + Addend;
+ support::ulittle32_t::ref Placeholder(
+ (void *)(Section.ObjAddress + Offset));
+ support::ulittle32_t::ref(Section.Address + Offset) =
+ Placeholder + Value + Addend;
break;
}
case ELF::R_386_PC32: {
// Get the placeholder value from the generated object since
// a previous relocation attempt may have overwritten the loaded version
- uint32_t *Placeholder =
- reinterpret_cast<uint32_t *>(Section.ObjAddress + Offset);
- uint32_t *Target = reinterpret_cast<uint32_t *>(Section.Address + Offset);
+ support::ulittle32_t::ref Placeholder(
+ (void *)(Section.ObjAddress + Offset));
uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF);
- uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
- *Target = RealOffset;
+ uint32_t RealOffset = Placeholder + Value + Addend - FinalAddress;
+ support::ulittle32_t::ref(Section.Address + Offset) = RealOffset;
break;
}
default:
@@ -704,8 +702,7 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
section_iterator tsi(Obj.end_sections());
check(TargetSymbol->getSection(tsi));
- bool IsCode = false;
- tsi->isText(IsCode);
+ bool IsCode = tsi->isText();
Rel.SectionID = findOrEmitSection(Obj, (*tsi), IsCode, LocalSections);
Rel.Addend = (intptr_t)Addend;
return;
@@ -911,8 +908,6 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
break;
case Triple::aarch64:
case Triple::aarch64_be:
- case Triple::arm64:
- case Triple::arm64_be:
resolveAArch64Relocation(Section, Offset, Value, Type, Addend);
break;
case Triple::arm: // Fall through.
@@ -987,9 +982,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
if (si == Obj.end_sections())
llvm_unreachable("Symbol section not found, bad object file format!");
DEBUG(dbgs() << "\t\tThis is section symbol\n");
- // Default to 'true' in case isText fails (though it never does).
- bool isCode = true;
- si->isText(isCode);
+ bool isCode = si->isText();
Value.SectionID = findOrEmitSection(Obj, (*si), isCode, ObjSectionToID);
Value.Addend = Addend;
break;
@@ -1018,8 +1011,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset
<< "\n");
- if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be ||
- Arch == Triple::arm64 || Arch == Triple::arm64_be) &&
+ if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be) &&
(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.");
@@ -1141,6 +1133,10 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
}
} else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) {
if (RelType == ELF::R_PPC64_REL24) {
+ // Determine ABI variant in use for this object.
+ unsigned AbiVariant;
+ Obj.getObjectFile()->getPlatformFlags(AbiVariant);
+ AbiVariant &= ELF::EF_PPC64_ABI;
// A PPC branch relocation will need a stub function if the target is
// an external symbol (Symbol::ST_Unknown) or if the target address
// is not within the signed 24-bits branch address.
@@ -1148,10 +1144,18 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
uint8_t *Target = Section.Address + Offset;
bool RangeOverflow = false;
if (SymType != SymbolRef::ST_Unknown) {
- // A function call may points to the .opd entry, so the final symbol
- // value
- // in calculated based in the relocation values in .opd section.
- findOPDEntrySection(Obj, ObjSectionToID, Value);
+ if (AbiVariant != 2) {
+ // In the ELFv1 ABI, a function call may point to the .opd entry,
+ // so the final symbol value is calculated based on the relocation
+ // values in the .opd section.
+ findOPDEntrySection(Obj, ObjSectionToID, Value);
+ } else {
+ // In the ELFv2 ABI, a function symbol may provide a local entry
+ // point, which must be used for direct calls.
+ uint8_t SymOther;
+ Symbol->getOther(SymOther);
+ Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther);
+ }
uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend;
int32_t delta = static_cast<int32_t>(Target - RelocTarget);
// If it is within 24-bits branch range, just set the branch target
@@ -1179,7 +1183,8 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
DEBUG(dbgs() << " Create a new stub function\n");
Stubs[Value] = Section.StubOffset;
uint8_t *StubTargetAddr =
- createStubFunction(Section.Address + Section.StubOffset);
+ createStubFunction(Section.Address + Section.StubOffset,
+ AbiVariant);
RelocationEntry RE(SectionID, StubTargetAddr - Section.Address,
ELF::R_PPC64_ADDR64, Value.Addend);
@@ -1217,9 +1222,13 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
RelType, 0);
Section.StubOffset += getMaxStubSize();
}
- if (SymType == SymbolRef::ST_Unknown)
+ if (SymType == SymbolRef::ST_Unknown) {
// Restore the TOC for external calls
- writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1)
+ if (AbiVariant == 2)
+ writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1)
+ else
+ writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1)
+ }
}
} else if (RelType == ELF::R_PPC64_TOC16 ||
RelType == ELF::R_PPC64_TOC16_DS ||
@@ -1306,7 +1315,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
Stubs[Value] = StubOffset;
createStubFunction((uint8_t *)StubAddress);
RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64,
- Value.Addend - Addend);
+ Value.Offset);
if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
@@ -1414,8 +1423,6 @@ size_t RuntimeDyldELF::getGOTEntrySize() {
case Triple::x86_64:
case Triple::aarch64:
case Triple::aarch64_be:
- case Triple::arm64:
- case Triple::arm64_be:
case Triple::ppc64:
case Triple::ppc64le:
case Triple::systemz:
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
index 59fdfbe..4aeab81 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_RUNTIME_DYLD_ELF_H
-#define LLVM_RUNTIME_DYLD_ELF_H
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H
#include "RuntimeDyldImpl.h"
#include "llvm/ADT/DenseMap.h"
@@ -58,8 +58,7 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
uint64_t Value, uint32_t Type, int64_t Addend);
unsigned getMaxStubSize() override {
- if (Arch == Triple::aarch64 || Arch == Triple::arm64 ||
- Arch == Triple::aarch64_be || Arch == Triple::arm64_be)
+ if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be)
return 20; // movz; movk; movk; movk; br
if (Arch == Triple::arm || Arch == Triple::thumb)
return 8; // 32-bit instruction and 32-bit address
@@ -120,7 +119,8 @@ public:
ObjSectionToIDMap &SectionMap) override;
virtual ~RuntimeDyldELF();
- static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
+ static std::unique_ptr<ObjectImage>
+ createObjectImage(std::unique_ptr<ObjectBuffer> InputBuffer);
static ObjectImage *createObjectImageFromFile(std::unique_ptr<object::ObjectFile> Obj);
};
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index 0336cba..69ea3b4 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_RUNTIME_DYLD_IMPL_H
-#define LLVM_RUNTIME_DYLD_IMPL_H
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -70,7 +70,7 @@ public:
SectionEntry(StringRef name, uint8_t *address, size_t size,
uintptr_t objAddress)
: Name(name), Address(address), Size(size),
- LoadAddress((uintptr_t)address), StubOffset(size),
+ LoadAddress(reinterpret_cast<uintptr_t>(address)), StubOffset(size),
ObjAddress(objAddress) {}
};
@@ -159,7 +159,7 @@ public:
};
class RuntimeDyldImpl {
- friend class RuntimeDyldChecker;
+ friend class RuntimeDyldCheckerImpl;
private:
uint64_t getAnySymbolRemoteAddress(StringRef Symbol) {
@@ -172,6 +172,9 @@ protected:
// The MemoryManager to load objects into.
RTDyldMemoryManager *MemMgr;
+ // Attached RuntimeDyldChecker instance. Null if no instance attached.
+ RuntimeDyldCheckerImpl *Checker;
+
// A list of all sections emitted by the dynamic linker. These sections are
// referenced in the code by means of their index in this list - SectionID.
typedef SmallVector<SectionEntry, 64> SectionList;
@@ -211,6 +214,7 @@ protected:
// modules. This map is indexed by symbol name.
StringMap<RelocationList> ExternalSymbolRelocations;
+
typedef std::map<RelocationValueRef, uintptr_t> StubMap;
Triple::ArchType Arch;
@@ -245,11 +249,11 @@ protected:
return true;
}
- uint64_t getSectionLoadAddress(unsigned SectionID) {
+ uint64_t getSectionLoadAddress(unsigned SectionID) const {
return Sections[SectionID].LoadAddress;
}
- uint8_t *getSectionAddress(unsigned SectionID) {
+ uint8_t *getSectionAddress(unsigned SectionID) const {
return (uint8_t *)Sections[SectionID].Address;
}
@@ -282,6 +286,13 @@ protected:
*(Addr + 7) = Value & 0xFF;
}
+ /// Endian-aware read Read the least significant Size bytes from Src.
+ uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const;
+
+ /// Endian-aware write. Write the least significant Size bytes from Value to
+ /// Dst.
+ void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const;
+
/// \brief Given the common symbols discovered in the object file, emit a
/// new section for them and update the symbol mappings in the object and
/// symbol table.
@@ -312,7 +323,7 @@ protected:
/// \brief Emits long jump instruction to Addr.
/// \return Pointer to the memory area for emitting target address.
- uint8_t *createStubFunction(uint8_t *Addr);
+ uint8_t *createStubFunction(uint8_t *Addr, unsigned AbiVariant = 0);
/// \brief Resolves relocations from Relocs list with address from Value.
void resolveRelocationList(const RelocationList &Relocs, uint64_t Value);
@@ -349,7 +360,7 @@ protected:
public:
RuntimeDyldImpl(RTDyldMemoryManager *mm)
- : MemMgr(mm), ProcessAllSections(false), HasError(false) {
+ : MemMgr(mm), Checker(nullptr), ProcessAllSections(false), HasError(false) {
}
virtual ~RuntimeDyldImpl();
@@ -358,9 +369,14 @@ public:
this->ProcessAllSections = ProcessAllSections;
}
- ObjectImage *loadObject(ObjectImage *InputObject);
+ void setRuntimeDyldChecker(RuntimeDyldCheckerImpl *Checker) {
+ this->Checker = Checker;
+ }
+
+ std::unique_ptr<ObjectImage>
+ loadObject(std::unique_ptr<ObjectImage> InputObject);
- uint8_t* getSymbolAddress(StringRef Name) {
+ uint8_t* getSymbolAddress(StringRef Name) const {
// FIXME: Just look up as a function for now. Overly simple of course.
// Work in progress.
SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name);
@@ -370,7 +386,7 @@ public:
return getSectionAddress(Loc.first) + Loc.second;
}
- uint64_t getSymbolLoadAddress(StringRef Name) {
+ uint64_t getSymbolLoadAddress(StringRef Name) const {
// FIXME: Just look up as a function for now. Overly simple of course.
// Work in progress.
SymbolTableMap::const_iterator pos = GlobalSymbolTable.find(Name);
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
index 4eb516c..d3d6f5d 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
@@ -14,8 +14,12 @@
#include "RuntimeDyldMachO.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "ObjectImageCommon.h"
-#include "JITRegistrar.h"
+
+#include "Targets/RuntimeDyldMachOARM.h"
+#include "Targets/RuntimeDyldMachOAArch64.h"
+#include "Targets/RuntimeDyldMachOI386.h"
+#include "Targets/RuntimeDyldMachOX86_64.h"
+
using namespace llvm;
using namespace llvm::object;
@@ -23,164 +27,231 @@ using namespace llvm::object;
namespace llvm {
-class MachOObjectImage : public ObjectImageCommon {
-private:
- typedef SmallVector<uint64_t, 1> SectionAddrList;
- SectionAddrList OldSectionAddrList;
-
-protected:
- bool is64;
- bool Registered;
-
-private:
- void initOldAddress() {
- MachOObjectFile *objf = static_cast<MachOObjectFile *>(ObjFile.get());
- // Unfortunately we need to do this, since there's information encoded
- // in the original addr of the section that we could not otherwise
- // recover. The reason for this is that symbols do not actually store
- // their file offset, but only their vmaddr. This means that in order
- // to locate the symbol correctly in the object file, we need to know
- // where the original start of the section was (including any padding,
- // etc).
- for (section_iterator i = objf->section_begin(), e = objf->section_end();
- i != e; ++i) {
- uint64_t Addr;
- i->getAddress(Addr);
- OldSectionAddrList[i->getRawDataRefImpl().d.a] = Addr;
+int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const {
+ unsigned NumBytes = 1 << RE.Size;
+ uint8_t *Src = Sections[RE.SectionID].Address + RE.Offset;
+
+ return static_cast<int64_t>(readBytesUnaligned(Src, NumBytes));
+}
+
+RelocationValueRef RuntimeDyldMachO::getRelocationValueRef(
+ ObjectImage &ObjImg, const relocation_iterator &RI,
+ const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID,
+ const SymbolTableMap &Symbols) {
+
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RI->getRawDataRefImpl());
+ RelocationValueRef Value;
+
+ bool IsExternal = Obj.getPlainRelocationExternal(RelInfo);
+ if (IsExternal) {
+ symbol_iterator Symbol = RI->getSymbol();
+ StringRef TargetName;
+ Symbol->getName(TargetName);
+ SymbolTableMap::const_iterator SI = Symbols.find(TargetName.data());
+ if (SI != Symbols.end()) {
+ Value.SectionID = SI->second.first;
+ Value.Offset = SI->second.second + RE.Addend;
+ } else {
+ SI = GlobalSymbolTable.find(TargetName.data());
+ if (SI != GlobalSymbolTable.end()) {
+ Value.SectionID = SI->second.first;
+ Value.Offset = SI->second.second + RE.Addend;
+ } else {
+ Value.SymbolName = TargetName.data();
+ Value.Offset = RE.Addend;
+ }
}
+ } else {
+ SectionRef Sec = Obj.getRelocationSection(RelInfo);
+ bool IsCode = Sec.isText();
+ Value.SectionID = findOrEmitSection(ObjImg, Sec, IsCode, ObjSectionToID);
+ uint64_t Addr = Sec.getAddress();
+ Value.Offset = RE.Addend - Addr;
}
-public:
- MachOObjectImage(ObjectBuffer *Input, bool is64)
- : ObjectImageCommon(Input),
- OldSectionAddrList(ObjFile->section_end()->getRawDataRefImpl().d.a, 0),
- is64(is64), Registered(false) {
- initOldAddress();
- }
+ return Value;
+}
- MachOObjectImage(std::unique_ptr<object::ObjectFile> Input, bool is64)
- : ObjectImageCommon(std::move(Input)),
- OldSectionAddrList(ObjFile->section_end()->getRawDataRefImpl().d.a, 0),
- is64(is64), Registered(false) {
- initOldAddress();
+void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value,
+ ObjectImage &ObjImg,
+ const relocation_iterator &RI,
+ unsigned OffsetToNextPC) {
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RI->getRawDataRefImpl());
+
+ bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo);
+ if (IsPCRel) {
+ uint64_t RelocAddr = 0;
+ RI->getAddress(RelocAddr);
+ Value.Offset += RelocAddr + OffsetToNextPC;
}
+}
+
+void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE,
+ uint64_t Value) const {
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+ uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+
+ dbgs() << "resolveRelocation Section: " << RE.SectionID
+ << " LocalAddress: " << format("%p", LocalAddress)
+ << " FinalAddress: " << format("0x%016" PRIx64, FinalAddress)
+ << " Value: " << format("0x%016" PRIx64, Value) << " Addend: " << RE.Addend
+ << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType
+ << " Size: " << (1 << RE.Size) << "\n";
+}
- virtual ~MachOObjectImage() {
- if (Registered)
- deregisterWithDebugger();
+section_iterator
+RuntimeDyldMachO::getSectionByAddress(const MachOObjectFile &Obj,
+ uint64_t Addr) {
+ section_iterator SI = Obj.section_begin();
+ section_iterator SE = Obj.section_end();
+
+ for (; SI != SE; ++SI) {
+ uint64_t SAddr = SI->getAddress();
+ uint64_t SSize = SI->getSize();
+ if ((Addr >= SAddr) && (Addr < SAddr + SSize))
+ return SI;
}
- // Subclasses can override these methods to update the image with loaded
- // addresses for sections and common symbols
- virtual void updateSectionAddress(const SectionRef &Sec, uint64_t Addr) {
- MachOObjectFile *objf = static_cast<MachOObjectFile *>(ObjFile.get());
- char *data =
- const_cast<char *>(objf->getSectionPointer(Sec.getRawDataRefImpl()));
+ return SE;
+}
- uint64_t oldAddr = OldSectionAddrList[Sec.getRawDataRefImpl().d.a];
- if (is64) {
- ((MachO::section_64 *)data)->addr = Addr;
- } else {
- ((MachO::section *)data)->addr = Addr;
- }
+// Populate __pointers section.
+void RuntimeDyldMachO::populateIndirectSymbolPointersSection(
+ MachOObjectFile &Obj,
+ const SectionRef &PTSection,
+ unsigned PTSectionID) {
+ assert(!Obj.is64Bit() &&
+ "Pointer table section not supported in 64-bit MachO.");
- for (symbol_iterator i = objf->symbol_begin(), e = objf->symbol_end();
- i != e; ++i) {
- section_iterator symSec(objf->section_end());
- (*i).getSection(symSec);
- if (*symSec == Sec) {
- uint64_t symAddr;
- (*i).getAddress(symAddr);
- updateSymbolAddress(*i, symAddr + Addr - oldAddr);
- }
- }
- }
+ MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
+ MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl());
+ uint32_t PTSectionSize = Sec32.size;
+ unsigned FirstIndirectSymbol = Sec32.reserved1;
+ const unsigned PTEntrySize = 4;
+ unsigned NumPTEntries = PTSectionSize / PTEntrySize;
+ unsigned PTEntryOffset = 0;
- uint64_t getOldSectionAddr(const SectionRef &Sec) const {
- return OldSectionAddrList[Sec.getRawDataRefImpl().d.a];
- }
+ assert((PTSectionSize % PTEntrySize) == 0 &&
+ "Pointers section does not contain a whole number of stubs?");
- virtual void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) {
- char *data = const_cast<char *>(
- reinterpret_cast<const char *>(Sym.getRawDataRefImpl().p));
- if (is64)
- ((MachO::nlist_64 *)data)->n_value = Addr;
- else
- ((MachO::nlist *)data)->n_value = Addr;
- }
+ DEBUG(dbgs() << "Populating pointer table section "
+ << Sections[PTSectionID].Name
+ << ", Section ID " << PTSectionID << ", "
+ << NumPTEntries << " entries, " << PTEntrySize
+ << " bytes each:\n");
- virtual void registerWithDebugger() {
- JITRegistrar::getGDBRegistrar().registerObject(*Buffer);
- Registered = true;
+ for (unsigned i = 0; i < NumPTEntries; ++i) {
+ unsigned SymbolIndex =
+ Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
+ symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
+ StringRef IndirectSymbolName;
+ SI->getName(IndirectSymbolName);
+ DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex
+ << ", PT offset: " << PTEntryOffset << "\n");
+ RelocationEntry RE(PTSectionID, PTEntryOffset,
+ MachO::GENERIC_RELOC_VANILLA, 0, false, 2);
+ addRelocationForSymbol(RE, IndirectSymbolName);
+ PTEntryOffset += PTEntrySize;
}
+}
- virtual void deregisterWithDebugger() {
- JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer);
- }
-};
-
-ObjectImage *RuntimeDyldMachO::createObjectImage(ObjectBuffer *Buffer) {
- uint32_t magic = *((const uint32_t *)Buffer->getBufferStart());
- bool is64 = (magic == MachO::MH_MAGIC_64);
- assert((magic == MachO::MH_MAGIC_64 || magic == MachO::MH_MAGIC) &&
- "Unrecognized Macho Magic");
- return new MachOObjectImage(Buffer, is64);
+bool
+RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const {
+ if (InputBuffer->getBufferSize() < 4)
+ return false;
+ StringRef Magic(InputBuffer->getBufferStart(), 4);
+ if (Magic == "\xFE\xED\xFA\xCE")
+ return true;
+ if (Magic == "\xCE\xFA\xED\xFE")
+ return true;
+ if (Magic == "\xFE\xED\xFA\xCF")
+ return true;
+ if (Magic == "\xCF\xFA\xED\xFE")
+ return true;
+ return false;
}
-ObjectImage *RuntimeDyldMachO::createObjectImageFromFile(
- std::unique_ptr<object::ObjectFile> ObjFile) {
- if (!ObjFile)
- return nullptr;
+bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const {
+ return Obj->isMachO();
+}
- MemoryBuffer *Buffer =
- MemoryBuffer::getMemBuffer(ObjFile->getData(), "", false);
+template <typename Impl>
+void RuntimeDyldMachOCRTPBase<Impl>::finalizeLoad(ObjectImage &ObjImg,
+ ObjSectionToIDMap &SectionMap) {
+ unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID;
+ unsigned TextSID = RTDYLD_INVALID_SECTION_ID;
+ unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID;
+ ObjSectionToIDMap::iterator i, e;
- uint32_t magic = *((const uint32_t *)Buffer->getBufferStart());
- bool is64 = (magic == MachO::MH_MAGIC_64);
- assert((magic == MachO::MH_MAGIC_64 || magic == MachO::MH_MAGIC) &&
- "Unrecognized Macho Magic");
- return new MachOObjectImage(std::move(ObjFile), is64);
+ 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;
+ else
+ impl().finalizeSection(ObjImg, i->second, Section);
+ }
+ UnregisteredEHFrameSections.push_back(
+ EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID));
}
-static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText,
- intptr_t DeltaForEH) {
+template <typename Impl>
+unsigned char *RuntimeDyldMachOCRTPBase<Impl>::processFDE(unsigned char *P,
+ int64_t DeltaForText,
+ int64_t DeltaForEH) {
+ typedef typename Impl::TargetPtrT TargetPtrT;
+
DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText
<< ", Delta for EH: " << DeltaForEH << "\n");
- uint32_t Length = *((uint32_t *)P);
+ uint32_t Length = readBytesUnaligned(P, 4);
P += 4;
unsigned char *Ret = P + Length;
- uint32_t Offset = *((uint32_t *)P);
+ uint32_t Offset = readBytesUnaligned(P, 4);
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);
+ TargetPtrT FDELocation = readBytesUnaligned(P, sizeof(TargetPtrT));
+ TargetPtrT NewLocation = FDELocation - DeltaForText;
+ writeBytesUnaligned(NewLocation, P, sizeof(TargetPtrT));
+
+ P += sizeof(TargetPtrT);
// Skip the FDE address range
- P += sizeof(intptr_t);
+ P += sizeof(TargetPtrT);
uint8_t Augmentationsize = *P;
P += 1;
if (Augmentationsize != 0) {
- intptr_t LSDA = *((intptr_t *)P);
- intptr_t NewLSDA = LSDA - DeltaForEH;
- *((intptr_t *)P) = NewLSDA;
+ TargetPtrT LSDA = readBytesUnaligned(P, sizeof(TargetPtrT));
+ TargetPtrT NewLSDA = LSDA - DeltaForEH;
+ writeBytesUnaligned(NewLSDA, P, sizeof(TargetPtrT));
}
return Ret;
}
-static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) {
- intptr_t ObjDistance = A->ObjAddress - B->ObjAddress;
- intptr_t MemDistance = A->LoadAddress - B->LoadAddress;
+static int64_t computeDelta(SectionEntry *A, SectionEntry *B) {
+ int64_t ObjDistance = A->ObjAddress - B->ObjAddress;
+ int64_t MemDistance = A->LoadAddress - B->LoadAddress;
return ObjDistance - MemDistance;
}
-void RuntimeDyldMachO::registerEHFrames() {
+template <typename Impl>
+void RuntimeDyldMachOCRTPBase<Impl>::registerEHFrames() {
if (!MemMgr)
return;
@@ -195,8 +266,8 @@ void RuntimeDyldMachO::registerEHFrames() {
if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID)
ExceptTab = &Sections[SectionInfo.ExceptTabSID];
- intptr_t DeltaForText = computeDelta(Text, EHFrame);
- intptr_t DeltaForEH = 0;
+ int64_t DeltaForText = computeDelta(Text, EHFrame);
+ int64_t DeltaForEH = 0;
if (ExceptTab)
DeltaForEH = computeDelta(ExceptTab, EHFrame);
@@ -212,615 +283,17 @@ void RuntimeDyldMachO::registerEHFrames() {
UnregisteredEHFrameSections.clear();
}
-void RuntimeDyldMachO::finalizeLoad(ObjectImage &ObjImg,
- 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;
- else if (Name == "__jump_table")
- populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
- Section, i->second);
- else if (Name == "__pointers")
- populatePointersSection(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
- Section, 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) {
- DEBUG (
- const SectionEntry &Section = Sections[RE.SectionID];
- uint8_t* LocalAddress = Section.Address + RE.Offset;
- uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
-
- dbgs() << "resolveRelocation Section: " << RE.SectionID
- << " LocalAddress: " << format("%p", LocalAddress)
- << " FinalAddress: " << format("%p", FinalAddress)
- << " Value: " << format("%p", Value)
- << " Addend: " << RE.Addend
- << " isPCRel: " << RE.IsPCRel
- << " MachoType: " << RE.RelType
- << " Size: " << (1 << RE.Size) << "\n";
- );
-
- // This just dispatches to the proper target specific routine.
+std::unique_ptr<RuntimeDyldMachO>
+llvm::RuntimeDyldMachO::create(Triple::ArchType Arch, RTDyldMemoryManager *MM) {
switch (Arch) {
default:
- llvm_unreachable("Unsupported CPU type!");
- case Triple::x86_64:
- resolveX86_64Relocation(RE, Value);
- break;
- case Triple::x86:
- resolveI386Relocation(RE, Value);
- break;
- case Triple::arm: // Fall through.
- case Triple::thumb:
- resolveARMRelocation(RE, Value);
- break;
- case Triple::aarch64:
- case Triple::arm64:
- resolveAArch64Relocation(RE, Value);
- break;
- }
-}
-
-bool RuntimeDyldMachO::resolveI386Relocation(const RelocationEntry &RE,
- uint64_t Value) {
- const SectionEntry &Section = Sections[RE.SectionID];
- uint8_t* LocalAddress = Section.Address + RE.Offset;
-
- if (RE.IsPCRel) {
- uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
- Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
- }
-
- switch (RE.RelType) {
- default:
- llvm_unreachable("Invalid relocation type!");
- case MachO::GENERIC_RELOC_VANILLA:
- return applyRelocationValue(LocalAddress, Value + RE.Addend,
- 1 << RE.Size);
- case MachO::GENERIC_RELOC_SECTDIFF:
- case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
- uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
- uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
- assert((Value == SectionABase || Value == SectionBBase) &&
- "Unexpected SECTDIFF relocation value.");
- Value = SectionABase - SectionBBase + RE.Addend;
- return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
- }
- case MachO::GENERIC_RELOC_PB_LA_PTR:
- return Error("Relocation type not implemented yet!");
- }
-}
-
-bool RuntimeDyldMachO::resolveX86_64Relocation(const RelocationEntry &RE,
- uint64_t Value) {
- const SectionEntry &Section = Sections[RE.SectionID];
- uint8_t* LocalAddress = Section.Address + RE.Offset;
-
- // If the relocation is PC-relative, the value to be encoded is the
- // pointer difference.
- if (RE.IsPCRel) {
- // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
- // address. Is that expected? Only for branches, perhaps?
- uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
- Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
- }
-
- switch (RE.RelType) {
- default:
- llvm_unreachable("Invalid relocation type!");
- 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:
- return applyRelocationValue(LocalAddress, Value + RE.Addend, 1 << RE.Size);
- 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!");
- }
-}
-
-bool RuntimeDyldMachO::resolveARMRelocation(const RelocationEntry &RE,
- uint64_t Value) {
- const SectionEntry &Section = Sections[RE.SectionID];
- uint8_t* LocalAddress = Section.Address + RE.Offset;
-
- // If the relocation is PC-relative, the value to be encoded is the
- // pointer difference.
- if (RE.IsPCRel) {
- uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
- Value -= FinalAddress;
- // ARM PCRel relocations have an effective-PC offset of two instructions
- // (four bytes in Thumb mode, 8 bytes in ARM mode).
- // FIXME: For now, assume ARM mode.
- Value -= 8;
- }
-
- switch (RE.RelType) {
- default:
- llvm_unreachable("Invalid relocation type!");
- case MachO::ARM_RELOC_VANILLA:
- return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
- 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;
- // The low two bits of the value are not encoded.
- Value >>= 2;
- // Mask the value to 24 bits.
- uint64_t FinalValue = Value & 0xffffff;
- // Check for overflow.
- if (Value != FinalValue)
- return Error("ARM BR24 relocation out of range.");
- // FIXME: If the destination is a Thumb function (and the instruction
- // is a non-predicated BL instruction), we need to change it to a BLX
- // instruction instead.
-
- // Insert the value into the instruction.
- *p = (*p & ~0xffffff) | FinalValue;
+ llvm_unreachable("Unsupported target for RuntimeDyldMachO.");
break;
+ case Triple::arm: return make_unique<RuntimeDyldMachOARM>(MM);
+ case Triple::aarch64: return make_unique<RuntimeDyldMachOAArch64>(MM);
+ case Triple::x86: return make_unique<RuntimeDyldMachOI386>(MM);
+ case Triple::x86_64: return make_unique<RuntimeDyldMachOX86_64>(MM);
}
- 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;
-}
-
-bool RuntimeDyldMachO::resolveAArch64Relocation(const RelocationEntry &RE,
- uint64_t Value) {
- const SectionEntry &Section = Sections[RE.SectionID];
- uint8_t* LocalAddress = Section.Address + RE.Offset;
-
- // If the relocation is PC-relative, the value to be encoded is the
- // pointer difference.
- if (RE.IsPCRel) {
- uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
- Value -= FinalAddress;
- }
-
- switch (RE.RelType) {
- default:
- llvm_unreachable("Invalid relocation type!");
- case MachO::ARM64_RELOC_UNSIGNED:
- return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
- case MachO::ARM64_RELOC_BRANCH26: {
- // 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;
- // The low two bits of the value are not encoded.
- Value >>= 2;
- // Mask the value to 26 bits.
- uint64_t FinalValue = Value & 0x3ffffff;
- // Check for overflow.
- if (FinalValue != Value)
- return Error("ARM64 BRANCH26 relocation out of range.");
- // Insert the value into the instruction.
- *p = (*p & ~0x3ffffff) | FinalValue;
- break;
- }
- case MachO::ARM64_RELOC_SUBTRACTOR:
- case MachO::ARM64_RELOC_PAGE21:
- case MachO::ARM64_RELOC_PAGEOFF12:
- case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
- case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
- case MachO::ARM64_RELOC_POINTER_TO_GOT:
- case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
- case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
- case MachO::ARM64_RELOC_ADDEND:
- return Error("Relocation type not implemented yet!");
- }
- return false;
-}
-
-void RuntimeDyldMachO::populateJumpTable(MachOObjectFile &Obj,
- const SectionRef &JTSection,
- unsigned JTSectionID) {
- assert(!Obj.is64Bit() &&
- "__jump_table section not supported in 64-bit MachO.");
-
- MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
- MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
- uint32_t JTSectionSize = Sec32.size;
- unsigned FirstIndirectSymbol = Sec32.reserved1;
- unsigned JTEntrySize = Sec32.reserved2;
- unsigned NumJTEntries = JTSectionSize / JTEntrySize;
- uint8_t* JTSectionAddr = getSectionAddress(JTSectionID);
- unsigned JTEntryOffset = 0;
-
- assert((JTSectionSize % JTEntrySize) == 0 &&
- "Jump-table section does not contain a whole number of stubs?");
-
- for (unsigned i = 0; i < NumJTEntries; ++i) {
- unsigned SymbolIndex =
- Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
- symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
- StringRef IndirectSymbolName;
- SI->getName(IndirectSymbolName);
- uint8_t* JTEntryAddr = JTSectionAddr + JTEntryOffset;
- createStubFunction(JTEntryAddr);
- RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
- MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
- addRelocationForSymbol(RE, IndirectSymbolName);
- JTEntryOffset += JTEntrySize;
- }
-}
-
-void RuntimeDyldMachO::populatePointersSection(MachOObjectFile &Obj,
- const SectionRef &PTSection,
- unsigned PTSectionID) {
- assert(!Obj.is64Bit() &&
- "__pointers section not supported in 64-bit MachO.");
-
- MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
- MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl());
- uint32_t PTSectionSize = Sec32.size;
- unsigned FirstIndirectSymbol = Sec32.reserved1;
- const unsigned PTEntrySize = 4;
- unsigned NumPTEntries = PTSectionSize / PTEntrySize;
- unsigned PTEntryOffset = 0;
-
- assert((PTSectionSize % PTEntrySize) == 0 &&
- "Pointers section does not contain a whole number of stubs?");
-
- DEBUG(dbgs() << "Populating __pointers, Section ID " << PTSectionID
- << ", " << NumPTEntries << " entries, "
- << PTEntrySize << " bytes each:\n");
-
- for (unsigned i = 0; i < NumPTEntries; ++i) {
- unsigned SymbolIndex =
- Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
- symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
- StringRef IndirectSymbolName;
- SI->getName(IndirectSymbolName);
- DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex
- << ", PT offset: " << PTEntryOffset << "\n");
- RelocationEntry RE(PTSectionID, PTEntryOffset,
- MachO::GENERIC_RELOC_VANILLA, 0, false, 2);
- addRelocationForSymbol(RE, IndirectSymbolName);
- PTEntryOffset += PTEntrySize;
- }
-}
-
-
-section_iterator getSectionByAddress(const MachOObjectFile &Obj,
- uint64_t Addr) {
- section_iterator SI = Obj.section_begin();
- section_iterator SE = Obj.section_end();
-
- for (; SI != SE; ++SI) {
- uint64_t SAddr, SSize;
- SI->getAddress(SAddr);
- SI->getSize(SSize);
- if ((Addr >= SAddr) && (Addr < SAddr + SSize))
- return SI;
- }
-
- return SE;
-}
-
-relocation_iterator RuntimeDyldMachO::processSECTDIFFRelocation(
- unsigned SectionID,
- relocation_iterator RelI,
- ObjectImage &Obj,
- ObjSectionToIDMap &ObjSectionToID) {
- const MachOObjectFile *MachO =
- static_cast<const MachOObjectFile*>(Obj.getObjectFile());
- MachO::any_relocation_info RE =
- MachO->getRelocation(RelI->getRawDataRefImpl());
-
- SectionEntry &Section = Sections[SectionID];
- uint32_t RelocType = MachO->getAnyRelocationType(RE);
- bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
- unsigned Size = MachO->getAnyRelocationLength(RE);
- uint64_t Offset;
- RelI->getOffset(Offset);
- uint8_t *LocalAddress = Section.Address + Offset;
- unsigned NumBytes = 1 << Size;
- int64_t Addend = 0;
- memcpy(&Addend, LocalAddress, NumBytes);
-
- ++RelI;
- MachO::any_relocation_info RE2 =
- MachO->getRelocation(RelI->getRawDataRefImpl());
-
- uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
- section_iterator SAI = getSectionByAddress(*MachO, AddrA);
- assert(SAI != MachO->section_end() && "Can't find section for address A");
- uint64_t SectionABase;
- SAI->getAddress(SectionABase);
- uint64_t SectionAOffset = AddrA - SectionABase;
- SectionRef SectionA = *SAI;
- bool IsCode;
- SectionA.isText(IsCode);
- uint32_t SectionAID = findOrEmitSection(Obj, SectionA, IsCode,
- ObjSectionToID);
-
- uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
- section_iterator SBI = getSectionByAddress(*MachO, AddrB);
- assert(SBI != MachO->section_end() && "Can't find section for address B");
- uint64_t SectionBBase;
- SBI->getAddress(SectionBBase);
- uint64_t SectionBOffset = AddrB - SectionBBase;
- SectionRef SectionB = *SBI;
- uint32_t SectionBID = findOrEmitSection(Obj, SectionB, IsCode,
- ObjSectionToID);
-
- if (Addend != AddrA - AddrB)
- Error("Unexpected SECTDIFF relocation addend.");
-
- DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
- << ", Addend: " << Addend << ", SectionA ID: "
- << SectionAID << ", SectionAOffset: " << SectionAOffset
- << ", SectionB ID: " << SectionBID << ", SectionBOffset: "
- << SectionBOffset << "\n");
- RelocationEntry R(SectionID, Offset, RelocType, 0,
- SectionAID, SectionAOffset, SectionBID, SectionBOffset,
- IsPCRel, Size);
-
- addRelocationForSection(R, SectionAID);
- addRelocationForSection(R, SectionBID);
-
- return ++RelI;
-}
-
-relocation_iterator RuntimeDyldMachO::processI386ScatteredVANILLA(
- unsigned SectionID,
- relocation_iterator RelI,
- ObjectImage &Obj,
- ObjSectionToIDMap &ObjSectionToID) {
- const MachOObjectFile *MachO =
- static_cast<const MachOObjectFile*>(Obj.getObjectFile());
- MachO::any_relocation_info RE =
- MachO->getRelocation(RelI->getRawDataRefImpl());
-
- SectionEntry &Section = Sections[SectionID];
- uint32_t RelocType = MachO->getAnyRelocationType(RE);
- bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
- unsigned Size = MachO->getAnyRelocationLength(RE);
- uint64_t Offset;
- RelI->getOffset(Offset);
- uint8_t *LocalAddress = Section.Address + Offset;
- unsigned NumBytes = 1 << Size;
- int64_t Addend = 0;
- memcpy(&Addend, LocalAddress, NumBytes);
-
- unsigned SymbolBaseAddr = MachO->getScatteredRelocationValue(RE);
- section_iterator TargetSI = getSectionByAddress(*MachO, SymbolBaseAddr);
- assert(TargetSI != MachO->section_end() && "Can't find section for symbol");
- uint64_t SectionBaseAddr;
- TargetSI->getAddress(SectionBaseAddr);
- SectionRef TargetSection = *TargetSI;
- bool IsCode;
- TargetSection.isText(IsCode);
- uint32_t TargetSectionID = findOrEmitSection(Obj, TargetSection, IsCode,
- ObjSectionToID);
-
- Addend -= SectionBaseAddr;
- RelocationEntry R(SectionID, Offset, RelocType, Addend,
- IsPCRel, Size);
-
- addRelocationForSection(R, TargetSectionID);
-
- return ++RelI;
-}
-
-relocation_iterator RuntimeDyldMachO::processRelocationRef(
- unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj,
- ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols,
- StubMap &Stubs) {
- const ObjectFile *OF = Obj.getObjectFile();
- const MachOObjectImage &MachOObj = *static_cast<MachOObjectImage *>(&Obj);
- const MachOObjectFile *MachO = static_cast<const MachOObjectFile *>(OF);
- MachO::any_relocation_info RE =
- MachO->getRelocation(RelI->getRawDataRefImpl());
-
- uint32_t RelType = MachO->getAnyRelocationType(RE);
-
- // FIXME: Properly handle scattered relocations.
- // Special case the couple of scattered relocations that we know how
- // to handle: SECTDIFF relocations, and scattered VANILLA relocations
- // on I386.
- // For all other scattered relocations, just bail out and hope for the
- // best, since the offsets computed by scattered relocations have often
- // been optimisticaly filled in by the compiler. This will fail
- // horribly where the relocations *do* need to be applied, but that was
- // already the case.
- if (MachO->isRelocationScattered(RE)) {
- if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
- RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
- return processSECTDIFFRelocation(SectionID, RelI, Obj, ObjSectionToID);
- else if (Arch == Triple::x86 && RelType == MachO::GENERIC_RELOC_VANILLA)
- return processI386ScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
- else
- return ++RelI;
- }
-
- RelocationValueRef Value;
- SectionEntry &Section = Sections[SectionID];
-
- bool IsExtern = MachO->getPlainRelocationExternal(RE);
- bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
- unsigned Size = MachO->getAnyRelocationLength(RE);
- uint64_t Offset;
- RelI->getOffset(Offset);
- uint8_t *LocalAddress = Section.Address + Offset;
- unsigned NumBytes = 1 << Size;
- uint64_t Addend = 0;
- memcpy(&Addend, LocalAddress, NumBytes);
-
- if (IsExtern) {
- // Obtain the symbol name which is referenced in the relocation
- symbol_iterator Symbol = RelI->getSymbol();
- StringRef 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()) {
- 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());
- if (gsi != GlobalSymbolTable.end()) {
- Value.SectionID = gsi->second.first;
- Value.Addend = gsi->second.second + Addend;
- } else {
- Value.SymbolName = TargetName.data();
- Value.Addend = Addend;
- }
- }
-
- // Addends for external, PC-rel relocations on i386 point back to the zero
- // offset. Calculate the final offset from the relocation target instead.
- // This allows us to use the same logic for both external and internal
- // relocations in resolveI386RelocationRef.
- if (Arch == Triple::x86 && IsPCRel) {
- uint64_t RelocAddr = 0;
- RelI->getAddress(RelocAddr);
- Value.Addend += RelocAddr + 4;
- }
-
- } else {
- SectionRef Sec = MachO->getRelocationSection(RE);
- bool IsCode = false;
- Sec.isText(IsCode);
- Value.SectionID = findOrEmitSection(Obj, Sec, IsCode, ObjSectionToID);
- uint64_t Addr = MachOObj.getOldSectionAddr(Sec);
- DEBUG(dbgs() << "\nAddr: " << Addr << "\nAddend: " << Addend);
- Value.Addend = Addend - Addr;
- if (IsPCRel)
- Value.Addend += Offset + NumBytes;
- }
-
- if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT ||
- RelType == MachO::X86_64_RELOC_GOT_LOAD)) {
- assert(IsPCRel);
- assert(Size == 2);
-
- // FIXME: Teach the generic code above not to prematurely conflate
- // relocation addends and symbol offsets.
- Value.Addend -= Addend;
- 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 GOTRE(SectionID, Section.StubOffset,
- MachO::X86_64_RELOC_UNSIGNED, Value.Addend, false,
- 3);
- if (Value.SymbolName)
- addRelocationForSymbol(GOTRE, Value.SymbolName);
- else
- addRelocationForSection(GOTRE, Value.SectionID);
- Section.StubOffset += 8;
- Addr = GOTEntry;
- }
- RelocationEntry TargetRE(SectionID, Offset,
- MachO::X86_64_RELOC_UNSIGNED, Addend, true,
- 2);
- resolveRelocation(TargetRE, (uint64_t)Addr);
- } else if (Arch == Triple::arm && (RelType & 0xf) == MachO::ARM_RELOC_BR24) {
- // This is an ARM branch relocation, need to use a stub function.
-
- // Look up for existing stub.
- StubMap::const_iterator i = Stubs.find(Value);
- uint8_t *Addr;
- if (i != Stubs.end()) {
- Addr = Section.Address + i->second;
- } else {
- // Create a new stub function.
- Stubs[Value] = Section.StubOffset;
- uint8_t *StubTargetAddr =
- createStubFunction(Section.Address + Section.StubOffset);
- RelocationEntry StubRE(SectionID, StubTargetAddr - Section.Address,
- MachO::GENERIC_RELOC_VANILLA, Value.Addend);
- if (Value.SymbolName)
- addRelocationForSymbol(StubRE, Value.SymbolName);
- else
- addRelocationForSection(StubRE, Value.SectionID);
- Addr = Section.Address + Section.StubOffset;
- Section.StubOffset += getMaxStubSize();
- }
- RelocationEntry TargetRE(Value.SectionID, Offset, RelType, 0, IsPCRel,
- Size);
- resolveRelocation(TargetRE, (uint64_t)Addr);
- } else {
- RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size);
- if (Value.SymbolName)
- addRelocationForSymbol(RE, Value.SymbolName);
- else
- addRelocationForSection(RE, Value.SectionID);
- }
- return ++RelI;
-}
-
-bool
-RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const {
- if (InputBuffer->getBufferSize() < 4)
- return false;
- StringRef Magic(InputBuffer->getBufferStart(), 4);
- if (Magic == "\xFE\xED\xFA\xCE")
- return true;
- if (Magic == "\xCE\xFA\xED\xFE")
- return true;
- if (Magic == "\xFE\xED\xFA\xCF")
- return true;
- if (Magic == "\xCF\xFA\xED\xFE")
- return true;
- return false;
-}
-
-bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const {
- return Obj->isMachO();
}
} // end namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
index 35f0720..7583474 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
@@ -11,74 +11,33 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_RUNTIME_DYLD_MACHO_H
-#define LLVM_RUNTIME_DYLD_MACHO_H
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H
#include "ObjectImageCommon.h"
#include "RuntimeDyldImpl.h"
-#include "llvm/ADT/IndexedMap.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Format.h"
+#define DEBUG_TYPE "dyld"
+
using namespace llvm;
using namespace llvm::object;
namespace llvm {
class RuntimeDyldMachO : public RuntimeDyldImpl {
-private:
-
- /// Write the least significant 'Size' bytes in 'Value' out at the address
- /// pointed to by Addr.
- bool applyRelocationValue(uint8_t *Addr, uint64_t Value, unsigned Size) {
- for (unsigned i = 0; i < Size; ++i) {
- *Addr++ = (uint8_t)Value;
- Value >>= 8;
- }
-
- return false;
- }
-
- bool resolveI386Relocation(const RelocationEntry &RE, uint64_t Value);
- bool resolveX86_64Relocation(const RelocationEntry &RE, uint64_t Value);
- bool resolveARMRelocation(const RelocationEntry &RE, uint64_t Value);
- bool resolveAArch64Relocation(const RelocationEntry &RE, uint64_t Value);
-
- // Populate stubs in __jump_table section.
- void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection,
- unsigned JTSectionID);
-
- // Populate __pointers section.
- void populatePointersSection(MachOObjectFile &Obj, const SectionRef &PTSection,
- unsigned PTSectionID);
-
- unsigned getMaxStubSize() override {
- 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() override { return 1; }
-
- relocation_iterator processSECTDIFFRelocation(
- unsigned SectionID,
- relocation_iterator RelI,
- ObjectImage &ObjImg,
- ObjSectionToIDMap &ObjSectionToID);
-
- relocation_iterator processI386ScatteredVANILLA(
- unsigned SectionID,
- relocation_iterator RelI,
- ObjectImage &ObjImg,
- ObjSectionToIDMap &ObjSectionToID);
+protected:
+ struct SectionOffsetPair {
+ unsigned SectionID;
+ uint64_t Offset;
+ };
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;
@@ -91,25 +50,116 @@ private:
// EH frame sections with the memory manager.
SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections;
-public:
RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
- void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override;
- relocation_iterator
- processRelocationRef(unsigned SectionID, relocation_iterator RelI,
- ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID,
- const SymbolTableMap &Symbols, StubMap &Stubs) override;
+ /// This convenience method uses memcpy to extract a contiguous addend (the
+ /// addend size and offset are taken from the corresponding fields of the RE).
+ int64_t memcpyAddend(const RelocationEntry &RE) const;
+
+ /// Given a relocation_iterator for a non-scattered relocation, construct a
+ /// RelocationEntry and fill in the common fields. The 'Addend' field is *not*
+ /// filled in, since immediate encodings are highly target/opcode specific.
+ /// For targets/opcodes with simple, contiguous immediates (e.g. X86) the
+ /// memcpyAddend method can be used to read the immediate.
+ RelocationEntry getRelocationEntry(unsigned SectionID, ObjectImage &ObjImg,
+ const relocation_iterator &RI) const {
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RI->getRawDataRefImpl());
+
+ bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo);
+ unsigned Size = Obj.getAnyRelocationLength(RelInfo);
+ uint64_t Offset;
+ RI->getOffset(Offset);
+ MachO::RelocationInfoType RelType =
+ static_cast<MachO::RelocationInfoType>(Obj.getAnyRelocationType(RelInfo));
+
+ return RelocationEntry(SectionID, Offset, RelType, 0, IsPCRel, Size);
+ }
+
+ /// Construct a RelocationValueRef representing the relocation target.
+ /// For Symbols in known sections, this will return a RelocationValueRef
+ /// representing a (SectionID, Offset) pair.
+ /// For Symbols whose section is not known, this will return a
+ /// (SymbolName, Offset) pair, where the Offset is taken from the instruction
+ /// immediate (held in RE.Addend).
+ /// In both cases the Addend field is *NOT* fixed up to be PC-relative. That
+ /// should be done by the caller where appropriate by calling makePCRel on
+ /// the RelocationValueRef.
+ RelocationValueRef getRelocationValueRef(ObjectImage &ObjImg,
+ const relocation_iterator &RI,
+ const RelocationEntry &RE,
+ ObjSectionToIDMap &ObjSectionToID,
+ const SymbolTableMap &Symbols);
+
+ /// Make the RelocationValueRef addend PC-relative.
+ void makeValueAddendPCRel(RelocationValueRef &Value, ObjectImage &ObjImg,
+ const relocation_iterator &RI,
+ unsigned OffsetToNextPC);
+
+ /// Dump information about the relocation entry (RE) and resolved value.
+ void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const;
+
+ // Return a section iterator for the section containing the given address.
+ static section_iterator getSectionByAddress(const MachOObjectFile &Obj,
+ uint64_t Addr);
+
+
+ // Populate __pointers section.
+ void populateIndirectSymbolPointersSection(MachOObjectFile &Obj,
+ const SectionRef &PTSection,
+ unsigned PTSectionID);
+
+public:
+ /// Create an ObjectImage from the given ObjectBuffer.
+ static std::unique_ptr<ObjectImage>
+ createObjectImage(std::unique_ptr<ObjectBuffer> InputBuffer) {
+ return llvm::make_unique<ObjectImageCommon>(std::move(InputBuffer));
+ }
+
+ /// Create an ObjectImage from the given ObjectFile.
+ static ObjectImage *
+ createObjectImageFromFile(std::unique_ptr<object::ObjectFile> InputObject) {
+ return new ObjectImageCommon(std::move(InputObject));
+ }
+
+ /// Create a RuntimeDyldMachO instance for the given target architecture.
+ static std::unique_ptr<RuntimeDyldMachO> create(Triple::ArchType Arch,
+ RTDyldMemoryManager *mm);
+
+ SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; }
+
bool isCompatibleFormat(const ObjectBuffer *Buffer) const override;
bool isCompatibleFile(const object::ObjectFile *Obj) const override;
- void registerEHFrames() override;
+};
+
+/// RuntimeDyldMachOTarget - Templated base class for generic MachO linker
+/// algorithms and data structures.
+///
+/// Concrete, target specific sub-classes can be accessed via the impl()
+/// methods. (i.e. the RuntimeDyldMachO hierarchy uses the Curiously
+/// Recurring Template Idiom). Concrete subclasses for each target
+/// can be found in ./Targets.
+template <typename Impl>
+class RuntimeDyldMachOCRTPBase : public RuntimeDyldMachO {
+private:
+ Impl &impl() { return static_cast<Impl &>(*this); }
+ const Impl &impl() const { return static_cast<const Impl &>(*this); }
+
+ unsigned char *processFDE(unsigned char *P, int64_t DeltaForText,
+ int64_t DeltaForEH);
+
+public:
+ RuntimeDyldMachOCRTPBase(RTDyldMemoryManager *mm) : RuntimeDyldMachO(mm) {}
+
void finalizeLoad(ObjectImage &ObjImg,
ObjSectionToIDMap &SectionMap) override;
-
- static ObjectImage *createObjectImage(ObjectBuffer *Buffer);
- static ObjectImage *
- createObjectImageFromFile(std::unique_ptr<object::ObjectFile> InputObject);
+ void registerEHFrames() override;
};
} // end namespace llvm
+#undef DEBUG_TYPE
+
#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
new file mode 100644
index 0000000..f5cf9ac
--- /dev/null
+++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
@@ -0,0 +1,405 @@
+//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H
+
+#include "../RuntimeDyldMachO.h"
+#include "llvm/Support/Endian.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOAArch64
+ : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> {
+public:
+
+ typedef uint64_t TargetPtrT;
+
+ RuntimeDyldMachOAArch64(RTDyldMemoryManager *MM)
+ : RuntimeDyldMachOCRTPBase(MM) {}
+
+ unsigned getMaxStubSize() override { return 8; }
+
+ unsigned getStubAlignment() override { return 8; }
+
+ /// Extract the addend encoded in the instruction / memory location.
+ int64_t decodeAddend(const RelocationEntry &RE) const {
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+ unsigned NumBytes = 1 << RE.Size;
+ int64_t Addend = 0;
+ // Verify that the relocation has the correct size and alignment.
+ switch (RE.RelType) {
+ default:
+ llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_UNSIGNED:
+ assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
+ break;
+ case MachO::ARM64_RELOC_BRANCH26:
+ case MachO::ARM64_RELOC_PAGE21:
+ case MachO::ARM64_RELOC_PAGEOFF12:
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ assert(NumBytes == 4 && "Invalid relocation size.");
+ assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
+ "Instruction address is not aligned to 4 bytes.");
+ break;
+ }
+
+ switch (RE.RelType) {
+ default:
+ llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_UNSIGNED:
+ // This could be an unaligned memory location.
+ if (NumBytes == 4)
+ Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress);
+ else
+ Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
+ break;
+ case MachO::ARM64_RELOC_BRANCH26: {
+ // Verify that the relocation points to the expected branch instruction.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction.");
+
+ // Get the 26 bit addend encoded in the branch instruction and sign-extend
+ // to 64 bit. The lower 2 bits are always zeros and are therefore implicit
+ // (<< 2).
+ Addend = (*p & 0x03FFFFFF) << 2;
+ Addend = SignExtend64(Addend, 28);
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_PAGE21: {
+ // Verify that the relocation points to the expected adrp instruction.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
+
+ // Get the 21 bit addend encoded in the adrp instruction and sign-extend
+ // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are
+ // therefore implicit (<< 12).
+ Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12;
+ Addend = SignExtend64(Addend, 33);
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
+ // Verify that the relocation points to one of the expected load / store
+ // instructions.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ (void)p;
+ assert((*p & 0x3B000000) == 0x39000000 &&
+ "Only expected load / store instructions.");
+ } // fall-through
+ case MachO::ARM64_RELOC_PAGEOFF12: {
+ // Verify that the relocation points to one of the expected load / store
+ // or add / sub instructions.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ assert((((*p & 0x3B000000) == 0x39000000) ||
+ ((*p & 0x11C00000) == 0x11000000) ) &&
+ "Expected load / store or add/sub instruction.");
+
+ // Get the 12 bit addend encoded in the instruction.
+ Addend = (*p & 0x003FFC00) >> 10;
+
+ // Check which instruction we are decoding to obtain the implicit shift
+ // factor of the instruction.
+ int ImplicitShift = 0;
+ if ((*p & 0x3B000000) == 0x39000000) { // << load / store
+ // For load / store instructions the size is encoded in bits 31:30.
+ ImplicitShift = ((*p >> 30) & 0x3);
+ if (ImplicitShift == 0) {
+ // Check if this a vector op to get the correct shift value.
+ if ((*p & 0x04800000) == 0x04800000)
+ ImplicitShift = 4;
+ }
+ }
+ // Compensate for implicit shift.
+ Addend <<= ImplicitShift;
+ break;
+ }
+ }
+ return Addend;
+ }
+
+ /// Extract the addend encoded in the instruction.
+ void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes,
+ MachO::RelocationInfoType RelType, int64_t Addend) const {
+ // Verify that the relocation has the correct alignment.
+ switch (RelType) {
+ default:
+ llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_UNSIGNED:
+ assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
+ break;
+ case MachO::ARM64_RELOC_BRANCH26:
+ case MachO::ARM64_RELOC_PAGE21:
+ case MachO::ARM64_RELOC_PAGEOFF12:
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ assert(NumBytes == 4 && "Invalid relocation size.");
+ assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
+ "Instruction address is not aligned to 4 bytes.");
+ break;
+ }
+
+ switch (RelType) {
+ default:
+ llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_UNSIGNED:
+ // This could be an unaligned memory location.
+ if (NumBytes == 4)
+ *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend;
+ else
+ *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend;
+ break;
+ case MachO::ARM64_RELOC_BRANCH26: {
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ // Verify that the relocation points to the expected branch instruction.
+ assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction.");
+
+ // Verify addend value.
+ assert((Addend & 0x3) == 0 && "Branch target is not aligned");
+ assert(isInt<28>(Addend) && "Branch target is out of range.");
+
+ // Encode the addend as 26 bit immediate in the branch instruction.
+ *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_PAGE21: {
+ // Verify that the relocation points to the expected adrp instruction.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
+
+ // Check that the addend fits into 21 bits (+ 12 lower bits).
+ assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
+ assert(isInt<33>(Addend) && "Invalid page reloc value.");
+
+ // Encode the addend into the instruction.
+ uint32_t ImmLoValue = (uint32_t)(Addend << 17) & 0x60000000;
+ uint32_t ImmHiValue = (uint32_t)(Addend >> 9) & 0x00FFFFE0;
+ *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
+ // Verify that the relocation points to one of the expected load / store
+ // instructions.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ assert((*p & 0x3B000000) == 0x39000000 &&
+ "Only expected load / store instructions.");
+ (void)p;
+ } // fall-through
+ case MachO::ARM64_RELOC_PAGEOFF12: {
+ // Verify that the relocation points to one of the expected load / store
+ // or add / sub instructions.
+ auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
+ assert((((*p & 0x3B000000) == 0x39000000) ||
+ ((*p & 0x11C00000) == 0x11000000) ) &&
+ "Expected load / store or add/sub instruction.");
+
+ // Check which instruction we are decoding to obtain the implicit shift
+ // factor of the instruction and verify alignment.
+ int ImplicitShift = 0;
+ if ((*p & 0x3B000000) == 0x39000000) { // << load / store
+ // For load / store instructions the size is encoded in bits 31:30.
+ ImplicitShift = ((*p >> 30) & 0x3);
+ switch (ImplicitShift) {
+ case 0:
+ // Check if this a vector op to get the correct shift value.
+ if ((*p & 0x04800000) == 0x04800000) {
+ ImplicitShift = 4;
+ assert(((Addend & 0xF) == 0) &&
+ "128-bit LDR/STR not 16-byte aligned.");
+ }
+ break;
+ case 1:
+ assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
+ break;
+ case 2:
+ assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
+ break;
+ case 3:
+ assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
+ break;
+ }
+ }
+ // Compensate for implicit shift.
+ Addend >>= ImplicitShift;
+ assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
+
+ // Encode the addend into the instruction.
+ *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
+ break;
+ }
+ }
+ }
+
+ relocation_iterator
+ processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+ ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+ const SymbolTableMap &Symbols, StubMap &Stubs) override {
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RelI->getRawDataRefImpl());
+
+ assert(!Obj.isRelocationScattered(RelInfo) && "");
+
+ // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit
+ // addend for the following relocation. If found: (1) store the associated
+ // addend, (2) consume the next relocation, and (3) use the stored addend to
+ // override the addend.
+ int64_t ExplicitAddend = 0;
+ if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) {
+ assert(!Obj.getPlainRelocationExternal(RelInfo));
+ assert(!Obj.getAnyRelocationPCRel(RelInfo));
+ assert(Obj.getAnyRelocationLength(RelInfo) == 2);
+ int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo);
+ // Sign-extend the 24-bit to 64-bit.
+ ExplicitAddend = SignExtend64(RawAddend, 24);
+ ++RelI;
+ RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl());
+ }
+
+ RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI));
+ RE.Addend = decodeAddend(RE);
+ RelocationValueRef Value(
+ getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+ assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
+ "ARM64_RELOC_ADDEND and embedded addend in the instruction.");
+ if (ExplicitAddend) {
+ RE.Addend = ExplicitAddend;
+ Value.Offset = ExplicitAddend;
+ }
+
+ bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+ if (!IsExtern && RE.IsPCRel)
+ makeValueAddendPCRel(Value, ObjImg, RelI, 1 << RE.Size);
+
+ RE.Addend = Value.Offset;
+
+ if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
+ RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12)
+ processGOTRelocation(RE, Value, Stubs);
+ else {
+ if (Value.SymbolName)
+ addRelocationForSymbol(RE, Value.SymbolName);
+ else
+ addRelocationForSection(RE, Value.SectionID);
+ }
+
+ return ++RelI;
+ }
+
+ void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
+ DEBUG(dumpRelocationToResolve(RE, Value));
+
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+ MachO::RelocationInfoType RelType =
+ static_cast<MachO::RelocationInfoType>(RE.RelType);
+
+ switch (RelType) {
+ default:
+ llvm_unreachable("Invalid relocation type!");
+ case MachO::ARM64_RELOC_UNSIGNED: {
+ assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported");
+ // 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).
+ if (RE.Size < 2)
+ llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED");
+
+ encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
+ break;
+ }
+ case MachO::ARM64_RELOC_BRANCH26: {
+ assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
+ // Check if branch is in range.
+ uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+ int64_t PCRelVal = Value - FinalAddress + RE.Addend;
+ encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_PAGE21: {
+ assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
+ // Adjust for PC-relative relocation and offset.
+ uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+ int64_t PCRelVal =
+ ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
+ encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal);
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ case MachO::ARM64_RELOC_PAGEOFF12: {
+ assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
+ // Add the offset from the symbol.
+ Value += RE.Addend;
+ // Mask out the page address and only use the lower 12 bits.
+ Value &= 0xFFF;
+ encodeAddend(LocalAddress, /*Size=*/4, RelType, Value);
+ break;
+ }
+ case MachO::ARM64_RELOC_SUBTRACTOR:
+ case MachO::ARM64_RELOC_POINTER_TO_GOT:
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
+ llvm_unreachable("Relocation type not yet implemented!");
+ case MachO::ARM64_RELOC_ADDEND:
+ llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
+ "processRelocationRef!");
+ }
+ }
+
+ void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+ const SectionRef &Section) {}
+
+private:
+ void processGOTRelocation(const RelocationEntry &RE,
+ RelocationValueRef &Value, StubMap &Stubs) {
+ assert(RE.Size == 2);
+ SectionEntry &Section = Sections[RE.SectionID];
+ StubMap::const_iterator i = Stubs.find(Value);
+ int64_t Offset;
+ if (i != Stubs.end())
+ Offset = static_cast<int64_t>(i->second);
+ else {
+ // FIXME: There must be a better way to do this then to check and fix the
+ // alignment every time!!!
+ uintptr_t BaseAddress = uintptr_t(Section.Address);
+ uintptr_t StubAlignment = getStubAlignment();
+ uintptr_t StubAddress =
+ (BaseAddress + Section.StubOffset + StubAlignment - 1) &
+ -StubAlignment;
+ unsigned StubOffset = StubAddress - BaseAddress;
+ Stubs[Value] = StubOffset;
+ assert(((StubAddress % getStubAlignment()) == 0) &&
+ "GOT entry not aligned");
+ RelocationEntry GOTRE(RE.SectionID, StubOffset,
+ MachO::ARM64_RELOC_UNSIGNED, Value.Offset,
+ /*IsPCRel=*/false, /*Size=*/3);
+ if (Value.SymbolName)
+ addRelocationForSymbol(GOTRE, Value.SymbolName);
+ else
+ addRelocationForSection(GOTRE, Value.SectionID);
+ Section.StubOffset = StubOffset + getMaxStubSize();
+ Offset = static_cast<int64_t>(StubOffset);
+ }
+ RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset,
+ RE.IsPCRel, RE.Size);
+ addRelocationForSection(TargetRE, RE.SectionID);
+ }
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
new file mode 100644
index 0000000..9766751
--- /dev/null
+++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
@@ -0,0 +1,277 @@
+//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOARM
+ : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
+private:
+ typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;
+
+public:
+
+ typedef uint32_t TargetPtrT;
+
+ RuntimeDyldMachOARM(RTDyldMemoryManager *MM) : RuntimeDyldMachOCRTPBase(MM) {}
+
+ unsigned getMaxStubSize() override { return 8; }
+
+ unsigned getStubAlignment() override { return 4; }
+
+ int64_t decodeAddend(const RelocationEntry &RE) const {
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+ switch (RE.RelType) {
+ default:
+ return memcpyAddend(RE);
+ case MachO::ARM_RELOC_BR24: {
+ uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
+ Temp &= 0x00ffffff; // Mask out the opcode.
+ // Now we've got the shifted immediate, shift by 2, sign extend and ret.
+ return SignExtend32<26>(Temp << 2);
+ }
+ }
+ }
+
+ relocation_iterator
+ processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+ ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+ const SymbolTableMap &Symbols, StubMap &Stubs) override {
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RelI->getRawDataRefImpl());
+ uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
+
+ if (Obj.isRelocationScattered(RelInfo)) {
+ if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
+ return processHALFSECTDIFFRelocation(SectionID, RelI, ObjImg,
+ ObjSectionToID);
+ else
+ return ++++RelI;
+ }
+
+ RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI));
+ RE.Addend = decodeAddend(RE);
+ RelocationValueRef Value(
+ getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+ if (RE.IsPCRel)
+ makeValueAddendPCRel(Value, ObjImg, RelI, 8);
+
+ if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
+ processBranchRelocation(RE, Value, Stubs);
+ else {
+ RE.Addend = Value.Offset;
+ if (Value.SymbolName)
+ addRelocationForSymbol(RE, Value.SymbolName);
+ else
+ addRelocationForSection(RE, Value.SectionID);
+ }
+
+ return ++RelI;
+ }
+
+ void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
+ DEBUG(dumpRelocationToResolve(RE, Value));
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+ // If the relocation is PC-relative, the value to be encoded is the
+ // pointer difference.
+ if (RE.IsPCRel) {
+ uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+ Value -= FinalAddress;
+ // ARM PCRel relocations have an effective-PC offset of two instructions
+ // (four bytes in Thumb mode, 8 bytes in ARM mode).
+ // FIXME: For now, assume ARM mode.
+ Value -= 8;
+ }
+
+ switch (RE.RelType) {
+ default:
+ llvm_unreachable("Invalid relocation type!");
+ case MachO::ARM_RELOC_VANILLA:
+ writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
+ break;
+ 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.
+ Value += RE.Addend;
+ // The low two bits of the value are not encoded.
+ Value >>= 2;
+ // Mask the value to 24 bits.
+ uint64_t FinalValue = Value & 0xffffff;
+ // FIXME: If the destination is a Thumb function (and the instruction
+ // is a non-predicated BL instruction), we need to change it to a BLX
+ // instruction instead.
+
+ // Insert the value into the instruction.
+ uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
+ writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);
+
+ break;
+ }
+ case MachO::ARM_RELOC_HALF_SECTDIFF: {
+ uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
+ uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
+ assert((Value == SectionABase || Value == SectionBBase) &&
+ "Unexpected HALFSECTDIFF relocation value.");
+ Value = SectionABase - SectionBBase + RE.Addend;
+ if (RE.Size & 0x1) // :upper16:
+ Value = (Value >> 16);
+ Value &= 0xffff;
+
+ uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
+ Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
+ writeBytesUnaligned(Insn, LocalAddress, 4);
+ break;
+ }
+
+ case MachO::ARM_THUMB_RELOC_BR22:
+ case MachO::ARM_THUMB_32BIT_BRANCH:
+ case MachO::ARM_RELOC_HALF:
+ case MachO::ARM_RELOC_PAIR:
+ case MachO::ARM_RELOC_SECTDIFF:
+ case MachO::ARM_RELOC_LOCAL_SECTDIFF:
+ case MachO::ARM_RELOC_PB_LA_PTR:
+ Error("Relocation type not implemented yet!");
+ return;
+ }
+ }
+
+ void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+ const SectionRef &Section) {
+ StringRef Name;
+ Section.getName(Name);
+
+ if (Name == "__nl_symbol_ptr")
+ populateIndirectSymbolPointersSection(
+ cast<MachOObjectFile>(*ObjImg.getObjectFile()),
+ Section, SectionID);
+ }
+
+private:
+
+ void processBranchRelocation(const RelocationEntry &RE,
+ const RelocationValueRef &Value,
+ StubMap &Stubs) {
+ // This is an ARM branch relocation, need to use a stub function.
+ // Look up for existing stub.
+ SectionEntry &Section = Sections[RE.SectionID];
+ RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
+ uint8_t *Addr;
+ if (i != Stubs.end()) {
+ Addr = Section.Address + i->second;
+ } else {
+ // Create a new stub function.
+ Stubs[Value] = Section.StubOffset;
+ uint8_t *StubTargetAddr =
+ createStubFunction(Section.Address + Section.StubOffset);
+ RelocationEntry StubRE(RE.SectionID, StubTargetAddr - Section.Address,
+ MachO::GENERIC_RELOC_VANILLA, Value.Offset, false,
+ 2);
+ if (Value.SymbolName)
+ addRelocationForSymbol(StubRE, Value.SymbolName);
+ else
+ addRelocationForSection(StubRE, Value.SectionID);
+ Addr = Section.Address + Section.StubOffset;
+ Section.StubOffset += getMaxStubSize();
+ }
+ RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
+ RE.IsPCRel, RE.Size);
+ resolveRelocation(TargetRE, (uint64_t)Addr);
+ }
+
+ relocation_iterator
+ processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
+ ObjectImage &Obj,
+ ObjSectionToIDMap &ObjSectionToID) {
+ const MachOObjectFile *MachO =
+ static_cast<const MachOObjectFile *>(Obj.getObjectFile());
+ MachO::any_relocation_info RE =
+ MachO->getRelocation(RelI->getRawDataRefImpl());
+
+
+ // For a half-diff relocation the length bits actually record whether this
+ // is a movw/movt, and whether this is arm or thumb.
+ // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
+ // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
+ unsigned HalfDiffKindBits = MachO->getAnyRelocationLength(RE);
+ if (HalfDiffKindBits & 0x2)
+ llvm_unreachable("Thumb not yet supported.");
+
+ SectionEntry &Section = Sections[SectionID];
+ uint32_t RelocType = MachO->getAnyRelocationType(RE);
+ bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
+ uint64_t Offset;
+ RelI->getOffset(Offset);
+ uint8_t *LocalAddress = Section.Address + Offset;
+ int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
+ Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
+
+ ++RelI;
+ MachO::any_relocation_info RE2 =
+ MachO->getRelocation(RelI->getRawDataRefImpl());
+ uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
+ section_iterator SAI = getSectionByAddress(*MachO, AddrA);
+ assert(SAI != MachO->section_end() && "Can't find section for address A");
+ uint64_t SectionABase = SAI->getAddress();
+ uint64_t SectionAOffset = AddrA - SectionABase;
+ SectionRef SectionA = *SAI;
+ bool IsCode = SectionA.isText();
+ uint32_t SectionAID =
+ findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID);
+
+ uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
+ section_iterator SBI = getSectionByAddress(*MachO, AddrB);
+ assert(SBI != MachO->section_end() && "Can't find section for address B");
+ uint64_t SectionBBase = SBI->getAddress();
+ uint64_t SectionBOffset = AddrB - SectionBBase;
+ SectionRef SectionB = *SBI;
+ uint32_t SectionBID =
+ findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID);
+
+ uint32_t OtherHalf = MachO->getAnyRelocationAddress(RE2) & 0xffff;
+ unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
+ uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
+ int64_t Addend = FullImmVal - (AddrA - AddrB);
+
+ // addend = Encoded - Expected
+ // = Encoded - (AddrA - AddrB)
+
+ DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
+ << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
+ << ", SectionAOffset: " << SectionAOffset
+ << ", SectionB ID: " << SectionBID
+ << ", SectionBOffset: " << SectionBOffset << "\n");
+ RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
+ SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
+ HalfDiffKindBits);
+
+ addRelocationForSection(R, SectionAID);
+ addRelocationForSection(R, SectionBID);
+
+ return ++RelI;
+ }
+
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h
new file mode 100644
index 0000000..258b847
--- /dev/null
+++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h
@@ -0,0 +1,261 @@
+//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOI386
+ : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> {
+public:
+
+ typedef uint32_t TargetPtrT;
+
+ RuntimeDyldMachOI386(RTDyldMemoryManager *MM)
+ : RuntimeDyldMachOCRTPBase(MM) {}
+
+ unsigned getMaxStubSize() override { return 0; }
+
+ unsigned getStubAlignment() override { return 1; }
+
+ relocation_iterator
+ processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+ ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+ const SymbolTableMap &Symbols, StubMap &Stubs) override {
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RelI->getRawDataRefImpl());
+ uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
+
+ if (Obj.isRelocationScattered(RelInfo)) {
+ if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
+ RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
+ return processSECTDIFFRelocation(SectionID, RelI, ObjImg,
+ ObjSectionToID);
+ else if (RelType == MachO::GENERIC_RELOC_VANILLA)
+ return processI386ScatteredVANILLA(SectionID, RelI, ObjImg,
+ ObjSectionToID);
+ llvm_unreachable("Unhandled scattered relocation.");
+ }
+
+ RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI));
+ RE.Addend = memcpyAddend(RE);
+ RelocationValueRef Value(
+ getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+ // Addends for external, PC-rel relocations on i386 point back to the zero
+ // offset. Calculate the final offset from the relocation target instead.
+ // This allows us to use the same logic for both external and internal
+ // relocations in resolveI386RelocationRef.
+ // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+ // if (IsExtern && RE.IsPCRel) {
+ // uint64_t RelocAddr = 0;
+ // RelI->getAddress(RelocAddr);
+ // Value.Addend += RelocAddr + 4;
+ // }
+ if (RE.IsPCRel)
+ makeValueAddendPCRel(Value, ObjImg, RelI, 1 << RE.Size);
+
+ RE.Addend = Value.Offset;
+
+ if (Value.SymbolName)
+ addRelocationForSymbol(RE, Value.SymbolName);
+ else
+ addRelocationForSection(RE, Value.SectionID);
+
+ return ++RelI;
+ }
+
+ void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
+ DEBUG(dumpRelocationToResolve(RE, Value));
+
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+ if (RE.IsPCRel) {
+ uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+ Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
+ }
+
+ switch (RE.RelType) {
+ default:
+ llvm_unreachable("Invalid relocation type!");
+ case MachO::GENERIC_RELOC_VANILLA:
+ writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
+ break;
+ case MachO::GENERIC_RELOC_SECTDIFF:
+ case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
+ uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
+ uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
+ assert((Value == SectionABase || Value == SectionBBase) &&
+ "Unexpected SECTDIFF relocation value.");
+ Value = SectionABase - SectionBBase + RE.Addend;
+ writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
+ break;
+ }
+ case MachO::GENERIC_RELOC_PB_LA_PTR:
+ Error("Relocation type not implemented yet!");
+ }
+ }
+
+ void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+ const SectionRef &Section) {
+ StringRef Name;
+ Section.getName(Name);
+
+ if (Name == "__jump_table")
+ populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()), Section,
+ SectionID);
+ else if (Name == "__pointers")
+ populateIndirectSymbolPointersSection(
+ cast<MachOObjectFile>(*ObjImg.getObjectFile()),
+ Section, SectionID);
+ }
+
+private:
+ relocation_iterator
+ processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
+ ObjectImage &Obj,
+ ObjSectionToIDMap &ObjSectionToID) {
+ const MachOObjectFile *MachO =
+ static_cast<const MachOObjectFile *>(Obj.getObjectFile());
+ MachO::any_relocation_info RE =
+ MachO->getRelocation(RelI->getRawDataRefImpl());
+
+ SectionEntry &Section = Sections[SectionID];
+ uint32_t RelocType = MachO->getAnyRelocationType(RE);
+ bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
+ unsigned Size = MachO->getAnyRelocationLength(RE);
+ uint64_t Offset;
+ RelI->getOffset(Offset);
+ uint8_t *LocalAddress = Section.Address + Offset;
+ unsigned NumBytes = 1 << Size;
+ uint64_t Addend = readBytesUnaligned(LocalAddress, NumBytes);
+
+ ++RelI;
+ MachO::any_relocation_info RE2 =
+ MachO->getRelocation(RelI->getRawDataRefImpl());
+
+ uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
+ section_iterator SAI = getSectionByAddress(*MachO, AddrA);
+ assert(SAI != MachO->section_end() && "Can't find section for address A");
+ uint64_t SectionABase = SAI->getAddress();
+ uint64_t SectionAOffset = AddrA - SectionABase;
+ SectionRef SectionA = *SAI;
+ bool IsCode = SectionA.isText();
+ uint32_t SectionAID =
+ findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID);
+
+ uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
+ section_iterator SBI = getSectionByAddress(*MachO, AddrB);
+ assert(SBI != MachO->section_end() && "Can't find section for address B");
+ uint64_t SectionBBase = SBI->getAddress();
+ uint64_t SectionBOffset = AddrB - SectionBBase;
+ SectionRef SectionB = *SBI;
+ uint32_t SectionBID =
+ findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID);
+
+ if (Addend != AddrA - AddrB)
+ Error("Unexpected SECTDIFF relocation addend.");
+
+ DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
+ << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
+ << ", SectionAOffset: " << SectionAOffset
+ << ", SectionB ID: " << SectionBID
+ << ", SectionBOffset: " << SectionBOffset << "\n");
+ RelocationEntry R(SectionID, Offset, RelocType, 0, SectionAID,
+ SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
+ Size);
+
+ addRelocationForSection(R, SectionAID);
+ addRelocationForSection(R, SectionBID);
+
+ return ++RelI;
+ }
+
+ relocation_iterator processI386ScatteredVANILLA(
+ unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj,
+ RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID) {
+ const MachOObjectFile *MachO =
+ static_cast<const MachOObjectFile *>(Obj.getObjectFile());
+ MachO::any_relocation_info RE =
+ MachO->getRelocation(RelI->getRawDataRefImpl());
+
+ SectionEntry &Section = Sections[SectionID];
+ uint32_t RelocType = MachO->getAnyRelocationType(RE);
+ bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
+ unsigned Size = MachO->getAnyRelocationLength(RE);
+ uint64_t Offset;
+ RelI->getOffset(Offset);
+ uint8_t *LocalAddress = Section.Address + Offset;
+ unsigned NumBytes = 1 << Size;
+ int64_t Addend = readBytesUnaligned(LocalAddress, NumBytes);
+
+ unsigned SymbolBaseAddr = MachO->getScatteredRelocationValue(RE);
+ section_iterator TargetSI = getSectionByAddress(*MachO, SymbolBaseAddr);
+ assert(TargetSI != MachO->section_end() && "Can't find section for symbol");
+ uint64_t SectionBaseAddr = TargetSI->getAddress();
+ SectionRef TargetSection = *TargetSI;
+ bool IsCode = TargetSection.isText();
+ uint32_t TargetSectionID =
+ findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID);
+
+ Addend -= SectionBaseAddr;
+ RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size);
+
+ addRelocationForSection(R, TargetSectionID);
+
+ return ++RelI;
+ }
+
+ // Populate stubs in __jump_table section.
+ void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection,
+ unsigned JTSectionID) {
+ assert(!Obj.is64Bit() &&
+ "__jump_table section not supported in 64-bit MachO.");
+
+ MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
+ MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
+ uint32_t JTSectionSize = Sec32.size;
+ unsigned FirstIndirectSymbol = Sec32.reserved1;
+ unsigned JTEntrySize = Sec32.reserved2;
+ unsigned NumJTEntries = JTSectionSize / JTEntrySize;
+ uint8_t *JTSectionAddr = getSectionAddress(JTSectionID);
+ unsigned JTEntryOffset = 0;
+
+ assert((JTSectionSize % JTEntrySize) == 0 &&
+ "Jump-table section does not contain a whole number of stubs?");
+
+ for (unsigned i = 0; i < NumJTEntries; ++i) {
+ unsigned SymbolIndex =
+ Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
+ symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
+ StringRef IndirectSymbolName;
+ SI->getName(IndirectSymbolName);
+ uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset;
+ createStubFunction(JTEntryAddr);
+ RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
+ MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
+ addRelocationForSymbol(RE, IndirectSymbolName);
+ JTEntryOffset += JTEntrySize;
+ }
+ }
+
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h
new file mode 100644
index 0000000..84d9e80
--- /dev/null
+++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h
@@ -0,0 +1,136 @@
+//===-- RuntimeDyldMachOX86_64.h ---- MachO/X86_64 specific code. -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H
+#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H
+
+#include "../RuntimeDyldMachO.h"
+
+#define DEBUG_TYPE "dyld"
+
+namespace llvm {
+
+class RuntimeDyldMachOX86_64
+ : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> {
+public:
+
+ typedef uint64_t TargetPtrT;
+
+ RuntimeDyldMachOX86_64(RTDyldMemoryManager *MM)
+ : RuntimeDyldMachOCRTPBase(MM) {}
+
+ unsigned getMaxStubSize() override { return 8; }
+
+ unsigned getStubAlignment() override { return 1; }
+
+ relocation_iterator
+ processRelocationRef(unsigned SectionID, relocation_iterator RelI,
+ ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
+ const SymbolTableMap &Symbols, StubMap &Stubs) override {
+ const MachOObjectFile &Obj =
+ static_cast<const MachOObjectFile &>(*ObjImg.getObjectFile());
+ MachO::any_relocation_info RelInfo =
+ Obj.getRelocation(RelI->getRawDataRefImpl());
+
+ assert(!Obj.isRelocationScattered(RelInfo) &&
+ "Scattered relocations not supported on X86_64");
+
+ RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI));
+ RE.Addend = memcpyAddend(RE);
+ RelocationValueRef Value(
+ getRelocationValueRef(ObjImg, RelI, RE, ObjSectionToID, Symbols));
+
+ bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
+ if (!IsExtern && RE.IsPCRel)
+ makeValueAddendPCRel(Value, ObjImg, RelI, 1 << RE.Size);
+
+ if (RE.RelType == MachO::X86_64_RELOC_GOT ||
+ RE.RelType == MachO::X86_64_RELOC_GOT_LOAD)
+ processGOTRelocation(RE, Value, Stubs);
+ else {
+ RE.Addend = Value.Offset;
+ if (Value.SymbolName)
+ addRelocationForSymbol(RE, Value.SymbolName);
+ else
+ addRelocationForSection(RE, Value.SectionID);
+ }
+
+ return ++RelI;
+ }
+
+ void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
+ DEBUG(dumpRelocationToResolve(RE, Value));
+ const SectionEntry &Section = Sections[RE.SectionID];
+ uint8_t *LocalAddress = Section.Address + RE.Offset;
+
+ // If the relocation is PC-relative, the value to be encoded is the
+ // pointer difference.
+ if (RE.IsPCRel) {
+ // FIXME: It seems this value needs to be adjusted by 4 for an effective
+ // PC address. Is that expected? Only for branches, perhaps?
+ uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
+ Value -= FinalAddress + 4;
+ }
+
+ switch (RE.RelType) {
+ default:
+ llvm_unreachable("Invalid relocation type!");
+ 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:
+ writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
+ break;
+ 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:
+ Error("Relocation type not implemented yet!");
+ }
+ }
+
+ void finalizeSection(ObjectImage &ObjImg, unsigned SectionID,
+ const SectionRef &Section) {}
+
+private:
+ void processGOTRelocation(const RelocationEntry &RE,
+ RelocationValueRef &Value, StubMap &Stubs) {
+ SectionEntry &Section = Sections[RE.SectionID];
+ assert(RE.IsPCRel);
+ assert(RE.Size == 2);
+ Value.Offset -= RE.Addend;
+ RuntimeDyldMachO::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 GOTRE(RE.SectionID, Section.StubOffset,
+ MachO::X86_64_RELOC_UNSIGNED, Value.Offset, false,
+ 3);
+ if (Value.SymbolName)
+ addRelocationForSymbol(GOTRE, Value.SymbolName);
+ else
+ addRelocationForSection(GOTRE, Value.SectionID);
+ Section.StubOffset += 8;
+ Addr = GOTEntry;
+ }
+ RelocationEntry TargetRE(RE.SectionID, RE.Offset,
+ MachO::X86_64_RELOC_UNSIGNED, RE.Addend, true, 2);
+ resolveRelocation(TargetRE, (uint64_t)Addr);
+ }
+};
+}
+
+#undef DEBUG_TYPE
+
+#endif