mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +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.
|
/// Returns true if an error occurred, false otherwise.
|
||||||
virtual bool applyPermissions(std::string *ErrMsg = 0) = 0;
|
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 {
|
class RuntimeDyld {
|
||||||
@ -109,6 +114,8 @@ public:
|
|||||||
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);
|
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);
|
||||||
|
|
||||||
StringRef getErrorString();
|
StringRef getErrorString();
|
||||||
|
|
||||||
|
StringRef getEHFrameSection();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -72,6 +72,8 @@ public:
|
|||||||
/// \returns true if an error occurred, false otherwise.
|
/// \returns true if an error occurred, false otherwise.
|
||||||
virtual bool applyPermissions(std::string *ErrMsg = 0);
|
virtual bool applyPermissions(std::string *ErrMsg = 0);
|
||||||
|
|
||||||
|
void registerEHFrames(StringRef SectionData);
|
||||||
|
|
||||||
/// This method returns the address of the specified function. As such it is
|
/// This method returns the address of the specified function. As such it is
|
||||||
/// only useful for resolving library symbols, not code generated symbols.
|
/// 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()
|
// If the call to Dyld.resolveRelocations() is removed from loadObject()
|
||||||
// we'll need to do that here.
|
// we'll need to do that here.
|
||||||
loadObject(M);
|
loadObject(M);
|
||||||
|
} else {
|
||||||
// Set page permissions.
|
// Resolve any relocations.
|
||||||
MemMgr->applyPermissions();
|
Dyld.resolveRelocations();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve any relocations.
|
StringRef EHData = Dyld.getEHFrameSection();
|
||||||
Dyld.resolveRelocations();
|
if (!EHData.empty())
|
||||||
|
MemMgr->registerEHFrames(EHData);
|
||||||
|
|
||||||
// Set page permissions.
|
// Set page permissions.
|
||||||
MemMgr->applyPermissions();
|
MemMgr->applyPermissions();
|
||||||
|
@ -146,6 +146,38 @@ bool SectionMemoryManager::applyPermissions(std::string *ErrMsg)
|
|||||||
return false;
|
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,
|
error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
|
||||||
unsigned Permissions) {
|
unsigned Permissions) {
|
||||||
|
|
||||||
|
@ -25,10 +25,15 @@ using namespace llvm::object;
|
|||||||
|
|
||||||
// Empty out-of-line virtual destructor as the key function.
|
// Empty out-of-line virtual destructor as the key function.
|
||||||
RTDyldMemoryManager::~RTDyldMemoryManager() {}
|
RTDyldMemoryManager::~RTDyldMemoryManager() {}
|
||||||
|
void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {}
|
||||||
RuntimeDyldImpl::~RuntimeDyldImpl() {}
|
RuntimeDyldImpl::~RuntimeDyldImpl() {}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
StringRef RuntimeDyldImpl::getEHFrameSection() {
|
||||||
|
return StringRef();
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve the relocations for all symbols we currently know about.
|
// Resolve the relocations for all symbols we currently know about.
|
||||||
void RuntimeDyldImpl::resolveRelocations() {
|
void RuntimeDyldImpl::resolveRelocations() {
|
||||||
// First, resolve relocations associated with external symbols.
|
// First, resolve relocations associated with external symbols.
|
||||||
@ -174,7 +179,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
|
|||||||
if (!Addr)
|
if (!Addr)
|
||||||
report_fatal_error("Unable to allocate memory for common symbols!");
|
report_fatal_error("Unable to allocate memory for common symbols!");
|
||||||
uint64_t Offset = 0;
|
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);
|
memset(Addr, 0, TotalSize);
|
||||||
|
|
||||||
DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID
|
DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID
|
||||||
@ -292,8 +297,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
|
|||||||
<< "\n");
|
<< "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
Sections.push_back(SectionEntry(Name, Addr, Allocate, DataSize,
|
Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData));
|
||||||
(uintptr_t)pData));
|
|
||||||
return SectionID;
|
return SectionID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,4 +548,8 @@ StringRef RuntimeDyld::getErrorString() {
|
|||||||
return Dyld->getErrorString();
|
return Dyld->getErrorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringRef RuntimeDyld::getEHFrameSection() {
|
||||||
|
return Dyld->getEHFrameSection();
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -151,6 +151,14 @@ void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef,
|
|||||||
|
|
||||||
namespace llvm {
|
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) {
|
ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) {
|
||||||
if (Buffer->getBufferSize() < ELF::EI_NIDENT)
|
if (Buffer->getBufferSize() < ELF::EI_NIDENT)
|
||||||
llvm_unreachable("Unexpected ELF object size");
|
llvm_unreachable("Unexpected ELF object size");
|
||||||
|
@ -96,6 +96,7 @@ public:
|
|||||||
StubMap &Stubs);
|
StubMap &Stubs);
|
||||||
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
|
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
|
||||||
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
|
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
|
||||||
|
virtual StringRef getEHFrameSection();
|
||||||
virtual ~RuntimeDyldELF();
|
virtual ~RuntimeDyldELF();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public:
|
|||||||
/// Address - address in the linker's memory where the section resides.
|
/// Address - address in the linker's memory where the section resides.
|
||||||
uint8_t *Address;
|
uint8_t *Address;
|
||||||
|
|
||||||
/// Size - section size.
|
/// Size - section size. Doesn't include the stubs.
|
||||||
size_t Size;
|
size_t Size;
|
||||||
|
|
||||||
/// LoadAddress - the address of the section in the target process's memory.
|
/// LoadAddress - the address of the section in the target process's memory.
|
||||||
@ -67,9 +67,9 @@ public:
|
|||||||
uintptr_t ObjAddress;
|
uintptr_t ObjAddress;
|
||||||
|
|
||||||
SectionEntry(StringRef name, uint8_t *address, size_t size,
|
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),
|
: 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
|
/// RelocationEntry - used to represent relocations internally in the dynamic
|
||||||
@ -174,6 +174,8 @@ protected:
|
|||||||
return 16;
|
return 16;
|
||||||
else if (Arch == Triple::ppc64)
|
else if (Arch == Triple::ppc64)
|
||||||
return 44;
|
return 44;
|
||||||
|
else if (Arch == Triple::x86_64)
|
||||||
|
return 8; // GOT
|
||||||
else if (Arch == Triple::systemz)
|
else if (Arch == Triple::systemz)
|
||||||
return 16;
|
return 16;
|
||||||
else
|
else
|
||||||
@ -332,6 +334,8 @@ public:
|
|||||||
StringRef getErrorString() { return ErrorStr; }
|
StringRef getErrorString() { return ErrorStr; }
|
||||||
|
|
||||||
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0;
|
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0;
|
||||||
|
|
||||||
|
virtual StringRef getEHFrameSection();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -21,6 +21,69 @@ using namespace llvm::object;
|
|||||||
|
|
||||||
namespace llvm {
|
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,
|
void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE,
|
||||||
uint64_t Value) {
|
uint64_t Value) {
|
||||||
const SectionEntry &Section = Sections[RE.SectionID];
|
const SectionEntry &Section = Sections[RE.SectionID];
|
||||||
@ -267,7 +330,30 @@ void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
|
|||||||
Value.Addend = Addend - Addr;
|
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.
|
// This is an ARM branch relocation, need to use a stub function.
|
||||||
|
|
||||||
// Look up for existing stub.
|
// Look up for existing stub.
|
||||||
|
@ -65,6 +65,7 @@ public:
|
|||||||
const SymbolTableMap &Symbols,
|
const SymbolTableMap &Symbols,
|
||||||
StubMap &Stubs);
|
StubMap &Stubs);
|
||||||
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
|
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
|
||||||
|
virtual StringRef getEHFrameSection();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // 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