Interface changes to allow RuntimeDyld memory managers to set memory permissions...
authorAndrew Kaylor <andrew.kaylor@intel.com>
Thu, 15 Nov 2012 23:50:01 +0000 (23:50 +0000)
committerAndrew Kaylor <andrew.kaylor@intel.com>
Thu, 15 Nov 2012 23:50:01 +0000 (23:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168114 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ExecutionEngine/RuntimeDyld.h
lib/ExecutionEngine/JIT/JITMemoryManager.cpp
lib/ExecutionEngine/MCJIT/MCJIT.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
tools/lli/RecordingMemoryManager.cpp
tools/lli/RecordingMemoryManager.h
tools/lli/lli.cpp
tools/llvm-rtdyld/llvm-rtdyld.cpp
unittests/ExecutionEngine/JIT/JITTest.cpp
unittests/ExecutionEngine/MCJIT/SectionMemoryManager.cpp
unittests/ExecutionEngine/MCJIT/SectionMemoryManager.h

index 891f534862f4d2432ec17bda7e2978c9d200f67f..c3d160f0125b858a3a91af71c24fc52c9c5203da 100644 (file)
@@ -48,7 +48,7 @@ public:
   /// assigned by the JIT engine, and optionally recorded by the memory manager
   /// to access a loaded section.
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
   /// assigned by the JIT engine, and optionally recorded by the memory manager
   /// to access a loaded section.
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                                       unsigned SectionID) = 0;
+                                       unsigned SectionID, bool IsReadOnly) = 0;
 
   /// getPointerToNamedFunction - This method returns the address of the
   /// specified function. As such it is only useful for resolving library
 
   /// getPointerToNamedFunction - This method returns the address of the
   /// specified function. As such it is only useful for resolving library
@@ -59,6 +59,15 @@ public:
   /// message to stderr and aborts.
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true) = 0;
   /// message to stderr and aborts.
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true) = 0;
+
+  /// applyPermissions - This method is called when object loading is
+  /// complete and section page permissions can be applied.  It is up to
+  /// the memory manager implementation to decide whether or not to act
+  /// on this method.  The memory manager will typically allocate all 
+  /// sections as read-write and then apply specific permissions when
+  /// this method is called.  Returns true if an error occurred, false
+  /// otherwise.
+  virtual bool applyPermissions(std::string *ErrMsg = 0) = 0;
 };
 
 class RuntimeDyld {
 };
 
 class RuntimeDyld {
index 61bc119d305bafb760bc5f27164bda4a5440ad73..bd0519e9c46435058fe2977c3b282203af14ef81 100644 (file)
@@ -501,10 +501,14 @@ namespace {
 
     /// allocateDataSection - Allocate memory for a data section.
     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
 
     /// allocateDataSection - Allocate memory for a data section.
     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                                 unsigned SectionID) {
+                                 unsigned SectionID, bool IsReadOnly) {
       return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
     }
 
       return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
     }
 
+    bool applyPermissions(std::string *ErrMsg) {
+      return false;
+    }
+
     /// startExceptionTable - Use startFunctionBody to allocate memory for the
     /// function's exception table.
     uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) {
     /// startExceptionTable - Use startFunctionBody to allocate memory for the
     /// function's exception table.
     uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) {
index 752c5b73ea324b0b2ad155f27b75ebae983051e3..d72e56378ba6c0dda8f2d1bd0c595fffcb1067aa 100644 (file)
@@ -118,17 +118,26 @@ void MCJIT::emitObject(Module *m) {
 
 // FIXME: Add a parameter to identify which object is being finalized when
 // MCJIT supports multiple modules.
 
 // FIXME: Add a parameter to identify which object is being finalized when
 // MCJIT supports multiple modules.
+// FIXME: Provide a way to separate code emission, relocations and page 
+// protection in the interface.
 void MCJIT::finalizeObject() {
   // If the module hasn't been compiled, just do that.
   if (!isCompiled) {
     // If the call to Dyld.resolveRelocations() is removed from emitObject()
     // we'll need to do that here.
     emitObject(M);
 void MCJIT::finalizeObject() {
   // If the module hasn't been compiled, just do that.
   if (!isCompiled) {
     // If the call to Dyld.resolveRelocations() is removed from emitObject()
     // we'll need to do that here.
     emitObject(M);
+
+    // Set page permissions.
+    MemMgr->applyPermissions();
+
     return;
   }
 
   // Resolve any relocations.
   Dyld.resolveRelocations();
     return;
   }
 
   // Resolve any relocations.
   Dyld.resolveRelocations();
+
+  // Set page permissions.
+  MemMgr->applyPermissions();
 }
 
 void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
 }
 
 void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
index f6dccb106d9bbe38e9b9e7bdbd0335c930ab727b..4118e8ad50954788374ab23b9e4490d1ec548a6f 100644 (file)
@@ -182,7 +182,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
   // Allocate memory for the section
   unsigned SectionID = Sections.size();
   uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, sizeof(void*),
   // Allocate memory for the section
   unsigned SectionID = Sections.size();
   uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, sizeof(void*),
-                                              SectionID);
+                                              SectionID, false);
   if (!Addr)
     report_fatal_error("Unable to allocate memory for common symbols!");
   uint64_t Offset = 0;
   if (!Addr)
     report_fatal_error("Unable to allocate memory for common symbols!");
   uint64_t Offset = 0;
