mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	Adding support and tests for multiple module handling in lli
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191938 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
		| @@ -21,6 +21,9 @@ | ||||
|  | ||||
| namespace llvm { | ||||
|  | ||||
| class ExecutionEngine; | ||||
| class ObjectImage; | ||||
|  | ||||
| // RuntimeDyld clients often want to handle the memory management of | ||||
| // what gets placed where. For JIT clients, this is the subset of | ||||
| // JITMemoryManager required for dynamic loading of binaries. | ||||
| @@ -63,11 +66,24 @@ public: | ||||
|   /// found, this function returns a null pointer. Otherwise, it prints a | ||||
|   /// message to stderr and aborts. | ||||
|   /// | ||||
|   /// This function is deprecated for memory managers used to be used with | ||||
|   /// This function is deprecated for memory managers to be used with | ||||
|   /// MCJIT or RuntimeDyld.  Use getSymbolAddress instead. | ||||
|   virtual void *getPointerToNamedFunction(const std::string &Name, | ||||
|                                           bool AbortOnFailure = true); | ||||
|  | ||||
|   /// This method is called after an object has been loaded into memory but | ||||
|   /// before relocations are applied to the loaded sections.  The object load | ||||
|   /// may have been initiated by MCJIT to resolve an external symbol for another | ||||
|   /// object that is being finalized.  In that case, the object about which | ||||
|   /// the memory manager is being notified will be finalized immediately after | ||||
|   /// the memory manager returns from this call. | ||||
|   /// | ||||
|   /// Memory managers which are preparing code for execution in an external | ||||
|   /// address space can use this call to remap the section addresses for the | ||||
|   /// newly loaded object. | ||||
|   virtual void notifyObjectLoaded(ExecutionEngine *EE, | ||||
|                                   const ObjectImage *) {} | ||||
|  | ||||
|   /// 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 | ||||
|   | ||||
| @@ -513,6 +513,7 @@ void MCJIT::UnregisterJITEventListener(JITEventListener *L) { | ||||
| } | ||||
| void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) { | ||||
|   MutexGuard locked(lock); | ||||
|   MemMgr.notifyObjectLoaded(this, &Obj); | ||||
|   for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { | ||||
|     EventListeners[I]->NotifyObjectEmitted(Obj); | ||||
|   } | ||||
|   | ||||
| @@ -46,6 +46,11 @@ public: | ||||
|                                          SectionID, SectionName, IsReadOnly); | ||||
|   } | ||||
|  | ||||
|   virtual void notifyObjectLoaded(ExecutionEngine *EE, | ||||
|                                   const ObjectImage *Obj) { | ||||
|     ClientMM->notifyObjectLoaded(EE, Obj); | ||||
|   } | ||||
|  | ||||
|   virtual void registerEHFrames(StringRef SectionData) { | ||||
|     ClientMM->registerEHFrames(SectionData); | ||||
|   } | ||||
|   | ||||
							
								
								
									
										13
									
								
								test/ExecutionEngine/MCJIT/cross-module-a.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								test/ExecutionEngine/MCJIT/cross-module-a.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| ; RUN: %lli_mcjit -extra-modules=%p/cross-module-b.ir %s > /dev/null | ||||
