aboutsummaryrefslogtreecommitdiff
path: root/lib/ExecutionEngine
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2013-05-05 20:43:10 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2013-05-05 20:43:10 +0000
commita2e40fbd624916c187a95ed76939ca7f02ed3e53 (patch)
treea2123a8cee6f7edaf0bb085625c018314e4e46fd /lib/ExecutionEngine
parent9f2bebbc288354f0818f3a319a91cc7efd09ef93 (diff)
Add EH support to the MCJIT.
This gets exception handling working on ELF and Macho (x86-64 at least). Other than the EH frame registration, this patch also implements support for GOT relocations which are used to locate the personality function on MachO. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181167 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine')
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJIT.cpp13
-rw-r--r--lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp32
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp14
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp8
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h1
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h10
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp88
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h1
8 files changed, 153 insertions, 14 deletions
diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index ccaa72a610..38aa5474a3 100644
--- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -168,15 +168,14 @@ void MCJIT::finalizeObject() {
// If the call to Dyld.resolveRelocations() is removed from loadObject()
// we'll need to do that here.
loadObject(M);
-
- // Set page permissions.
- MemMgr->applyPermissions();
-
- return;
+ } else {
+ // Resolve any relocations.
+ Dyld.resolveRelocations();
}
- // Resolve any relocations.
- Dyld.resolveRelocations();
+ StringRef EHData = Dyld.getEHFrameSection();
+ if (!EHData.empty())
+ MemMgr->registerEHFrames(EHData);
// Set page permissions.
MemMgr->applyPermissions();
diff --git a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
index da931247b6..bac77ce75f 100644
--- a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
+++ b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
@@ -146,6 +146,38 @@ bool SectionMemoryManager::applyPermissions(std::string *ErrMsg)
return false;
}
+// Determine whether we can register EH tables.
+#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
+ !defined(__USING_SJLJ_EXCEPTIONS__))
+#define HAVE_EHTABLE_SUPPORT 1
+#else
+#define HAVE_EHTABLE_SUPPORT 0
+#endif
+
+#if HAVE_EHTABLE_SUPPORT
+extern "C" void __register_frame(void*);
+
+static const char *processFDE(const char *Entry) {
+ const char *P = Entry;
+ uint32_t Length = *((uint32_t*)P);
+ P += 4;
+ uint32_t Offset = *((uint32_t*)P);
+ if (Offset != 0)
+ __register_frame((void*)Entry);
+ return P + Length;
+}
+#endif
+
+void SectionMemoryManager::registerEHFrames(StringRef SectionData) {
+#if HAVE_EHTABLE_SUPPORT
+ const char *P = SectionData.data();
+ const char *End = SectionData.data() + SectionData.size();
+ do {
+ P = processFDE(P);
+ } while(P != End);
+#endif
+}
+
error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
unsigned Permissions) {
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 714eaf48cf..a08b508a8d 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -25,10 +25,15 @@ using namespace llvm::object;
// Empty out-of-line virtual destructor as the key function.
RTDyldMemoryManager::~RTDyldMemoryManager() {}
+void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {}
RuntimeDyldImpl::~RuntimeDyldImpl() {}
namespace llvm {
+StringRef RuntimeDyldImpl::getEHFrameSection() {
+ return StringRef();
+}
+
// Resolve the relocations for all symbols we currently know about.
void RuntimeDyldImpl::resolveRelocations() {
// First, resolve relocations associated with external symbols.
@@ -174,7 +179,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
if (!Addr)
report_fatal_error("Unable to allocate memory for common symbols!");
uint64_t Offset = 0;
- Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, TotalSize, 0));
+ Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, 0));
memset(Addr, 0, TotalSize);
DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID
@@ -292,8 +297,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
<< "\n");
}
- Sections.push_back(SectionEntry(Name, Addr, Allocate, DataSize,
- (uintptr_t)pData));
+ Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData));
return SectionID;
}
@@ -544,4 +548,8 @@ StringRef RuntimeDyld::getErrorString() {
return Dyld->getErrorString();
}
+StringRef RuntimeDyld::getEHFrameSection() {
+ return Dyld->getEHFrameSection();
+}
+
} // end namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 80231a7c04..004f4f2996 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -151,6 +151,14 @@ void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef,
namespace llvm {
+StringRef RuntimeDyldELF::getEHFrameSection() {
+ for (int i = 0, e = Sections.size(); i != e; ++i) {
+ if (Sections[i].Name == ".eh_frame")
+ return StringRef((const char*)Sections[i].Address, Sections[i].Size);
+ }
+ return StringRef();
+}
+
ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) {
if (Buffer->getBufferSize() < ELF::EI_NIDENT)
llvm_unreachable("Unexpected ELF object size");
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
index 238254440e..794c7ece10 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
@@ -96,6 +96,7 @@ public:
StubMap &Stubs);
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
+ virtual StringRef getEHFrameSection();
virtual ~RuntimeDyldELF();
};
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index b09e71ed4b..383ffab521 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -49,7 +49,7 @@ public:
/// Address - address in the linker's memory where the section resides.
uint8_t *Address;
- /// Size - section size.
+ /// Size - section size. Doesn't include the stubs.
size_t Size;
/// LoadAddress - the address of the section in the target process's memory.
@@ -67,9 +67,9 @@ public:
uintptr_t ObjAddress;
SectionEntry(StringRef name, uint8_t *address, size_t size,
- uintptr_t stubOffset, uintptr_t objAddress)
+ uintptr_t objAddress)
: Name(name), Address(address), Size(size), LoadAddress((uintptr_t)address),
- StubOffset(stubOffset), ObjAddress(objAddress) {}
+ StubOffset(size), ObjAddress(objAddress) {}
};
/// RelocationEntry - used to represent relocations internally in the dynamic
@@ -174,6 +174,8 @@ protected:
return 16;
else if (Arch == Triple::ppc64)
return 44;
+ else if (Arch == Triple::x86_64)
+ return 8; // GOT
else if (Arch == Triple::systemz)
return 16;
else
@@ -332,6 +334,8 @@ public:
StringRef getErrorString() { return ErrorStr; }
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0;
+
+ virtual StringRef getEHFrameSection();
};
} // end namespace llvm
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
index b3467a9ab3..01a3fd9f82 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
@@ -21,6 +21,69 @@ using namespace llvm::object;
namespace llvm {
+static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) {
+ uint32_t Length = *((uint32_t*)P);
+ P += 4;
+ unsigned char *Ret = P + Length;
+ uint32_t Offset = *((uint32_t*)P);
+ if (Offset == 0) // is a CIE
+ return Ret;
+
+ P += 4;
+ intptr_t FDELocation = *((intptr_t*)P);
+ intptr_t NewLocation = FDELocation - DeltaForText;
+ *((intptr_t*)P) = NewLocation;
+ P += sizeof(intptr_t);
+
+ // Skip the FDE address range
+ P += sizeof(intptr_t);
+
+ uint8_t Augmentationsize = *P;
+ P += 1;
+ if (Augmentationsize != 0) {
+ intptr_t LSDA = *((intptr_t*)P);
+ intptr_t NewLSDA = LSDA - DeltaForEH;
+ *((intptr_t*)P) = NewLSDA;
+ }
+
+ return Ret;
+}
+
+static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) {
+ intptr_t ObjDistance = A->ObjAddress - B->ObjAddress;
+ intptr_t MemDistance = A->LoadAddress - B->LoadAddress;
+ return ObjDistance - MemDistance;
+}
+
+StringRef RuntimeDyldMachO::getEHFrameSection() {
+ SectionEntry *Text = NULL;
+ SectionEntry *EHFrame = NULL;
+ SectionEntry *ExceptTab = NULL;
+ for (int i = 0, e = Sections.size(); i != e; ++i) {
+ if (Sections[i].Name == "__eh_frame")
+ EHFrame = &Sections[i];
+ else if (Sections[i].Name == "__text")
+ Text = &Sections[i];
+ else if (Sections[i].Name == "__gcc_except_tab")
+ ExceptTab = &Sections[i];
+ }
+ if (Text == NULL || EHFrame == NULL)
+ return StringRef();
+
+ intptr_t DeltaForText = computeDelta(Text, EHFrame);
+ intptr_t DeltaForEH = 0;
+ if (ExceptTab)
+ DeltaForEH = computeDelta(ExceptTab, EHFrame);
+
+ unsigned char *P = EHFrame->Address;
+ unsigned char *End = P + EHFrame->Size;
+ do {
+ P = processFDE(P, DeltaForText, DeltaForEH);
+ } while(P != End);
+
+ return StringRef((char*)EHFrame->Address, EHFrame->Size);
+}
+
void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE,
uint64_t Value) {
const SectionEntry &Section = Sections[RE.SectionID];
@@ -267,7 +330,30 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
Value.Addend = Addend - Addr;
}
- if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) {
+ if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) {
+ assert(IsPCRel);
+ assert(Size == 2);
+ StubMap::const_iterator i = Stubs.find(Value);
+ uint8_t *Addr;
+ if (i != Stubs.end()) {
+ Addr = Section.Address + i->second;
+ } else {
+ Stubs[Value] = Section.StubOffset;
+ uint8_t *GOTEntry = Section.Address + Section.StubOffset;
+ RelocationEntry RE(SectionID, Section.StubOffset,
+ macho::RIT_X86_64_Unsigned, Value.Addend - 4, false,
+ 3);
+ if (Value.SymbolName)
+ addRelocationForSymbol(RE, Value.SymbolName);
+ else
+ addRelocationForSection(RE, Value.SectionID);
+ Section.StubOffset += 8;
+ Addr = GOTEntry;
+ }
+ resolveRelocation(Section, Offset, (uint64_t)Addr,
+ macho::RIT_X86_64_Unsigned, 4, true, 2);
+ } else if (Arch == Triple::arm &&
+ (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) {
// This is an ARM branch relocation, need to use a stub function.
// Look up for existing stub.
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
index 8da6e35a87..df8d3bb482 100644
--- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
@@ -65,6 +65,7 @@ public:
const SymbolTableMap &Symbols,
StubMap &Stubs);
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
+ virtual StringRef getEHFrameSection();
};
} // end namespace llvm