@@ -237,11 +237,13 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
   bool IsRequired;
   bool IsVirtual;
   bool IsZeroInit;
   bool IsRequired;
   bool IsVirtual;
   bool IsZeroInit;
+  bool IsReadOnly;
   uint64_t DataSize;
   StringRef Name;
   Check(Section.isRequiredForExecution(IsRequired));
   Check(Section.isVirtual(IsVirtual));
   Check(Section.isZeroInit(IsZeroInit));
   uint64_t DataSize;
   StringRef Name;
   Check(Section.isRequiredForExecution(IsRequired));
   Check(Section.isVirtual(IsVirtual));
   Check(Section.isZeroInit(IsZeroInit));
+  Check(Section.isReadOnlyData(IsReadOnly));
   Check(Section.getSize(DataSize));
   Check(Section.getName(Name));
 
   Check(Section.getSize(DataSize));
   Check(Section.getName(Name));
 
@@ -256,7 +258,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
     Allocate = DataSize + StubBufSize;
     Addr = IsCode
       ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID)
     Allocate = DataSize + StubBufSize;
     Addr = IsCode
       ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID)
-      : MemMgr->allocateDataSection(Allocate, Alignment, SectionID);
+      : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, IsReadOnly);
     if (!Addr)
       report_fatal_error("Unable to allocate section memory!");
 
     if (!Addr)
       report_fatal_error("Unable to allocate section memory!");
 
@@ -451,6 +453,12 @@ void RuntimeDyldImpl::resolveExternalSymbols() {
 //===----------------------------------------------------------------------===//
 // RuntimeDyld class implementation
 RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) {
 //===----------------------------------------------------------------------===//
 // RuntimeDyld class implementation
 RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) {
+  // FIXME: There's a potential issue lurking here if a single instance of
+  // RuntimeDyld is used to load multiple objects.  The current implementation
+  // associates a single memory manager with a RuntimeDyld instance.  Even
+  // though the public class spawns a new 'impl' instance for each load,
+  // they share a single memory manager.  This can become a problem when page
+  // permissions are applied.
   Dyld = 0;
   MM = mm;
 }
   Dyld = 0;
   MM = mm;
 }
index 9e1cff55277d3130f34e09251d83467528609dcd..f54f17461e110a1c26e9612d51a2d0828aea215f 100644 (file)
@@ -28,7 +28,8 @@ allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
 }
 
 uint8_t *RecordingMemoryManager::
 }
 
 uint8_t *RecordingMemoryManager::
-allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
+allocateDataSection(uintptr_t Size, unsigned Alignment,
+                    unsigned SectionID, bool IsReadOnly) {
   // The recording memory manager is just a local copy of the remote target.
   // The alignment requirement is just stored here for later use. Regular
   // heap storage is sufficient here.
   // The recording memory manager is just a local copy of the remote target.
   // The alignment requirement is just stored here for later use. Regular
   // heap storage is sufficient here.
index 1590235a793cccbbe4d9a822619dc9a4beb8d486..20fd0c2e6ed79a2fbc6cd9e309b12dcdc174e6c4 100644 (file)
@@ -47,10 +47,13 @@ public:
                                        unsigned SectionID);
 
   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                                        unsigned SectionID);
 
   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                                       unsigned SectionID);
+                                       unsigned SectionID, bool IsReadOnly);
 
   void *getPointerToNamedFunction(const std::string &Name,
                                   bool AbortOnFailure = true);
 
   void *getPointerToNamedFunction(const std::string &Name,
                                   bool AbortOnFailure = true);
+
+  bool applyPermissions(std::string *ErrMsg) { return false; }
+
   // The following obsolete JITMemoryManager calls are stubbed out for
   // this model.
   void setMemoryWritable();
   // The following obsolete JITMemoryManager calls are stubbed out for
   // this model.
   void setMemoryWritable();
index d41a595de857132b06781d7a084e87dfb5192348..fa4669dec63ed269249d8070e04f5480ff248c02 100644 (file)
@@ -231,11 +231,13 @@ public:
                                        unsigned SectionID);
 
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                                        unsigned SectionID);
 
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                                       unsigned SectionID);
+                                       unsigned SectionID, bool IsReadOnly);
 
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true);
 
 
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true);
 
