Interface changes to allow RuntimeDyld memory managers to set memory permissions after an object has been loaded.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168114 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Kaylor
2012-11-15 23:50:01 +00:00
parent 085f982462
commit 53608a34ce
11 changed files with 58 additions and 14 deletions

View File

@@ -48,7 +48,7 @@ public:
/// assigned by the JIT engine, and optionally recorded by the memory manager /// assigned by the JIT engine, and optionally recorded by the memory manager
/// to access a loaded section. /// to access a loaded section.
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 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 /// getPointerToNamedFunction - This method returns the address of the
/// specified function. As such it is only useful for resolving library /// specified function. As such it is only useful for resolving library
@@ -59,6 +59,15 @@ public:
/// message to stderr and aborts. /// message to stderr and aborts.
virtual void *getPointerToNamedFunction(const std::string &Name, virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) = 0; 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 {

View File

@@ -501,10 +501,14 @@ namespace {
/// allocateDataSection - Allocate memory for a data section. /// allocateDataSection - Allocate memory for a data section.
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 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 /// startExceptionTable - Use startFunctionBody to allocate memory for the
/// function's exception table. /// function's exception table.
uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) { uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) {

View File

@@ -118,17 +118,26 @@ void MCJIT::emitObject(Module *m) {
// FIXME: Add a parameter to identify which object is being finalized when // FIXME: Add a parameter to identify which object is being finalized when
// MCJIT supports multiple modules. // MCJIT supports multiple modules.
// FIXME: Provide a way to separate code emission, relocations and page
// protection in the interface.
void MCJIT::finalizeObject() { void MCJIT::finalizeObject() {
// If the module hasn't been compiled, just do that. // If the module hasn't been compiled, just do that.
if (!isCompiled) { if (!isCompiled) {
// If the call to Dyld.resolveRelocations() is removed from emitObject() // If the call to Dyld.resolveRelocations() is removed from emitObject()
// we'll need to do that here. // we'll need to do that here.
emitObject(M); emitObject(M);
// Set page permissions.
MemMgr->applyPermissions();
return; return;
} }
// Resolve any relocations. // Resolve any relocations.
Dyld.resolveRelocations(); Dyld.resolveRelocations();
// Set page permissions.
MemMgr->applyPermissions();
} }
void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) { void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {

View File

@@ -182,7 +182,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj,
// Allocate memory for the section // Allocate memory for the section
unsigned SectionID = Sections.size(); unsigned SectionID = Sections.size();
uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, sizeof(void*), uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, sizeof(void*),
SectionID); SectionID, false);
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;
@@ -237,11 +237,13 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
bool IsRequired; bool IsRequired;
bool IsVirtual; bool IsVirtual;
bool IsZeroInit; bool IsZeroInit;
bool IsReadOnly;
uint64_t DataSize; uint64_t DataSize;
StringRef Name; StringRef Name;
Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isRequiredForExecution(IsRequired));
Check(Section.isVirtual(IsVirtual)); Check(Section.isVirtual(IsVirtual));
Check(Section.isZeroInit(IsZeroInit)); Check(Section.isZeroInit(IsZeroInit));
Check(Section.isReadOnlyData(IsReadOnly));
Check(Section.getSize(DataSize)); Check(Section.getSize(DataSize));
Check(Section.getName(Name)); Check(Section.getName(Name));
@@ -256,7 +258,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj,
Allocate = DataSize + StubBufSize; Allocate = DataSize + StubBufSize;
Addr = IsCode Addr = IsCode
? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID) ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID)
: MemMgr->allocateDataSection(Allocate, Alignment, SectionID); : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, IsReadOnly);
if (!Addr) if (!Addr)
report_fatal_error("Unable to allocate section memory!"); report_fatal_error("Unable to allocate section memory!");
@@ -451,6 +453,12 @@ void RuntimeDyldImpl::resolveExternalSymbols() {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// RuntimeDyld class implementation // RuntimeDyld class implementation
RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) { 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; Dyld = 0;
MM = mm; MM = mm;
} }

View 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 recording memory manager is just a local copy of the remote target.
// The alignment requirement is just stored here for later use. Regular // The alignment requirement is just stored here for later use. Regular
// heap storage is sufficient here. // heap storage is sufficient here.