|  | ||||
| declare i32 @FB() | ||||
|  | ||||
| define i32 @FA() { | ||||
|   ret i32 0 | ||||
| } | ||||
|  | ||||
| define i32 @main() { | ||||
|   %r = call i32 @FB( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										7
									
								
								test/ExecutionEngine/MCJIT/cross-module-b.ir
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/ExecutionEngine/MCJIT/cross-module-b.ir
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| declare i32 @FA() | ||||
|  | ||||
| define i32 @FB() { | ||||
|   %r = call i32 @FA( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										9
									
								
								test/ExecutionEngine/MCJIT/multi-module-a.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								test/ExecutionEngine/MCJIT/multi-module-a.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| ; RUN: %lli_mcjit -extra-modules=%p/multi-module-b.ir,%p/multi-module-c.ir %s > /dev/null | ||||
|  | ||||
| declare i32 @FB() | ||||
|  | ||||
| define i32 @main() { | ||||
|   %r = call i32 @FB( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										7
									
								
								test/ExecutionEngine/MCJIT/multi-module-b.ir
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/ExecutionEngine/MCJIT/multi-module-b.ir
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| declare i32 @FC() | ||||
|  | ||||
| define i32 @FB() { | ||||
|   %r = call i32 @FC( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										4
									
								
								test/ExecutionEngine/MCJIT/multi-module-c.ir
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/ExecutionEngine/MCJIT/multi-module-c.ir
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| define i32 @FC() { | ||||
|   ret i32 0 | ||||
| } | ||||
|  | ||||
							
								
								
									
										13
									
								
								test/ExecutionEngine/MCJIT/remote/cross-module-a.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								test/ExecutionEngine/MCJIT/remote/cross-module-a.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| ; RUN: %lli_mcjit -extra-modules=%p/cross-module-b.ir  -disable-lazy-compilation=true -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null | ||||
|  | ||||
| declare i32 @FB() | ||||
|  | ||||
| define i32 @FA() { | ||||
|   ret i32 0 | ||||
| } | ||||
|  | ||||
| define i32 @main() { | ||||
|   %r = call i32 @FB( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										7
									
								
								test/ExecutionEngine/MCJIT/remote/cross-module-b.ir
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/ExecutionEngine/MCJIT/remote/cross-module-b.ir
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| declare i32 @FA() | ||||
|  | ||||
| define i32 @FB() { | ||||
|   %r = call i32 @FA( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										9
									
								
								test/ExecutionEngine/MCJIT/remote/multi-module-a.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								test/ExecutionEngine/MCJIT/remote/multi-module-a.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| ; RUN: %lli_mcjit -extra-modules=%p/multi-module-b.ir,%p/multi-module-c.ir  -disable-lazy-compilation=true -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null | ||||
|  | ||||
| declare i32 @FB() | ||||
|  | ||||
| define i32 @main() { | ||||
|   %r = call i32 @FB( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										7
									
								
								test/ExecutionEngine/MCJIT/remote/multi-module-b.ir
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/ExecutionEngine/MCJIT/remote/multi-module-b.ir
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| declare i32 @FC() | ||||
|  | ||||
| define i32 @FB() { | ||||
|   %r = call i32 @FC( )   ; <i32> [#uses=1] | ||||
|   ret i32 %r | ||||
| } | ||||
|  | ||||
							
								
								
									
										4
									
								
								test/ExecutionEngine/MCJIT/remote/multi-module-c.ir
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/ExecutionEngine/MCJIT/remote/multi-module-c.ir
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| define i32 @FC() { | ||||
|   ret i32 0 | ||||
| } | ||||
|  | ||||
| @@ -21,7 +21,7 @@ endif( LLVM_USE_INTEL_JITEVENTS ) | ||||
|  | ||||
| add_llvm_tool(lli | ||||
|   lli.cpp | ||||
|   RecordingMemoryManager.cpp | ||||
|   RemoteMemoryManager.cpp | ||||
|   RemoteTarget.cpp | ||||
|   RemoteTargetExternal.cpp | ||||
|   ) | ||||
|   | ||||
| @@ -1,126 +0,0 @@ | ||||
| //===- RecordingMemoryManager.cpp - Recording memory manager --------------===// | ||||
| // | ||||
| //                     The LLVM Compiler Infrastructure | ||||
| // | ||||
| // This file is distributed under the University of Illinois Open Source | ||||
| // License. See LICENSE.TXT for details. | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
| // | ||||
| // This memory manager allocates local storage and keeps a record of each | ||||
| // allocation. Iterators are provided for all data and code allocations. | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
|  | ||||
| #include "RecordingMemoryManager.h" | ||||
| using namespace llvm; | ||||
|  | ||||
| RecordingMemoryManager::~RecordingMemoryManager() { | ||||
|   for (SmallVectorImpl<Allocation>::iterator | ||||
|          I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); | ||||
|        I != E; ++I) | ||||
|     sys::Memory::releaseMappedMemory(I->first); | ||||
|   for (SmallVectorImpl<Allocation>::iterator | ||||
|          I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); | ||||
|        I != E; ++I) | ||||
|     sys::Memory::releaseMappedMemory(I->first); | ||||
| } | ||||
|  | ||||
| uint8_t *RecordingMemoryManager:: | ||||
| allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, | ||||
|                     StringRef SectionName) { | ||||
|   // 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, but we're using mapped memory to work | ||||
|   // around a bug in MCJIT. | ||||
|   sys::MemoryBlock Block = allocateSection(Size); | ||||
|   AllocatedCodeMem.push_back(Allocation(Block, Alignment)); | ||||
|   return (uint8_t*)Block.base(); | ||||
| } | ||||
|  | ||||
| uint8_t *RecordingMemoryManager:: | ||||
| allocateDataSection(uintptr_t Size, unsigned Alignment, | ||||
|                     unsigned SectionID, StringRef SectionName, | ||||
|                     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, but we're using mapped memory to work | ||||
|   // around a bug in MCJIT. | ||||
|   sys::MemoryBlock Block = allocateSection(Size); | ||||
|   AllocatedDataMem.push_back(Allocation(Block, Alignment)); | ||||
|   return (uint8_t*)Block.base(); | ||||
| } | ||||
|  | ||||
| sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) { | ||||
|   error_code ec; | ||||
|   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, | ||||
|                                                           &Near, | ||||
|                                                           sys::Memory::MF_READ | | ||||
|                                                           sys::Memory::MF_WRITE, | ||||
|                                                           ec); | ||||
|   assert(!ec && MB.base()); | ||||
|  | ||||
|   // FIXME: This is part of a work around to keep sections near one another | ||||
|   // when MCJIT performs relocations after code emission but before | ||||
|   // the generated code is moved to the remote target. | ||||
|   // Save this address as the basis for our next request | ||||
|   Near = MB; | ||||
|   return MB; | ||||
| } | ||||
|  | ||||
| void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } | ||||
| void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } | ||||
| void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } | ||||
| void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } | ||||
| uint8_t *RecordingMemoryManager::getGOTBase() const { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, | ||||
|                                               unsigned Alignment) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, | ||||
|                                              uint8_t *FunctionEnd) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
| } | ||||
| uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| void RecordingMemoryManager::deallocateFunctionBody(void *Body) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
| } | ||||
|  | ||||
| static int jit_noop() { | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void *RecordingMemoryManager::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; | ||||
| } | ||||
							
								
								
									
										230
									
								
								tools/lli/RemoteMemoryManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								tools/lli/RemoteMemoryManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,230 @@ | ||||
| //===---- RemoteMemoryManager.cpp - Recording memory manager --------------===// | ||||
| // | ||||
| //                     The LLVM Compiler Infrastructure | ||||
| // | ||||
| // This file is distributed under the University of Illinois Open Source | ||||
| // License. See LICENSE.TXT for details. | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
| // | ||||
| // This memory manager allocates local storage and keeps a record of each | ||||
| // allocation. Iterators are provided for all data and code allocations. | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
|  | ||||
| #define DEBUG_TYPE "lli" | ||||
| #include "RemoteMemoryManager.h" | ||||
| #include "llvm/ExecutionEngine/ExecutionEngine.h" | ||||
| #include "llvm/ExecutionEngine/ObjectImage.h" | ||||
| #include "llvm/Support/Debug.h" | ||||
| #include "llvm/Support/Format.h" | ||||
|  | ||||
| using namespace llvm; | ||||
|  | ||||
| RemoteMemoryManager::~RemoteMemoryManager() { | ||||
|   for (SmallVector<Allocation, 2>::iterator | ||||
|          I = AllocatedSections.begin(), E = AllocatedSections.end(); | ||||
|        I != E; ++I) | ||||
|     sys::Memory::releaseMappedMemory(I->MB); | ||||
| } | ||||
|  | ||||
| uint8_t *RemoteMemoryManager:: | ||||
| allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, | ||||
|                     StringRef SectionName) { | ||||
|   // 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, but we're using mapped memory to work | ||||
|   // around a bug in MCJIT. | ||||
|   sys::MemoryBlock Block = allocateSection(Size); | ||||
|   AllocatedSections.push_back( Allocation(Block, Alignment, true) ); | ||||
|   UnmappedSections.push_back( &AllocatedSections.back() ); | ||||
|   return (uint8_t*)Block.base(); | ||||
| } | ||||
|  | ||||
| uint8_t *RemoteMemoryManager:: | ||||
| allocateDataSection(uintptr_t Size, unsigned Alignment, | ||||
|                     unsigned SectionID, StringRef SectionName, | ||||
|                     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, but we're using mapped memory to work | ||||
|   // around a bug in MCJIT. | ||||
|   sys::MemoryBlock Block = allocateSection(Size); | ||||
|   AllocatedSections.push_back( Allocation(Block, Alignment, false) ); | ||||
|   UnmappedSections.push_back( &AllocatedSections.back() ); | ||||
|   return (uint8_t*)Block.base(); | ||||
| } | ||||
|  | ||||
| sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { | ||||
|   error_code ec; | ||||
|   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, | ||||
|                                                           &Near, | ||||
|                                                           sys::Memory::MF_READ | | ||||
|                                                           sys::Memory::MF_WRITE, | ||||
|                                                           ec); | ||||
|   assert(!ec && MB.base()); | ||||
|  | ||||
|   // FIXME: This is part of a work around to keep sections near one another | ||||
|   // when MCJIT performs relocations after code emission but before | ||||
|   // the generated code is moved to the remote target. | ||||
|   // Save this address as the basis for our next request | ||||
|   Near = MB; | ||||
|   return MB; | ||||
| } | ||||
|  | ||||
| void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, | ||||
|                                                 const ObjectImage *Obj) { | ||||
|   // The client should have called setRemoteTarget() before triggering any | ||||
|   // code generation. | ||||
|   assert(Target); | ||||
|   if (!Target) | ||||
|     return; | ||||
|  | ||||
|   // FIXME: Make this function thread safe. | ||||
|  | ||||
|   // Lay out our sections in order, with all the code sections first, then | ||||
|   // all the data sections. | ||||
|   uint64_t CurOffset = 0; | ||||
|   unsigned MaxAlign = Target->getPageAlignment(); | ||||
|   SmallVector<std::pair<const Allocation*, uint64_t>, 16> Offsets; | ||||
|   unsigned NumSections = UnmappedSections.size(); | ||||
|   // We're going to go through the list twice to separate code and data, but | ||||
|   // it's a very small list, so that's OK. | ||||
|   for (size_t i = 0, e = NumSections; i != e; ++i) { | ||||
|     const Allocation *Section = UnmappedSections[i]; | ||||
|     assert(Section); | ||||
|     if (Section->IsCode) { | ||||
|       unsigned Size = Section->MB.size(); | ||||
|       unsigned Align = Section->Alignment; | ||||
|       DEBUG(dbgs() << "code region: size " << Size | ||||
|                   << ", alignment " << Align << "\n"); | ||||
|       // Align the current offset up to whatever is needed for the next | ||||
|       // section. | ||||
|       CurOffset = (CurOffset + Align - 1) / Align * Align; | ||||
|       // Save off the address of the new section and allocate its space. | ||||
|       Offsets.push_back(std::pair<const Allocation*,uint64_t>(Section,  | ||||
|                                                               CurOffset)); | ||||
|       CurOffset += Size; | ||||
|     } | ||||
|   } | ||||
|   // Adjust to keep code and data aligned on seperate pages. | ||||
|   CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; | ||||
|   for (size_t i = 0, e = NumSections; i != e; ++i) { | ||||
|     const Allocation *Section = UnmappedSections[i]; | ||||
|     assert(Section); | ||||
|     if (!Section->IsCode) { | ||||
|       unsigned Size = Section->MB.size(); | ||||
|       unsigned Align = Section->Alignment; | ||||
|       DEBUG(dbgs() << "data region: size " << Size | ||||
|                   << ", alignment " << Align << "\n"); | ||||
|       // Align the current offset up to whatever is needed for the next | ||||
|       // section. | ||||
|       CurOffset = (CurOffset + Align - 1) / Align * Align; | ||||
|       // Save off the address of the new section and allocate its space. | ||||
|       Offsets.push_back(std::pair<const Allocation*,uint64_t>(Section,  | ||||
|                                                               CurOffset)); | ||||
|       CurOffset += Size; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Allocate space in the remote target. | ||||
|   uint64_t RemoteAddr; | ||||
|   if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) | ||||
|     report_fatal_error(Target->getErrorMsg()); | ||||
|  | ||||
|   // Map the section addresses so relocations will get updated in the local | ||||
|   // copies of the sections. | ||||
|   for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { | ||||
|     uint64_t Addr = RemoteAddr + Offsets[i].second; | ||||
|     EE->mapSectionAddress(const_cast<void*>(Offsets[i].first->MB.base()), Addr); | ||||
|  | ||||
|     DEBUG(dbgs() << "  Mapping local: " << Offsets[i].first->MB.base() | ||||
|                  << " to remote: 0x" << format("%llx", Addr) << "\n"); | ||||
|  | ||||
|     MappedSections[Addr] = Offsets[i].first; | ||||
|   } | ||||
|  | ||||
|   UnmappedSections.clear(); | ||||
| } | ||||
|  | ||||
| bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { | ||||
|   // FIXME: Make this function thread safe. | ||||
|   for (DenseMap<uint64_t, const Allocation*>::iterator | ||||
|          I = MappedSections.begin(), E = MappedSections.end(); | ||||
|        I != E; ++I) { | ||||
|     uint64_t RemoteAddr = I->first; | ||||
|     const Allocation *Section = I->second; | ||||
|     if (Section->IsCode) { | ||||
|       Target->loadCode(RemoteAddr, Section->MB.base(), Section->MB.size()); | ||||
|  | ||||
|       DEBUG(dbgs() << "  loading code: " << Section->MB.base() | ||||
|             << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); | ||||
|     } else { | ||||
|       Target->loadData(RemoteAddr, Section->MB.base(), Section->MB.size()); | ||||
|  | ||||
|       DEBUG(dbgs() << "  loading data: " << Section->MB.base() | ||||
|             << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   MappedSections.clear(); | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } | ||||
| void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } | ||||
| void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } | ||||
| void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } | ||||
| uint8_t *RemoteMemoryManager::getGOTBase() const { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, | ||||
|                                               unsigned Alignment) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, | ||||
|                                              uint8_t *FunctionEnd) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
| } | ||||
| uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { | ||||
|   llvm_unreachable("Unexpected!"); | ||||
|   return 0; | ||||
| } | ||||
| 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; | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| //===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===//
 | ||||
