Adding multiple object support to MCJIT EH frame handling
authorAndrew Kaylor <andrew.kaylor@intel.com>
Fri, 11 Oct 2013 21:25:48 +0000 (21:25 +0000)
committerAndrew Kaylor <andrew.kaylor@intel.com>
Fri, 11 Oct 2013 21:25:48 +0000 (21:25 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192504 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/llvm/ExecutionEngine/RTDyldMemoryManager.h
include/llvm/ExecutionEngine/RuntimeDyld.h
lib/ExecutionEngine/MCJIT/MCJIT.cpp
lib/ExecutionEngine/MCJIT/MCJIT.h
lib/ExecutionEngine/RTDyldMemoryManager.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
test/ExecutionEngine/MCJIT/multi-module-eh-a.ll [new file with mode: 0644]
test/ExecutionEngine/MCJIT/multi-module-eh-b.ir [new file with mode: 0644]
tools/lli/RemoteMemoryManager.cpp
tools/lli/RemoteMemoryManager.h

index 09a5cb4884082b10bbf17586bed720f96879d5b3..468b8234c988098b1462c078794f210c6f6b57e7 100644 (file)
@@ -53,7 +53,12 @@ public:
     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.
index 1a573171a457e73f8ce1d1ce83691bbfeb8d920c..a5610fbe3bed1bb710f300f05be317446e822491 100644 (file)
@@ -64,9 +64,14 @@ public:
   /// 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
index 541ba9eb62b144505970edc3934243e20649e5a9..fa2c9842d9ef4b17a19d08c4fa81ca3be97a5fa3 100644 (file)
@@ -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();
 }
@@ -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();
 }
@@ -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();
index 6969ff13c001628f5004787723ed81b8edf7e8bb..fe59288aeab85086c1eb88d7eaf8d373cc0da72d 100644 (file)
@@ -51,8 +51,8 @@ public:
     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) {
index de38b38d64ba2ad1030a477a0e1cde717820ab9d..99265760be17d16680d44eecf1b824cf4a0c157f 100644 (file)
@@ -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);
index 077442d8dfb10e95f59c8ad62a0933f2823c0bcd..1b9e0bf035ff5e39fb3a9bc3e08b47318cf0e084 100644 (file)
@@ -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.
@@ -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();
 }
@@ -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
index a438dcd87991159f11341374cd2adf833b273521..97e03f0694968e1f8a0428691d5eda283d482253 100644 (file)
@@ -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) {
@@ -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();
@@ -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 {
index 67dc693b1b6840d2ef214dc9d29331804d47533f..ab6b8bdaf3d44b238192334f575e5ecca14394fa 100644 (file)
@@ -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)
                                           {}
@@ -112,8 +116,8 @@ public:
                                     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();
 };
 
index 11f77febd5fa7d49a9aad11ba39a7b6f043ab3a7..5796c7cd39f7f81b3ab755b752fdf1acf67cef21 100644 (file)
@@ -147,6 +147,9 @@ protected:
   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;
@@ -357,9 +360,9 @@ public:
 
   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
index 1bf47d55a7f2dc2f1bc62a5a195c44a50b539528..5b92867b4778b3dd76f7889b0d5e68c99ae241f3 100644 (file)
@@ -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
index df8d3bb482060b2eba48dcaa463bb0309c129aba..3906c9d56d6180cac72928cd0fb70a4a50351eb2 100644 (file)
@@ -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) {}
 
@@ -65,7 +81,8 @@ public:
                                     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
diff --git a/test/ExecutionEngine/MCJIT/multi-module-eh-a.ll b/test/ExecutionEngine/MCJIT/multi-module-eh-a.ll
new file mode 100644 (file)
index 0000000..89035e6
--- /dev/null
@@ -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
+}
diff --git a/test/ExecutionEngine/MCJIT/multi-module-eh-b.ir b/test/ExecutionEngine/MCJIT/multi-module-eh-b.ir
new file mode 100644 (file)
index 0000000..d7dbb03
--- /dev/null
@@ -0,0 +1,30 @@
+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*
+
+define void @throwException_B() {
+  %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 @FB() {
+entry:
+  invoke void @throwException_B()
+          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:
+  ret i32 0
+}
index 8ccfde8fc775913a8a62a95cf5a857c8e633b910..04fc40e426f0c90323859a79df6ac4350bbd0528 100644 (file)
@@ -204,27 +204,3 @@ uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment)
 void RemoteMemoryManager::deallocateFunctionBody(void *Body) {
   llvm_unreachable("Unexpected!");
 }
-
-static int jit_noop() {
-  return 0;
-}
-
-void *RemoteMemoryManager::getPointerToNamedFunction(const std::string &Name,
-                                                        bool AbortOnFailure) {
-  // We should not invoke parent's ctors/dtors from generated main()!
-  // On Mingw and Cygwin, the symbol __main is resolved to
-  // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
-  // (and register wrong callee's dtors with atexit(3)).
-  // We expect ExecutionEngine::runStaticConstructorsDestructors()
-  // is called before ExecutionEngine::runFunctionAsMain() is called.
-  if (Name == "__main") return (void*)(intptr_t)&jit_noop;
-
-  // FIXME: Would it be responsible to provide GOT?
-  if (AbortOnFailure) {
-    if (Name == "_GLOBAL_OFFSET_TABLE_")
-      report_fatal_error("Program used external function '" + Name +
-                         "' which could not be resolved!");
-  }
-
-  return NULL;
-}
index ca157a79298c7e72c51e3088235de4839ef3dc12..eabe042fff052ad9f71c8bdcb5f48e06d6076469 100644 (file)
@@ -74,13 +74,20 @@ public:
                                unsigned SectionID, StringRef SectionName,
                                bool IsReadOnly);
 
-  void *getPointerToNamedFunction(const std::string &Name,
-                                  bool AbortOnFailure = true);
+  // For now, remote symbol resolution is not support in lli.  The MCJIT
+  // interface does support this, but clients must provide their own
+  // mechanism for finding remote symbol addresses.  MCJIT will resolve
+  // symbols from Modules it contains.
+  uint64_t getSymbolAddress(const std::string &Name) {}
 
   void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj);
 
   bool finalizeMemory(std::string *ErrMsg);
 
+  // For now, remote EH frame registration isn't supported.  Remote symbol
+  // resolution is a prerequisite to supporting remote EH frame registration.
+  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {}
+
   // This is a non-interface function used by lli
   void setRemoteTarget(RemoteTarget *T) { Target = T; }