+  virtual bool applyPermissions(std::string *ErrMsg) { return false; }
+
   // Invalidate instruction cache for code sections. Some platforms with
   // separate data cache and instruction cache require explicit cache flush,
   // otherwise JIT code manipulations (like resolved relocations) will get to
   // Invalidate instruction cache for code sections. Some platforms with
   // separate data cache and instruction cache require explicit cache flush,
   // otherwise JIT code manipulations (like resolved relocations) will get to
@@ -301,7 +303,8 @@ public:
 
 uint8_t *LLIMCJITMemoryManager::allocateDataSection(uintptr_t Size,
                                                     unsigned Alignment,
 
 uint8_t *LLIMCJITMemoryManager::allocateDataSection(uintptr_t Size,
                                                     unsigned Alignment,
-                                                    unsigned SectionID) {
+                                                    unsigned SectionID,
+                                                    bool IsReadOnly) {
   if (!Alignment)
     Alignment = 16;
   // Ensure that enough memory is requested to allow aligning.
   if (!Alignment)
     Alignment = 16;
   // Ensure that enough memory is requested to allow aligning.
index 7b5bd0388d882d58424c4aa754ea0096a18c89b8..e06d798cd517c49fc5b97fc5c3ed819c67e9875c 100644 (file)
@@ -58,13 +58,15 @@ public:
   uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                                unsigned SectionID);
   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
   uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                                unsigned SectionID);
   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                               unsigned SectionID);
+                               unsigned SectionID, bool IsReadOnly);
 
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true) {
     return 0;
   }
 
 
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true) {
     return 0;
   }
 
+  bool applyPermissions(std::string *ErrMsg) { return false; }
+
   // Invalidate instruction cache for sections with execute permissions.
   // Some platforms with separate data cache and instruction cache require
   // explicit cache flush, otherwise JIT code manipulations (like resolved
   // Invalidate instruction cache for sections with execute permissions.
   // Some platforms with separate data cache and instruction cache require
   // explicit cache flush, otherwise JIT code manipulations (like resolved
@@ -82,7 +84,8 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
 
 uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
                                                    unsigned Alignment,
 
 uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
                                                    unsigned Alignment,
-                                                   unsigned SectionID) {
+                                                   unsigned SectionID,
+                                                   bool IsReadOnly) {
   sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
   DataMemory.push_back(MB);
   return (uint8_t*)MB.base();
   sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
   DataMemory.push_back(MB);
   return (uint8_t*)MB.base();
index 59604dfbf5cf3b6f10c60744ab4d07d53fc5fed7..6e54449beba64fb5d34241dddf250a3028bcf405 100644 (file)
@@ -118,13 +118,14 @@ public:
     Base->endFunctionBody(F, FunctionStart, FunctionEnd);
   }
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
     Base->endFunctionBody(F, FunctionStart, FunctionEnd);
   }
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                                       unsigned SectionID) {
-    return Base->allocateDataSection(Size, Alignment, SectionID);
+                                       unsigned SectionID, bool IsReadOnly) {
+    return Base->allocateDataSection(Size, Alignment, SectionID, IsReadOnly);
   }
   virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                                        unsigned SectionID) {
     return Base->allocateCodeSection(Size, Alignment, SectionID);
   }
   }
   virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
                                        unsigned SectionID) {
     return Base->allocateCodeSection(Size, Alignment, SectionID);
   }
+  virtual bool applyPermissions(std::string *ErrMsg) { return false; }
   virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
     return Base->allocateSpace(Size, Alignment);
   }
   virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
     return Base->allocateSpace(Size, Alignment);
   }
index d6baf3c9bb8e5f8a9556fe7447f97121f04111ad..225106ecab2c092598f41547525feb41d75711c1 100644 (file)
@@ -32,7 +32,8 @@ namespace llvm {
 
 uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
                                                     unsigned Alignment,
 
 uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
                                                     unsigned Alignment,
-                                                    unsigned SectionID) {
+                                                    unsigned SectionID,
+                                                    bool IsReadOnly) {
   if (!Alignment)
     Alignment = 16;
   // Ensure that enough memory is requested to allow aligning.
   if (!Alignment)
     Alignment = 16;
   // Ensure that enough memory is requested to allow aligning.
index e44217c906389100293b6519a5053581ca18226b..968ee63ffdf5fd189f51da23789c2323234b3413 100644 (file)
@@ -34,7 +34,9 @@ public:
                                        unsigned SectionID);
 
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
                                        unsigned SectionID);
 
   virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
-                                       unsigned SectionID);
+                                       unsigned SectionID, bool IsReadOnly);
+
+  virtual bool applyPermissions(std::string *ErrMsg) { return false; }
 
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true);
 
   virtual void *getPointerToNamedFunction(const std::string &Name,
                                           bool AbortOnFailure = true);