| //===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===//
 | ||||
| //
 | ||||
| //                     The LLVM Compiler Infrastructure
 | ||||
| //
 | ||||
| @@ -12,24 +12,47 @@ | ||||
| //
 | ||||
| //===----------------------------------------------------------------------===//
 | ||||
| 
 | ||||
| #ifndef RECORDINGMEMORYMANAGER_H | ||||
| #define RECORDINGMEMORYMANAGER_H | ||||
| #ifndef REMOTEMEMORYMANAGER_H | ||||
| #define REMOTEMEMORYMANAGER_H | ||||
| 
 | ||||
| #include "llvm/ADT/DenseMap.h" | ||||
| #include "llvm/ADT/SmallVector.h" | ||||
| #include "llvm/ExecutionEngine/JITMemoryManager.h" | ||||
| #include "llvm/Support/ErrorHandling.h" | ||||
| #include "llvm/Support/Memory.h" | ||||
| #include <utility> | ||||
| 
 | ||||
| #include "RemoteTarget.h" | ||||
| 
 | ||||
| namespace llvm { | ||||
| 
 | ||||
| class RecordingMemoryManager : public JITMemoryManager { | ||||
| class RemoteMemoryManager : public JITMemoryManager { | ||||
| public: | ||||
|   typedef std::pair<sys::MemoryBlock, unsigned> Allocation; | ||||
|   // Notice that this structure takes ownership of the memory allocated.
 | ||||
|   struct Allocation { | ||||
|     Allocation(sys::MemoryBlock mb, unsigned a, bool code) | ||||
|       : MB(mb), Alignment(a), IsCode(code) {} | ||||
| 
 | ||||
|     sys::MemoryBlock  MB; | ||||
|     unsigned          Alignment; | ||||
|     bool              IsCode; | ||||
|   }; | ||||
| 
 | ||||
| private: | ||||
|   SmallVector<Allocation, 16> AllocatedDataMem; | ||||
|   SmallVector<Allocation, 16> AllocatedCodeMem; | ||||
|   // This vector contains Allocation objects for all sections which we have
 | ||||
|   // allocated.  This vector effectively owns the memory associated with the
 | ||||
|   // allocations.
 | ||||
|   SmallVector<Allocation, 2>  AllocatedSections; | ||||
| 
 | ||||
|   // This vector contains pointers to Allocation objects for any sections we
 | ||||
|   // have allocated locally but have not yet remapped for the remote target.
 | ||||
|   // When we receive notification of a completed module load, we will map
 | ||||
|   // these sections into the remote target.
 | ||||
|   SmallVector<const Allocation *, 2>  UnmappedSections; | ||||
| 
 | ||||
|   // This map tracks the sections we have remapped for the remote target
 | ||||
|   // but have not yet copied to the target.
 | ||||
|   DenseMap<uint64_t, const Allocation *>  MappedSections; | ||||
| 
 | ||||
|   // FIXME: This is part of a work around to keep sections near one another
 | ||||
|   // when MCJIT performs relocations after code emission but before
 | ||||
| @@ -37,17 +60,11 @@ private: | ||||
|   sys::MemoryBlock Near; | ||||
|   sys::MemoryBlock allocateSection(uintptr_t Size); | ||||
| 
 | ||||
|   RemoteTarget *Target; | ||||
| 
 | ||||
| public: | ||||
|   RecordingMemoryManager() {} | ||||
|   virtual ~RecordingMemoryManager(); | ||||
| 
 | ||||
|   typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator; | ||||
|   typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator; | ||||
| 
 | ||||
|   const_data_iterator data_begin() const { return AllocatedDataMem.begin(); } | ||||
|   const_data_iterator   data_end() const { return AllocatedDataMem.end(); } | ||||
|   const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); } | ||||
|   const_code_iterator   code_end() const { return AllocatedCodeMem.end(); } | ||||
|   RemoteMemoryManager() : Target(NULL) {} | ||||
|   virtual ~RemoteMemoryManager(); | ||||
| 
 | ||||
|   uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, | ||||
|                                unsigned SectionID, StringRef SectionName); | ||||
| @@ -59,7 +76,12 @@ public: | ||||
|   void *getPointerToNamedFunction(const std::string &Name, | ||||
|                                   bool AbortOnFailure = true); | ||||
| 
 | ||||