View File

@@ -47,10 +47,13 @@ public:
unsigned SectionID); unsigned SectionID);
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID); unsigned SectionID, bool IsReadOnly);
void *getPointerToNamedFunction(const std::string &Name, void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true); bool AbortOnFailure = true);
bool applyPermissions(std::string *ErrMsg) { return false; }
// The following obsolete JITMemoryManager calls are stubbed out for // The following obsolete JITMemoryManager calls are stubbed out for
// this model. // this model.
void setMemoryWritable(); void setMemoryWritable();

View File

@@ -231,11 +231,13 @@ public:
unsigned SectionID); unsigned SectionID);
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID); unsigned SectionID, bool IsReadOnly);
virtual void *getPointerToNamedFunction(const std::string &Name, virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true); bool AbortOnFailure = true);
virtual bool applyPermissions(std::string *ErrMsg) { return false; }
// Invalidate instruction cache for code sections. Some platforms with // Invalidate instruction cache for code sections. Some platforms with
// separate data cache and instruction cache require explicit cache flush, // separate data cache and instruction cache require explicit cache flush,
// otherwise JIT code manipulations (like resolved relocations) will get to // otherwise JIT code manipulations (like resolved relocations) will get to
@@ -301,7 +303,8 @@ public:
uint8_t *LLIMCJITMemoryManager::allocateDataSection(uintptr_t Size, uint8_t *LLIMCJITMemoryManager::allocateDataSection(uintptr_t Size,
unsigned Alignment, unsigned Alignment,
unsigned SectionID) { unsigned SectionID,
bool IsReadOnly) {
if (!Alignment) if (!Alignment)
Alignment = 16; Alignment = 16;
// Ensure that enough memory is requested to allow aligning. // Ensure that enough memory is requested to allow aligning.

View File

@@ -58,13 +58,15 @@ public:
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID); unsigned SectionID);
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID); unsigned SectionID, bool IsReadOnly);
virtual void *getPointerToNamedFunction(const std::string &Name, virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) { bool AbortOnFailure = true) {
return 0; return 0;
} }
bool applyPermissions(std::string *ErrMsg) { return false; }
// Invalidate instruction cache for sections with execute permissions. // Invalidate instruction cache for sections with execute permissions.
// Some platforms with separate data cache and instruction cache require // Some platforms with separate data cache and instruction cache require
// explicit cache flush, otherwise JIT code manipulations (like resolved // 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, uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
unsigned Alignment, unsigned Alignment,
unsigned SectionID) { unsigned SectionID,
bool IsReadOnly) {
sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
DataMemory.push_back(MB); DataMemory.push_back(MB);
return (uint8_t*)MB.base(); return (uint8_t*)MB.base();

View File

@@ -118,13 +118,14 @@ public:
Base->endFunctionBody(F, FunctionStart, FunctionEnd); Base->endFunctionBody(F, FunctionStart, FunctionEnd);
} }
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) { unsigned SectionID, bool IsReadOnly) {
return Base->allocateDataSection(Size, Alignment, SectionID); return Base->allocateDataSection(Size, Alignment, SectionID, IsReadOnly);
} }
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) { unsigned SectionID) {
return Base->allocateCodeSection(Size, Alignment, SectionID); return Base->allocateCodeSection(Size, Alignment, SectionID);
} }
virtual bool applyPermissions(std::string *ErrMsg) { return false; }
virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
return Base->allocateSpace(Size, Alignment); return Base->allocateSpace(Size, Alignment);
} }

View File

@@ -32,7 +32,8 @@ namespace llvm {
uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
unsigned Alignment, unsigned Alignment,
unsigned SectionID) { unsigned SectionID,
bool IsReadOnly) {
if (!Alignment) if (!Alignment)
Alignment = 16; Alignment = 16;
// Ensure that enough memory is requested to allow aligning. // Ensure that enough memory is requested to allow aligning.

View File

@@ -34,7 +34,9 @@ public:
unsigned SectionID); unsigned SectionID);
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 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, virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true); bool AbortOnFailure = true);