mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
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
This commit is contained in:
parent
9f2bebbc28
commit
a2e40fbd62
@ -66,6 +66,11 @@ public:
|
||||
///
|
||||
/// Returns true if an error occurred, false otherwise.
|
||||
virtual bool applyPermissions(std::string *ErrMsg = 0) = 0;
|
||||
|
||||
/// Register the EH frames with the runtime so that c++ exceptions work. The
|
||||
/// default implementation does nothing. Look at SectionMemoryManager for one
|
||||
/// that uses __register_frame.
|
||||
virtual void registerEHFrames(StringRef SectionData);
|
||||
};
|
||||
|
||||
class RuntimeDyld {
|
||||
@ -109,6 +114,8 @@ public:
|
||||
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);
|
||||
|
||||
StringRef getErrorString();
|
||||
|
||||
StringRef getEHFrameSection();
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -72,6 +72,8 @@ public:
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
virtual bool applyPermissions(std::string *ErrMsg = 0);
|
||||
|
||||
void registerEHFrames(StringRef SectionData);
|
||||
|
||||
/// This method returns the address of the specified function. As such it is
|
||||
/// only useful for resolving library symbols, not code generated symbols.
|
||||
///
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -96,6 +96,7 @@ public:
|
||||
StubMap &Stubs);
|
||||
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
|
||||
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
|
||||
virtual StringRef getEHFrameSection();
|
||||
virtual ~RuntimeDyldELF();
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
const SymbolTableMap &Symbols,
|
||||
StubMap &Stubs);
|
||||
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
|
||||
virtual StringRef getEHFrameSection();
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
26
test/ExecutionEngine/MCJIT/eh.ll
Normal file
26
test/ExecutionEngine/MCJIT/eh.ll
Normal file
@ -0,0 +1,26 @@
|
||||
; RUN: %lli_mcjit %s
|
||||
declare i8* @__cxa_allocate_exception(i64)
|
||||
declare void @__cxa_throw(i8*, i8*, i8*)
|
||||
declare i32 @__gxx_personality_v0(...)
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
|
||||
define void @throwException() {
|
||||
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
||||
call void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
invoke void @throwException()
|
||||
to label %try.cont unwind label %lpad
|
||||
|
||||
lpad:
|
||||
%p = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
||||
catch i8* bitcast (i8** @_ZTIi to i8*)
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
ret i32 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user