|   bool finalizeMemory(std::string *ErrMsg) { return false; } | ||||
|   void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj); | ||||
| 
 | ||||
|   bool finalizeMemory(std::string *ErrMsg); | ||||
| 
 | ||||
|   // This is a non-interface function used by lli
 | ||||
|   void setRemoteTarget(RemoteTarget *T) { Target = T; } | ||||
| 
 | ||||
|   // The following obsolete JITMemoryManager calls are stubbed out for
 | ||||
|   // this model.
 | ||||
| @@ -15,7 +15,7 @@ | ||||
|  | ||||
| #define DEBUG_TYPE "lli" | ||||
| #include "llvm/IR/LLVMContext.h" | ||||
| #include "RecordingMemoryManager.h" | ||||
| #include "RemoteMemoryManager.h" | ||||
| #include "RemoteTarget.h" | ||||
| #include "llvm/ADT/Triple.h" | ||||
| #include "llvm/Bitcode/ReaderWriter.h" | ||||
| @@ -131,6 +131,12 @@ namespace { | ||||
|             cl::value_desc("function"), | ||||
|             cl::init("main")); | ||||
|  | ||||
|   cl::list<std::string> | ||||
|   ExtraModules("extra-modules", | ||||
|          cl::CommaSeparated, | ||||
|          cl::desc("Extra modules to be loaded"), | ||||
|          cl::value_desc("<input bitcode 2>,<input bitcode 3>,...")); | ||||
|  | ||||
|   cl::opt<std::string> | ||||
|   FakeArgv0("fake-argv0", | ||||
|             cl::desc("Override the 'argv[0]' value passed into the executing" | ||||
| @@ -222,82 +228,6 @@ static void do_shutdown() { | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { | ||||
|   // Lay out our sections in order, with all the code sections first, then | ||||
|   // all the data sections. | ||||
|   uint64_t CurOffset = 0; | ||||
|   unsigned MaxAlign = T->getPageAlignment(); | ||||
|   SmallVector<std::pair<const void*, uint64_t>, 16> Offsets; | ||||
|   SmallVector<unsigned, 16> Sizes; | ||||
|   for (RecordingMemoryManager::const_code_iterator I = JMM->code_begin(), | ||||
|                                                    E = JMM->code_end(); | ||||
|        I != E; ++I) { | ||||
|     DEBUG(dbgs() << "code region: size " << I->first.size() | ||||
|                  << ", alignment " << I->second << "\n"); | ||||
|     // Align the current offset up to whatever is needed for the next | ||||
|     // section. | ||||
|     unsigned Align = I->second; | ||||
|     CurOffset = (CurOffset + Align - 1) / Align * Align; | ||||
|     // Save off the address of the new section and allocate its space. | ||||
|     Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); | ||||
|     Sizes.push_back(I->first.size()); | ||||
|     CurOffset += I->first.size(); | ||||
|   } | ||||
|   // Adjust to keep code and data aligned on seperate pages. | ||||
|   CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; | ||||
|   unsigned FirstDataIndex = Offsets.size(); | ||||
|   for (RecordingMemoryManager::const_data_iterator I = JMM->data_begin(), | ||||
|                                                    E = JMM->data_end(); | ||||
|        I != E; ++I) { | ||||
|     DEBUG(dbgs() << "data region: size " << I->first.size() | ||||
|                  << ", alignment " << I->second << "\n"); | ||||
|     // Align the current offset up to whatever is needed for the next | ||||
|     // section. | ||||
|     unsigned Align = I->second; | ||||
|     CurOffset = (CurOffset + Align - 1) / Align * Align; | ||||
|     // Save off the address of the new section and allocate its space. | ||||
|     Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); | ||||
|     Sizes.push_back(I->first.size()); | ||||
|     CurOffset += I->first.size(); | ||||
|   } | ||||
|  | ||||
|   // Allocate space in the remote target. | ||||
|   uint64_t RemoteAddr; | ||||
|   if (T->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) | ||||
|     report_fatal_error(T->getErrorMsg()); | ||||
|   // Map the section addresses so relocations will get updated in the local | ||||
|   // copies of the sections. | ||||
|   for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { | ||||
|     uint64_t Addr = RemoteAddr + Offsets[i].second; | ||||
|     EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr); | ||||
|  | ||||
|     DEBUG(dbgs() << "  Mapping local: " << Offsets[i].first | ||||
|                  << " to remote: 0x" << format("%llx", Addr) << "\n"); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Trigger application of relocations | ||||
|   EE->finalizeObject(); | ||||
|  | ||||
|   // Now load it all to the target. | ||||
|   for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { | ||||
|     uint64_t Addr = RemoteAddr + Offsets[i].second; | ||||
|  | ||||
|     if (i < FirstDataIndex) { | ||||
|       T->loadCode(Addr, Offsets[i].first, Sizes[i]); | ||||
|  | ||||
|       DEBUG(dbgs() << "  loading code: " << Offsets[i].first | ||||
|             << " to remote: 0x" << format("%llx", Addr) << "\n"); | ||||
|     } else { | ||||
|       T->loadData(Addr, Offsets[i].first, Sizes[i]); | ||||
|  | ||||
|       DEBUG(dbgs() << "  loading data: " << Offsets[i].first | ||||
|             << " to remote: 0x" << format("%llx", Addr) << "\n"); | ||||
|     } | ||||
|  | ||||
|   } | ||||
| } | ||||
|  | ||||
| //===----------------------------------------------------------------------===// | ||||
| // main Driver function | ||||
| // | ||||
| @@ -370,7 +300,7 @@ int main(int argc, char **argv, char * const *envp) { | ||||
|   if (UseMCJIT && !ForceInterpreter) { | ||||
|     builder.setUseMCJIT(true); | ||||
|     if (RemoteMCJIT) | ||||
|       RTDyldMM = new RecordingMemoryManager(); | ||||
|       RTDyldMM = new RemoteMemoryManager(); | ||||
|     else | ||||
|       RTDyldMM = new SectionMemoryManager(); | ||||
|     builder.setMCJITMemoryManager(RTDyldMM); | ||||
| @@ -420,6 +350,16 @@ int main(int argc, char **argv, char * const *envp) { | ||||
|     exit(1); | ||||
|   } | ||||
|  | ||||
|   // Load any additional modules specified on the command line. | ||||
|   for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) { | ||||
|     Module *XMod = ParseIRFile(ExtraModules[i], Err, Context); | ||||
|     if (!XMod) { | ||||
|       Err.print(argv[0], errs()); | ||||
|       return 1; | ||||
|     } | ||||
|     EE->addModule(XMod); | ||||
|   } | ||||
|  | ||||
|   // The following functions have no effect if their respective profiling | ||||
|   // support wasn't enabled in the build configuration. | ||||
|   EE->RegisterJITEventListener( | ||||
| @@ -519,7 +459,7 @@ int main(int argc, char **argv, char * const *envp) { | ||||
|     // it couldn't. This is a limitation of the LLI implemantation, not the | ||||
|     // MCJIT itself. FIXME. | ||||
|     // | ||||
|     RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(RTDyldMM); | ||||
|     RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(RTDyldMM); | ||||
|     // Everything is prepared now, so lay out our program for the target | ||||
|     // address space, assign the section addresses to resolve any relocations, | ||||
|     // and send it to the target. | ||||
| @@ -543,19 +483,30 @@ int main(int argc, char **argv, char * const *envp) { | ||||
|       Target.reset(RemoteTarget::createRemoteTarget()); | ||||
|     } | ||||
|  | ||||
|     // Create the remote target | ||||
|     // Give the memory manager a pointer to our remote target interface object. | ||||
|     MM->setRemoteTarget(Target.get()); | ||||
|  | ||||
|     // Create the remote target. | ||||
|     Target->create(); | ||||
|  | ||||
| // FIXME: Don't commit like this.  I don't think these calls are necessary. | ||||
| #if 0 | ||||
|     // Trigger compilation. | ||||
|     EE->generateCodeForModule(Mod); | ||||
|  | ||||
|     // Layout the target memory. | ||||
|     layoutRemoteTargetMemory(Target.get(), MM); | ||||
|     // Get everything ready to execute. | ||||
|     EE->finalizeModule(Mod); | ||||
| #endif | ||||
|  | ||||
|     // Since we're executing in a (at least simulated) remote address space, | ||||
|     // we can't use the ExecutionEngine::runFunctionAsMain(). We have to | ||||
|     // grab the function address directly here and tell the remote target | ||||
|     // to execute the function. | ||||
|     // | ||||
|     // Our memory manager will map generated code into the remote address | ||||
|     // space as it is loaded and copy the bits over during the finalizeMemory | ||||
|     // operation. | ||||
|     // | ||||
|     // FIXME: argv and envp handling. | ||||
|     uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str()); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user