diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h --- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h @@ -32,6 +32,7 @@ ExecutorAddr WriteUInt32s; ExecutorAddr WriteUInt64s; ExecutorAddr WriteBuffers; + ExecutorAddr WritePointers; }; /// Create an EPCGenericMemoryAccess instance from a given set of @@ -74,6 +75,13 @@ FAs.WriteBuffers, std::move(OnWriteComplete), Ws); } + void writePointersAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override { + using namespace shared; + EPC.callSPSWrapperAsync)>( + FAs.WritePointers, std::move(OnWriteComplete), Ws); + } + private: ExecutorProcessControl &EPC; FuncAddrs FAs; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h --- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h @@ -120,6 +120,9 @@ virtual void writeBuffersAsync(ArrayRef Ws, WriteResultFn OnWriteComplete) = 0; + virtual void writePointersAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) = 0; + Error writeUInt8s(ArrayRef Ws) { std::promise ResultP; auto ResultF = ResultP.get_future(); @@ -159,6 +162,14 @@ [&](Error Err) { ResultP.set_value(std::move(Err)); }); return ResultF.get(); } + + Error writePointers(ArrayRef Ws) { + std::promise ResultP; + auto ResultF = ResultP.get_future(); + writePointersAsync(Ws, + [&](Error Err) { ResultP.set_value(std::move(Err)); }); + return ResultF.get(); + } }; /// A pair of a dylib and a set of symbols to be looked up. @@ -403,21 +414,48 @@ StringMap BootstrapSymbols; }; +class InProcessMemoryAccess : public ExecutorProcessControl::MemoryAccess { +public: + InProcessMemoryAccess(bool IsArch64Bit) : IsArch64Bit(IsArch64Bit) {} + void writeUInt8sAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override; + + void writeUInt16sAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override; + + void writeUInt32sAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override; + + void writeUInt64sAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override; + + void writeBuffersAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override; + + void writePointersAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) override; + +private: + bool IsArch64Bit; +}; + /// A ExecutorProcessControl instance that asserts if any of its methods are /// used. Suitable for use is unit tests, and by ORC clients who haven't moved /// to ExecutorProcessControl-based APIs yet. -class UnsupportedExecutorProcessControl : public ExecutorProcessControl { +class UnsupportedExecutorProcessControl : public ExecutorProcessControl, + private InProcessMemoryAccess { public: UnsupportedExecutorProcessControl( std::shared_ptr SSP = nullptr, - std::unique_ptr D = nullptr, - const std::string &TT = "", unsigned PageSize = 0) - : ExecutorProcessControl(SSP ? std::move(SSP) - : std::make_shared(), - D ? std::move(D) - : std::make_unique()) { + std::unique_ptr D = nullptr, const std::string &TT = "", + unsigned PageSize = 0) + : ExecutorProcessControl( + SSP ? std::move(SSP) : std::make_shared(), + D ? std::move(D) : std::make_unique()), + InProcessMemoryAccess(Triple(TT).isArch64Bit()) { this->TargetTriple = Triple(TT); this->PageSize = PageSize; + this->MemAccess = this; } Expected loadDylib(const char *DylibPath) override { @@ -452,9 +490,8 @@ }; /// A ExecutorProcessControl implementation targeting the current process. -class SelfExecutorProcessControl - : public ExecutorProcessControl, - private ExecutorProcessControl::MemoryAccess { +class SelfExecutorProcessControl : public ExecutorProcessControl, + private InProcessMemoryAccess { public: SelfExecutorProcessControl( std::shared_ptr SSP, std::unique_ptr D, @@ -490,21 +527,6 @@ Error disconnect() override; private: - void writeUInt8sAsync(ArrayRef Ws, - WriteResultFn OnWriteComplete) override; - - void writeUInt16sAsync(ArrayRef Ws, - WriteResultFn OnWriteComplete) override; - - void writeUInt32sAsync(ArrayRef Ws, - WriteResultFn OnWriteComplete) override; - - void writeUInt64sAsync(ArrayRef Ws, - WriteResultFn OnWriteComplete) override; - - void writeBuffersAsync(ArrayRef Ws, - WriteResultFn OnWriteComplete) override; - static shared::CWrapperFunctionResult jitDispatchViaWrapperFunctionManager(void *Ctx, const void *FnTag, const char *Data, size_t Size); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h --- a/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -13,14 +13,18 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/OrcABISupport.h" #include "llvm/Support/Error.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Process.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include #include @@ -29,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +60,8 @@ namespace orc { +class ObjectLinkingLayer; + /// Base class for pools of compiler re-entry trampolines. /// These trampolines are callable addresses that save all register state /// before calling a supplied function to return the trampoline landing @@ -309,6 +316,119 @@ virtual void anchor(); }; +/// Base class for managing redirectable symbols in which a call +/// gets redirected to another symbol in runtime. +class RedirectionManager { +public: + /// Symbol name to symbol definition map. + using SymbolAddrMap = DenseMap; + + virtual ~RedirectionManager() = default; + + /// Create redirectable symbols with given symbol names and initial + /// desitnation symbols. + virtual Error + createRedirectableSymbols(const SymbolAddrMap &InitialDests) = 0; + + /// Create a single redirectable symbol with given symbol name and initial + /// desitnation symbol. + virtual Error createRedirectableSymbol(SymbolStringPtr Symbol, + ExecutorSymbolDef InitialDest) { + return createRedirectableSymbols({{Symbol, InitialDest}}); + } + + /// Release redirectable symbols. + virtual Error releaseRedirectableSymbols(const SymbolNameSet &Symbols) = 0; + + /// Release redirectable symbol. + virtual Error releaseRedirectableSymbol(SymbolStringPtr Symbol) { + return releaseRedirectableSymbols({Symbol}); + } + + /// Change the redirection destination of given symbols to new destination + /// symbols. + virtual Error redirect(const SymbolAddrMap &NewDests) = 0; + + /// Change the redirection destination of given symbol to new destination + /// symbol. + virtual Error redirect(SymbolStringPtr Symbol, ExecutorSymbolDef NewDest) { + return redirect({{Symbol, NewDest}}); + } + +private: + virtual void anchor(); +}; + +class JITLinkRedirectionManager : public RedirectionManager { +public: + /// Create redirection manager that uses JITLink based implementaion. + static Expected> + Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, + JITDylib &JD) { + Error Err = Error::success(); + auto RM = std::unique_ptr( + new JITLinkRedirectionManager(ES, ObjLinkingLayer, JD, Err)); + if (Err) + return Err; + return std::move(RM); + } + + Error createRedirectableSymbols(const SymbolAddrMap &InitialDests) override; + + Error releaseRedirectableSymbols(const SymbolNameSet &Symbols) override; + + Error redirect(const SymbolAddrMap &NewDests) override; + +private: + using StubHandle = unsigned; + constexpr static unsigned StubBlockSize = 256; + constexpr static StringRef JumpStubPrefix = "$__IND_JUMP_STUBS"; + constexpr static StringRef StubPtrPrefix = "$IND_JUMP_PTR_"; + constexpr static StringRef JumpStubTableName = "$IND_JUMP_"; + constexpr static StringRef StubPtrTableName = "$__IND_JUMP_PTRS"; + + JITLinkRedirectionManager(ExecutionSession &ES, + ObjectLinkingLayer &ObjLinkingLayer, JITDylib &JD, + Error &Err) + : ES(ES), ObjLinkingLayer(ObjLinkingLayer), JD(JD), + AnonymousPtrCreator( + jitlink::getAnonymousPointerCreator(ES.getTargetTriple())), + PtrJumpStubCreator( + jitlink::getPointerJumpStubCreator(ES.getTargetTriple())) { + if (!AnonymousPtrCreator || !PtrJumpStubCreator) + Err = make_error("Architecture not supported", + inconvertibleErrorCode()); + } + + StringRef JumpStubSymbolName(unsigned I) { + return StringPool.save((JumpStubPrefix + Twine(I)).str()); + } + + StringRef StubPtrSymbolName(unsigned I) { + return StringPool.save((StubPtrPrefix + Twine(I)).str()); + } + + unsigned GetNumAvailableStubs() const { return AvailbleStubs.size(); } + + Error redirectInner(const SymbolAddrMap &NewDests); + Error grow(unsigned Need); + + ExecutionSession &ES; + ObjectLinkingLayer &ObjLinkingLayer; + JITDylib &JD; + jitlink::AnonymousPointerCreator AnonymousPtrCreator; + jitlink::PointerJumpStubCreator PtrJumpStubCreator; + + std::vector AvailbleStubs; + DenseMap SymbolToStubs; + std::vector JumpStubs; + std::vector StubPointers; + + BumpPtrAllocator BAlloc; + StringSaver StringPool{BAlloc}; + std::mutex Mutex; +}; + template class LocalIndirectStubsInfo { public: LocalIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem) @@ -332,7 +452,7 @@ return errorCodeToError(EC); sys::MemoryBlock StubsBlock(StubsAndPtrsMem.base(), ISAS.StubBytes); - auto StubsBlockMem = static_cast(StubsAndPtrsMem.base()); + auto *StubsBlockMem = static_cast(StubsAndPtrsMem.base()); auto PtrBlockAddress = ExecutorAddr::fromPtr(StubsBlockMem) + ISAS.StubBytes; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h --- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h @@ -100,6 +100,17 @@ StringRef Buffer; }; +/// Describes a write to a pointer. +/// For use with TargetProcessControl::MemoryAccess objects. +struct PointerWrite { + PointerWrite() = default; + PointerWrite(ExecutorAddr Addr, ExecutorAddr Value) + : Addr(Addr), Value(Value) {} + + ExecutorAddr Addr; + ExecutorAddr Value; +}; + /// A handle used to represent a loaded dylib in the target process. using DylibHandle = ExecutorAddr; @@ -133,6 +144,7 @@ using SPSMemoryAccessUInt64Write = SPSMemoryAccessUIntWrite; using SPSMemoryAccessBufferWrite = SPSTuple>; +using SPSMemoryAccessPointerWrite = SPSTuple; template <> class SPSSerializationTraits { @@ -302,6 +314,26 @@ } }; +template <> +class SPSSerializationTraits { +public: + static size_t size(const tpctypes::PointerWrite &W) { + return SPSTuple::AsArgList::size(W.Addr, + W.Value); + } + + static bool serialize(SPSOutputBuffer &OB, const tpctypes::PointerWrite &W) { + return SPSTuple::AsArgList::serialize( + OB, W.Addr, W.Value); + } + + static bool deserialize(SPSInputBuffer &IB, tpctypes::PointerWrite &W) { + return SPSTuple::AsArgList::deserialize( + IB, W.Addr, W.Value); + } +}; + } // end namespace shared } // end namespace orc } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp --- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp @@ -27,7 +27,8 @@ std::shared_ptr SSP, std::unique_ptr D, Triple TargetTriple, unsigned PageSize, std::unique_ptr MemMgr) - : ExecutorProcessControl(std::move(SSP), std::move(D)) { + : ExecutorProcessControl(std::move(SSP), std::move(D)), + InProcessMemoryAccess(TargetTriple.isArch64Bit()) { OwnedMemMgr = std::move(MemMgr); if (!OwnedMemMgr) @@ -139,41 +140,54 @@ return Error::success(); } -void SelfExecutorProcessControl::writeUInt8sAsync( - ArrayRef Ws, WriteResultFn OnWriteComplete) { +void InProcessMemoryAccess::writeUInt8sAsync(ArrayRef Ws, + WriteResultFn OnWriteComplete) { for (auto &W : Ws) *W.Addr.toPtr() = W.Value; OnWriteComplete(Error::success()); } -void SelfExecutorProcessControl::writeUInt16sAsync( +void InProcessMemoryAccess::writeUInt16sAsync( ArrayRef Ws, WriteResultFn OnWriteComplete) { for (auto &W : Ws) *W.Addr.toPtr() = W.Value; OnWriteComplete(Error::success()); } -void SelfExecutorProcessControl::writeUInt32sAsync( +void InProcessMemoryAccess::writeUInt32sAsync( ArrayRef Ws, WriteResultFn OnWriteComplete) { for (auto &W : Ws) *W.Addr.toPtr() = W.Value; OnWriteComplete(Error::success()); } -void SelfExecutorProcessControl::writeUInt64sAsync( +void InProcessMemoryAccess::writeUInt64sAsync( ArrayRef Ws, WriteResultFn OnWriteComplete) { for (auto &W : Ws) *W.Addr.toPtr() = W.Value; OnWriteComplete(Error::success()); } -void SelfExecutorProcessControl::writeBuffersAsync( +void InProcessMemoryAccess::writeBuffersAsync( ArrayRef Ws, WriteResultFn OnWriteComplete) { for (auto &W : Ws) memcpy(W.Addr.toPtr(), W.Buffer.data(), W.Buffer.size()); OnWriteComplete(Error::success()); } +void InProcessMemoryAccess::writePointersAsync( + ArrayRef Ws, WriteResultFn OnWriteComplete) { + if (IsArch64Bit) { + for (auto &W : Ws) + *W.Addr.toPtr() = W.Value.getValue(); + } else { + for (auto &W : Ws) + *W.Addr.toPtr() = static_cast(W.Value.getValue()); + } + + OnWriteComplete(Error::success()); +} + shared::CWrapperFunctionResult SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager( void *Ctx, const void *FnTag, const char *Data, size_t Size) { diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp --- a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -8,15 +8,24 @@ #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/JITLink/JITLink.h" +#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/ExecutionEngine/Orc/OrcABISupport.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h" +#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h" +#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" #include "llvm/IR/IRBuilder.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/Cloning.h" #include +#include #define DEBUG_TYPE "orc" @@ -62,6 +71,151 @@ TrampolinePool::~TrampolinePool() = default; void IndirectStubsManager::anchor() {} +void RedirectionManager::anchor() {} + +Error JITLinkRedirectionManager::createRedirectableSymbols( + const SymbolAddrMap &InitialDests) { + std::unique_lock Lock(Mutex); + if (GetNumAvailableStubs() < InitialDests.size()) + if (auto Err = grow(InitialDests.size() - GetNumAvailableStubs())) + return Err; + + SymbolMap NewSymbolDefs; + for (auto &[K, V] : InitialDests) { + StubHandle StubID = AvailbleStubs.back(); + if (SymbolToStubs.count(K)) + return make_error( + "Tried to create duplicate redirectable symbols", + inconvertibleErrorCode()); + SymbolToStubs[K] = StubID; + NewSymbolDefs[K] = JumpStubs[StubID]; + AvailbleStubs.pop_back(); + } + + if (auto Err = JD.define(absoluteSymbols(NewSymbolDefs))) + return Err; + + if (auto Err = redirectInner(InitialDests)) + return Err; + + return Error::success(); +} + +Error JITLinkRedirectionManager::releaseRedirectableSymbols( + const SymbolNameSet &Symbols) { + std::unique_lock Lock(Mutex); + for (auto &K : Symbols) { + if (!SymbolToStubs.count(K)) + return make_error( + "Tried to remove non-existent redirectalbe symbol", + inconvertibleErrorCode()); + AvailbleStubs.push_back(SymbolToStubs.at(K)); + SymbolToStubs.erase(K); + } + + if (auto Err = JD.remove(Symbols)) + return Err; + + return Error::success(); +} + +Error JITLinkRedirectionManager::redirect(const SymbolAddrMap &NewDests) { + std::unique_lock Lock(Mutex); + return redirectInner(NewDests); +} + +Error JITLinkRedirectionManager::redirectInner(const SymbolAddrMap &NewDests) { + std::vector> PtrWrites; + for (auto &[K, V] : NewDests) { + if (!SymbolToStubs.count(K)) + return make_error( + "Tried to redirect non-existent redirectalbe symbol", + inconvertibleErrorCode()); + StubHandle StubID = SymbolToStubs.at(K); + PtrWrites.push_back({StubPointers[StubID].getAddress(), V.getAddress()}); + } + + if (ES.getTargetTriple().isArch64Bit()) { + std::vector NativeWrites; + for (auto &[Ptr, Target] : PtrWrites) + NativeWrites.push_back(tpctypes::UInt64Write(Ptr, Target.getValue())); + if (auto Err = + ES.getExecutorProcessControl().getMemoryAccess().writeUInt64s( + NativeWrites)) + return Err; + } else { + assert(DL.getPointerSize() == 4 && "Unsupported pointer size"); + std::vector NativeWrites; + for (auto &[Ptr, Target] : PtrWrites) + NativeWrites.push_back(tpctypes::UInt32Write(Ptr, Target.getValue())); + if (auto Err = + ES.getExecutorProcessControl().getMemoryAccess().writeUInt32s( + NativeWrites)) + return Err; + } + return Error::success(); +} + +Error JITLinkRedirectionManager::grow(unsigned Need) { + unsigned OldSize = JumpStubs.size(); + unsigned NumNewStubs = alignTo(Need, StubBlockSize); + unsigned NewSize = OldSize + NumNewStubs; + + JumpStubs.resize(NewSize); + StubPointers.resize(NewSize); + AvailbleStubs.reserve(NewSize); + + SymbolLookupSet LookupSymbols; + DenseMap NewDefsMap; + + Triple TT = ES.getTargetTriple(); + auto G = std::make_unique( + "", TT, TT.isArch64Bit() ? 8 : 4, + TT.isLittleEndian() ? support::little : support::big, + jitlink::getGenericEdgeKindName); + auto &PointerSection = + G->createSection(StubPtrTableName, MemProt::Write | MemProt::Read); + auto &StubsSection = + G->createSection(JumpStubTableName, MemProt::Exec | MemProt::Read); + + for (size_t I = OldSize; I < NewSize; I++) { + auto Pointer = AnonymousPtrCreator(*G, PointerSection, nullptr, 0); + if (auto Err = Pointer.takeError()) + return Err; + + StringRef PtrSymName = StubPtrSymbolName(I); + Pointer->setName(PtrSymName); + Pointer->setScope(jitlink::Scope::Default); + LookupSymbols.add(ES.intern(PtrSymName)); + NewDefsMap[ES.intern(PtrSymName)] = &StubPointers[I]; + + auto Stub = PtrJumpStubCreator(*G, StubsSection, *Pointer); + if (auto Err = Stub.takeError()) + return Err; + + StringRef JumpStubSymName = JumpStubSymbolName(I); + Stub->setName(JumpStubSymName); + Stub->setScope(jitlink::Scope::Default); + LookupSymbols.add(ES.intern(JumpStubSymName)); + NewDefsMap[ES.intern(JumpStubSymName)] = &JumpStubs[I]; + } + + if (auto Err = ObjLinkingLayer.add(JD, std::move(G))) + return Err; + + auto LookupResult = ES.lookup(makeJITDylibSearchOrder(&JD), LookupSymbols); + if (auto Err = LookupResult.takeError()) + return Err; + + for (auto &[K, V] : *LookupResult) + *NewDefsMap.at(K) = V; + + for (size_t I = OldSize; I < NewSize; I++) + AvailbleStubs.push_back(I); + + return Error::success(); +} + Expected JITCompileCallbackManager::getCompileCallback(CompileFunction Compile) { if (auto TrampolineAddr = TP->getTrampoline()) { @@ -251,9 +405,9 @@ GlobalVariable* createImplPointer(PointerType &PT, Module &M, const Twine &Name, Constant *Initializer) { - auto IP = new GlobalVariable(M, &PT, false, GlobalValue::ExternalLinkage, - Initializer, Name, nullptr, - GlobalValue::NotThreadLocal, 0, true); + auto *IP = new GlobalVariable(M, &PT, false, GlobalValue::ExternalLinkage, + Initializer, Name, nullptr, + GlobalValue::NotThreadLocal, 0, true); IP->setVisibility(GlobalValue::HiddenVisibility); return IP; } @@ -316,7 +470,7 @@ if (VMap) { (*VMap)[&F] = NewF; - auto NewArgI = NewF->arg_begin(); + auto *NewArgI = NewF->arg_begin(); for (auto ArgI = F.arg_begin(), ArgE = F.arg_end(); ArgI != ArgE; ++ArgI, ++NewArgI) (*VMap)[&*ArgI] = &*NewArgI; @@ -364,7 +518,7 @@ auto &B = Sym.getBlock(); assert(!B.isZeroFill() && "expected content block"); auto SymAddress = Sym.getAddress(); - auto SymStartInBlock = + auto *SymStartInBlock = (const uint8_t *)B.getContent().data() + Sym.getOffset(); auto SymSize = Sym.getSize() ? Sym.getSize() : B.getSize() - Sym.getOffset(); auto Content = ArrayRef(SymStartInBlock, SymSize); diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt --- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -40,6 +40,7 @@ TaskDispatchTest.cpp ThreadSafeModuleTest.cpp WrapperFunctionUtilsTest.cpp + JITLinkRedirectionManagerTest.cpp ) target_link_libraries(OrcJITTests PRIVATE diff --git a/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp b/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp --- a/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/EPCGenericMemoryAccessTest.cpp @@ -41,6 +41,17 @@ .release(); } +llvm::orc::shared::CWrapperFunctionResult testWritePointers(const char *ArgData, + size_t ArgSize) { + return WrapperFunction)>:: + handle(ArgData, ArgSize, + [](std::vector Ws) { + for (auto &W : Ws) + *W.Addr.template toPtr() = W.Value.getValue(); + }) + .release(); +} + TEST(EPCGenericMemoryAccessTest, MemWrites) { auto SelfEPC = cantFail(SelfExecutorProcessControl::Create()); @@ -54,6 +65,7 @@ FAs.WriteUInt64s = ExecutorAddr::fromPtr( &testWriteUInts); FAs.WriteBuffers = ExecutorAddr::fromPtr(&testWriteBuffers); + FAs.WritePointers = ExecutorAddr::fromPtr(&testWritePointers); auto MemAccess = std::make_unique(*SelfEPC, FAs); @@ -62,6 +74,7 @@ uint16_t Test_UInt16 = 0; uint32_t Test_UInt32 = 0; uint64_t Test_UInt64 = 0; + uint64_t Test_Pointer = 0; char Test_Buffer[21]; auto Err1 = @@ -93,6 +106,11 @@ EXPECT_THAT_ERROR(std::move(Err5), Succeeded()); EXPECT_EQ(StringRef(Test_Buffer, TestMsg.size()), TestMsg); + auto Err6 = MemAccess->writePointers( + {{ExecutorAddr::fromPtr(&Test_Pointer), ExecutorAddr(1U)}}); + EXPECT_THAT_ERROR(std::move(Err6), Succeeded()); + EXPECT_EQ(Test_Pointer, 1U); + cantFail(SelfEPC->disconnect()); }