Skip to content

Commit

Permalink
Adding multiple object support to MCJIT EH frame handling
Browse files Browse the repository at this point in the history
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192504 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Andrew Kaylor committed Oct 11, 2013
1 parent b19b474 commit 528f6d7
Show file tree
Hide file tree
Showing 15 changed files with 210 additions and 88 deletions.
7 changes: 6 additions & 1 deletion include/llvm/ExecutionEngine/RTDyldMemoryManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ class RTDyldMemoryManager {
StringRef SectionName, bool IsReadOnly) = 0;

/// Register the EH frames with the runtime so that c++ exceptions work.
virtual void registerEHFrames(StringRef SectionData);
///
/// \p Addr parameter provides the local address of the EH frame section
/// data, while \p LoadAddr provides the address of the data in the target
/// address space. If the section has not been remapped (which will usually
/// be the case for local execution) these two values will be the same.
virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size);

/// This method returns the address of the specified function or variable.
/// It is used to resolve symbols during module linking.
Expand Down
9 changes: 7 additions & 2 deletions include/llvm/ExecutionEngine/RuntimeDyld.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,14 @@ class RuntimeDyld {
/// This is the address which will be used for relocation resolution.
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);

StringRef getErrorString();
/// Register any EH frame sections that have been loaded but not previously
/// registered with the memory manager. Note, RuntimeDyld is responsible
/// for identifying the EH frame and calling the memory manager with the
/// EH frame section data. However, the memory manager itself will handle
/// the actual target-specific EH frame registration.
void registerEHFrames();

StringRef getEHFrameSection();
StringRef getErrorString();
};

} // end namespace llvm
Expand Down
17 changes: 5 additions & 12 deletions lib/ExecutionEngine/MCJIT/MCJIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,12 @@ void MCJIT::finalizeLoadedModules() {

if (ModuleStates[M].hasBeenLoaded() &&
!ModuleStates[M].hasBeenFinalized()) {
// FIXME: This should be module specific!
StringRef EHData = Dyld.getEHFrameSection();
if (!EHData.empty())
MemMgr.registerEHFrames(EHData);
ModuleStates[M] = ModuleFinalized;
}
}

Dyld.registerEHFrames();

// Set page permissions.
MemMgr.finalizeMemory();
}
Expand Down Expand Up @@ -221,14 +219,12 @@ void MCJIT::finalizeObject() {

if (ModuleStates[M].hasBeenLoaded() &&
!ModuleStates[M].hasBeenFinalized()) {
// FIXME: This should be module specific!
StringRef EHData = Dyld.getEHFrameSection();
if (!EHData.empty())
MemMgr.registerEHFrames(EHData);
ModuleStates[M] = ModuleFinalized;
}
}

Dyld.registerEHFrames();

// Set page permissions.
MemMgr.finalizeMemory();
}
Expand All @@ -248,10 +244,7 @@ void MCJIT::finalizeModule(Module *M) {
// Resolve any outstanding relocations.
Dyld.resolveRelocations();

// FIXME: Should this be module specific?
StringRef EHData = Dyld.getEHFrameSection();
if (!EHData.empty())
MemMgr.registerEHFrames(EHData);
Dyld.registerEHFrames();

// Set page permissions.
MemMgr.finalizeMemory();
Expand Down
4 changes: 2 additions & 2 deletions lib/ExecutionEngine/MCJIT/MCJIT.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class LinkingMemoryManager : public RTDyldMemoryManager {
ClientMM->notifyObjectLoaded(EE, Obj);
}

virtual void registerEHFrames(StringRef SectionData) {
ClientMM->registerEHFrames(SectionData);
virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
ClientMM->registerEHFrames(Addr, LoadAddr, Size);
}

virtual bool finalizeMemory(std::string *ErrMsg = 0) {
Expand Down
11 changes: 8 additions & 3 deletions lib/ExecutionEngine/RTDyldMemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,15 @@ static const char *processFDE(const char *Entry) {
}
#endif

void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {
// This implementation handles frame registration for local targets.
// Memory managers for remote targets should re-implement this function
// and use the LoadAddr parameter.
void RTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
uint64_t LoadAddr,
size_t Size) {
#if HAVE_EHTABLE_SUPPORT
const char *P = SectionData.data();
const char *End = SectionData.data() + SectionData.size();
const char *P = (const char *)Addr;
const char *End = P + Size;
do {
P = processFDE(P);
} while(P != End);
Expand Down
9 changes: 4 additions & 5 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ RuntimeDyldImpl::~RuntimeDyldImpl() {}

namespace llvm {

StringRef RuntimeDyldImpl::getEHFrameSection() {
return StringRef();
void RuntimeDyldImpl::registerEHFrames() {
}

// Resolve the relocations for all symbols we currently know about.
Expand Down Expand Up @@ -171,7 +170,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) {
}

// Give the subclasses a chance to tie-up any loose ends.
finalizeLoad();
finalizeLoad(LocalSections);

return obj.take();
}
Expand Down Expand Up @@ -592,8 +591,8 @@ StringRef RuntimeDyld::getErrorString() {
return Dyld->getErrorString();
}

StringRef RuntimeDyld::getEHFrameSection() {
return Dyld->getEHFrameSection();
void RuntimeDyld::registerEHFrames() {
return Dyld->registerEHFrames();
}

} // end namespace llvm
30 changes: 24 additions & 6 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,17 @@ 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);
void RuntimeDyldELF::registerEHFrames() {
if (!MemMgr)
return;
for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) {
SID EHFrameSID = UnregisteredEHFrameSections[i];
uint8_t *EHFrameAddr = Sections[EHFrameSID].Address;
uint64_t EHFrameLoadAddr = Sections[EHFrameSID].LoadAddress;
size_t EHFrameSize = Sections[EHFrameSID].Size;
MemMgr->registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
}
return StringRef();
UnregisteredEHFrameSections.clear();
}

ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) {
Expand Down Expand Up @@ -1342,7 +1347,8 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress,
return 0;
}

void RuntimeDyldELF::finalizeLoad() {
void RuntimeDyldELF::finalizeLoad(ObjSectionToIDMap &SectionMap) {
// If necessary, allocate the global offset table
if (MemMgr) {
// Allocate the GOT if necessary
size_t numGOTEntries = GOTEntries.size();
Expand All @@ -1365,6 +1371,18 @@ void RuntimeDyldELF::finalizeLoad() {
else {
report_fatal_error("Unable to allocate memory for GOT!");
}

// Look for and record the EH frame section.
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") {
UnregisteredEHFrameSections.push_back(i->second);
break;
}
}
}

bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const {
Expand Down
10 changes: 7 additions & 3 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,15 @@ class RuntimeDyldELF : public RuntimeDyldImpl {

// Relocation entries for symbols whose position-independant offset is
// updated in a global offset table.
typedef unsigned SID; // Type for SectionIDs
typedef SmallVector<RelocationValueRef, 2> GOTRelocations;
GOTRelocations GOTEntries; // List of entries requiring finalization.
SmallVector<std::pair<SID, GOTRelocations>, 8> GOTs; // Allocated tables.

// When a module is loaded we save the SectionID of the EH frame section
// in a table until we receive a request to register all unregistered
// EH frame sections with the memory manager.
SmallVector<SID, 2> UnregisteredEHFrameSections;

public:
RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm)
{}
Expand All @@ -112,8 +116,8 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
StubMap &Stubs);
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
virtual StringRef getEHFrameSection();
virtual void finalizeLoad();
virtual void registerEHFrames();
virtual void finalizeLoad(ObjSectionToIDMap &SectionMap);
virtual ~RuntimeDyldELF();
};

Expand Down
7 changes: 5 additions & 2 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ class RuntimeDyldImpl {
typedef SmallVector<SectionEntry, 64> SectionList;
SectionList Sections;

typedef unsigned SID; // Type for SectionIDs
#define RTDYLD_INVALID_SECTION_ID ((SID)(-1))

// Keep a map of sections from object file to the SectionID which
// references it.
typedef std::map<SectionRef, unsigned> ObjSectionToIDMap;
Expand Down Expand Up @@ -357,9 +360,9 @@ class RuntimeDyldImpl {

virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0;

virtual StringRef getEHFrameSection();
virtual void registerEHFrames();

virtual void finalizeLoad() {}
virtual void finalizeLoad(ObjSectionToIDMap &SectionMap) {}
};

} // end namespace llvm
Expand Down
75 changes: 50 additions & 25 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,58 @@ static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) {
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);
void RuntimeDyldMachO::registerEHFrames() {

unsigned char *P = EHFrame->Address;
unsigned char *End = P + EHFrame->Size;
do {
P = processFDE(P, DeltaForText, DeltaForEH);
} while(P != End);
if (!MemMgr)
return;
for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) {
EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i];
if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID ||
SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID)
continue;
SectionEntry *Text = &Sections[SectionInfo.TextSID];
SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID];
SectionEntry *ExceptTab = NULL;
if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID)
ExceptTab = &Sections[SectionInfo.ExceptTabSID];

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);

MemMgr->registerEHFrames(EHFrame->Address,
EHFrame->LoadAddress,
EHFrame->Size);
}
UnregisteredEHFrameSections.clear();
}

return StringRef((char*)EHFrame->Address, EHFrame->Size);
void RuntimeDyldMachO::finalizeLoad(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;
}
UnregisteredEHFrameSections.push_back(EHFrameRelatedSections(EHFrameSID,
TextSID,
ExceptTabSID));
}

// The target location for the relocation is described by RE.SectionID and
Expand Down
19 changes: 18 additions & 1 deletion lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ class RuntimeDyldMachO : public RuntimeDyldImpl {
int64_t Addend,
bool isPCRel,
unsigned Size);

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;
SID TextSID;
SID ExceptTabSID;
};

// When a module is loaded we save the SectionID of the EH frame section
// in a table until we receive a request to register all unregistered
// EH frame sections with the memory manager.
SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections;
public:
RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}

Expand All @@ -65,7 +81,8 @@ class RuntimeDyldMachO : public RuntimeDyldImpl {
const SymbolTableMap &Symbols,
StubMap &Stubs);
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
virtual StringRef getEHFrameSection();
virtual void registerEHFrames();
virtual void finalizeLoad(ObjSectionToIDMap &SectionMap);
};

} // end namespace llvm
Expand Down
35 changes: 35 additions & 0 deletions test/ExecutionEngine/MCJIT/multi-module-eh-a.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
; RUN: %lli_mcjit -extra-modules=%p/multi-module-eh-b.ir %s
; XFAIL: arm, cygwin, win32, mingw
declare i8* @__cxa_allocate_exception(i64)
declare void @__cxa_throw(i8*, i8*, i8*)
declare i32 @__gxx_personality_v0(...)
declare void @__cxa_end_catch()
declare i8* @__cxa_begin_catch(i8*)

@_ZTIi = external constant i8*

declare i32 @FB()

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*)
%e = extractvalue { i8*, i32 } %p, 0
call i8* @__cxa_begin_catch(i8* %e)
call void @__cxa_end_catch()
br label %try.cont

try.cont:
%r = call i32 @FB( )
ret i32 %r
}
Loading

0 comments on commit 528f6d7

Please sign in to comment.