EPCIndirectionUtils.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. //===------- EPCIndirectionUtils.cpp -- EPC based indirection APIs --------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h"
  9. #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
  10. #include "llvm/Support/MathExtras.h"
  11. #include <future>
  12. using namespace llvm;
  13. using namespace llvm::orc;
  14. namespace llvm {
  15. namespace orc {
  16. class EPCIndirectionUtilsAccess {
  17. public:
  18. using IndirectStubInfo = EPCIndirectionUtils::IndirectStubInfo;
  19. using IndirectStubInfoVector = EPCIndirectionUtils::IndirectStubInfoVector;
  20. static Expected<IndirectStubInfoVector>
  21. getIndirectStubs(EPCIndirectionUtils &EPCIU, unsigned NumStubs) {
  22. return EPCIU.getIndirectStubs(NumStubs);
  23. };
  24. };
  25. } // end namespace orc
  26. } // end namespace llvm
  27. namespace {
  28. class EPCTrampolinePool : public TrampolinePool {
  29. public:
  30. EPCTrampolinePool(EPCIndirectionUtils &EPCIU);
  31. Error deallocatePool();
  32. protected:
  33. Error grow() override;
  34. using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
  35. EPCIndirectionUtils &EPCIU;
  36. unsigned TrampolineSize = 0;
  37. unsigned TrampolinesPerPage = 0;
  38. std::vector<FinalizedAlloc> TrampolineBlocks;
  39. };
  40. class EPCIndirectStubsManager : public IndirectStubsManager,
  41. private EPCIndirectionUtilsAccess {
  42. public:
  43. EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {}
  44. Error deallocateStubs();
  45. Error createStub(StringRef StubName, JITTargetAddress StubAddr,
  46. JITSymbolFlags StubFlags) override;
  47. Error createStubs(const StubInitsMap &StubInits) override;
  48. JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override;
  49. JITEvaluatedSymbol findPointer(StringRef Name) override;
  50. Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override;
  51. private:
  52. using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
  53. std::mutex ISMMutex;
  54. EPCIndirectionUtils &EPCIU;
  55. StringMap<StubInfo> StubInfos;
  56. };
  57. EPCTrampolinePool::EPCTrampolinePool(EPCIndirectionUtils &EPCIU)
  58. : EPCIU(EPCIU) {
  59. auto &EPC = EPCIU.getExecutorProcessControl();
  60. auto &ABI = EPCIU.getABISupport();
  61. TrampolineSize = ABI.getTrampolineSize();
  62. TrampolinesPerPage =
  63. (EPC.getPageSize() - ABI.getPointerSize()) / TrampolineSize;
  64. }
  65. Error EPCTrampolinePool::deallocatePool() {
  66. Error Err = Error::success();
  67. std::promise<MSVCPError> DeallocResultP;
  68. auto DeallocResultF = DeallocResultP.get_future();
  69. EPCIU.getExecutorProcessControl().getMemMgr().deallocate(
  70. std::move(TrampolineBlocks),
  71. [&](Error Err) { DeallocResultP.set_value(std::move(Err)); });
  72. return DeallocResultF.get();
  73. }
  74. Error EPCTrampolinePool::grow() {
  75. using namespace jitlink;
  76. assert(AvailableTrampolines.empty() &&
  77. "Grow called with trampolines still available");
  78. auto ResolverAddress = EPCIU.getResolverBlockAddress();
  79. assert(ResolverAddress && "Resolver address can not be null");
  80. auto &EPC = EPCIU.getExecutorProcessControl();
  81. auto PageSize = EPC.getPageSize();
  82. auto Alloc = SimpleSegmentAlloc::Create(
  83. EPC.getMemMgr(), nullptr,
  84. {{MemProt::Read | MemProt::Exec, {PageSize, Align(PageSize)}}});
  85. if (!Alloc)
  86. return Alloc.takeError();
  87. unsigned NumTrampolines = TrampolinesPerPage;
  88. auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
  89. EPCIU.getABISupport().writeTrampolines(SegInfo.WorkingMem.data(),
  90. SegInfo.Addr.getValue(),
  91. ResolverAddress, NumTrampolines);
  92. for (unsigned I = 0; I < NumTrampolines; ++I)
  93. AvailableTrampolines.push_back(SegInfo.Addr.getValue() +
  94. (I * TrampolineSize));
  95. auto FA = Alloc->finalize();
  96. if (!FA)
  97. return FA.takeError();
  98. TrampolineBlocks.push_back(std::move(*FA));
  99. return Error::success();
  100. }
  101. Error EPCIndirectStubsManager::createStub(StringRef StubName,
  102. JITTargetAddress StubAddr,
  103. JITSymbolFlags StubFlags) {
  104. StubInitsMap SIM;
  105. SIM[StubName] = std::make_pair(StubAddr, StubFlags);
  106. return createStubs(SIM);
  107. }
  108. Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
  109. auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
  110. if (!AvailableStubInfos)
  111. return AvailableStubInfos.takeError();
  112. {
  113. std::lock_guard<std::mutex> Lock(ISMMutex);
  114. unsigned ASIdx = 0;
  115. for (auto &SI : StubInits) {
  116. auto &A = (*AvailableStubInfos)[ASIdx++];
  117. StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
  118. }
  119. }
  120. auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
  121. switch (EPCIU.getABISupport().getPointerSize()) {
  122. case 4: {
  123. unsigned ASIdx = 0;
  124. std::vector<tpctypes::UInt32Write> PtrUpdates;
  125. for (auto &SI : StubInits)
  126. PtrUpdates.push_back(
  127. {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
  128. static_cast<uint32_t>(SI.second.first)});
  129. return MemAccess.writeUInt32s(PtrUpdates);
  130. }
  131. case 8: {
  132. unsigned ASIdx = 0;
  133. std::vector<tpctypes::UInt64Write> PtrUpdates;
  134. for (auto &SI : StubInits)
  135. PtrUpdates.push_back(
  136. {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
  137. static_cast<uint64_t>(SI.second.first)});
  138. return MemAccess.writeUInt64s(PtrUpdates);
  139. }
  140. default:
  141. return make_error<StringError>("Unsupported pointer size",
  142. inconvertibleErrorCode());
  143. }
  144. }
  145. JITEvaluatedSymbol EPCIndirectStubsManager::findStub(StringRef Name,
  146. bool ExportedStubsOnly) {
  147. std::lock_guard<std::mutex> Lock(ISMMutex);
  148. auto I = StubInfos.find(Name);
  149. if (I == StubInfos.end())
  150. return nullptr;
  151. return {I->second.first.StubAddress, I->second.second};
  152. }
  153. JITEvaluatedSymbol EPCIndirectStubsManager::findPointer(StringRef Name) {
  154. std::lock_guard<std::mutex> Lock(ISMMutex);
  155. auto I = StubInfos.find(Name);
  156. if (I == StubInfos.end())
  157. return nullptr;
  158. return {I->second.first.PointerAddress, I->second.second};
  159. }
  160. Error EPCIndirectStubsManager::updatePointer(StringRef Name,
  161. JITTargetAddress NewAddr) {
  162. JITTargetAddress PtrAddr = 0;
  163. {
  164. std::lock_guard<std::mutex> Lock(ISMMutex);
  165. auto I = StubInfos.find(Name);
  166. if (I == StubInfos.end())
  167. return make_error<StringError>("Unknown stub name",
  168. inconvertibleErrorCode());
  169. PtrAddr = I->second.first.PointerAddress;
  170. }
  171. auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
  172. switch (EPCIU.getABISupport().getPointerSize()) {
  173. case 4: {
  174. tpctypes::UInt32Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
  175. return MemAccess.writeUInt32s(PUpdate);
  176. }
  177. case 8: {
  178. tpctypes::UInt64Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
  179. return MemAccess.writeUInt64s(PUpdate);
  180. }
  181. default:
  182. return make_error<StringError>("Unsupported pointer size",
  183. inconvertibleErrorCode());
  184. }
  185. }
  186. } // end anonymous namespace.
  187. namespace llvm {
  188. namespace orc {
  189. EPCIndirectionUtils::ABISupport::~ABISupport() {}
  190. Expected<std::unique_ptr<EPCIndirectionUtils>>
  191. EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) {
  192. const auto &TT = EPC.getTargetTriple();
  193. switch (TT.getArch()) {
  194. default:
  195. return make_error<StringError>(
  196. std::string("No EPCIndirectionUtils available for ") + TT.str(),
  197. inconvertibleErrorCode());
  198. case Triple::aarch64:
  199. case Triple::aarch64_32:
  200. return CreateWithABI<OrcAArch64>(EPC);
  201. case Triple::x86:
  202. return CreateWithABI<OrcI386>(EPC);
  203. case Triple::mips:
  204. return CreateWithABI<OrcMips32Be>(EPC);
  205. case Triple::mipsel:
  206. return CreateWithABI<OrcMips32Le>(EPC);
  207. case Triple::mips64:
  208. case Triple::mips64el:
  209. return CreateWithABI<OrcMips64>(EPC);
  210. case Triple::x86_64:
  211. if (TT.getOS() == Triple::OSType::Win32)
  212. return CreateWithABI<OrcX86_64_Win32>(EPC);
  213. else
  214. return CreateWithABI<OrcX86_64_SysV>(EPC);
  215. }
  216. }
  217. Error EPCIndirectionUtils::cleanup() {
  218. auto &MemMgr = EPC.getMemMgr();
  219. auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs));
  220. if (TP)
  221. Err = joinErrors(std::move(Err),
  222. static_cast<EPCTrampolinePool &>(*TP).deallocatePool());
  223. if (ResolverBlock)
  224. Err =
  225. joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock)));
  226. return Err;
  227. }
  228. Expected<JITTargetAddress>
  229. EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr,
  230. JITTargetAddress ReentryCtxAddr) {
  231. using namespace jitlink;
  232. assert(ABI && "ABI can not be null");
  233. auto ResolverSize = ABI->getResolverCodeSize();
  234. auto Alloc =
  235. SimpleSegmentAlloc::Create(EPC.getMemMgr(), nullptr,
  236. {{MemProt::Read | MemProt::Exec,
  237. {ResolverSize, Align(EPC.getPageSize())}}});
  238. if (!Alloc)
  239. return Alloc.takeError();
  240. auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
  241. ResolverBlockAddr = SegInfo.Addr.getValue();
  242. ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
  243. ReentryFnAddr, ReentryCtxAddr);
  244. auto FA = Alloc->finalize();
  245. if (!FA)
  246. return FA.takeError();
  247. ResolverBlock = std::move(*FA);
  248. return ResolverBlockAddr;
  249. }
  250. std::unique_ptr<IndirectStubsManager>
  251. EPCIndirectionUtils::createIndirectStubsManager() {
  252. return std::make_unique<EPCIndirectStubsManager>(*this);
  253. }
  254. TrampolinePool &EPCIndirectionUtils::getTrampolinePool() {
  255. if (!TP)
  256. TP = std::make_unique<EPCTrampolinePool>(*this);
  257. return *TP;
  258. }
  259. LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager(
  260. ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
  261. assert(!LCTM &&
  262. "createLazyCallThroughManager can not have been called before");
  263. LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
  264. &getTrampolinePool());
  265. return *LCTM;
  266. }
  267. EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC,
  268. std::unique_ptr<ABISupport> ABI)
  269. : EPC(EPC), ABI(std::move(ABI)) {
  270. assert(this->ABI && "ABI can not be null");
  271. assert(EPC.getPageSize() > getABISupport().getStubSize() &&
  272. "Stubs larger than one page are not supported");
  273. }
  274. Expected<EPCIndirectionUtils::IndirectStubInfoVector>
  275. EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
  276. using namespace jitlink;
  277. std::lock_guard<std::mutex> Lock(EPCUIMutex);
  278. // If there aren't enough stubs available then allocate some more.
  279. if (NumStubs > AvailableIndirectStubs.size()) {
  280. auto NumStubsToAllocate = NumStubs;
  281. auto PageSize = EPC.getPageSize();
  282. auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
  283. NumStubsToAllocate = StubBytes / ABI->getStubSize();
  284. auto PtrBytes =
  285. alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
  286. auto StubProt = MemProt::Read | MemProt::Exec;
  287. auto PtrProt = MemProt::Read | MemProt::Write;
  288. auto Alloc = SimpleSegmentAlloc::Create(
  289. EPC.getMemMgr(), nullptr,
  290. {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
  291. {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
  292. if (!Alloc)
  293. return Alloc.takeError();
  294. auto StubSeg = Alloc->getSegInfo(StubProt);
  295. auto PtrSeg = Alloc->getSegInfo(PtrProt);
  296. ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
  297. StubSeg.Addr.getValue(),
  298. PtrSeg.Addr.getValue(), NumStubsToAllocate);
  299. auto FA = Alloc->finalize();
  300. if (!FA)
  301. return FA.takeError();
  302. IndirectStubAllocs.push_back(std::move(*FA));
  303. auto StubExecutorAddr = StubSeg.Addr;
  304. auto PtrExecutorAddr = PtrSeg.Addr;
  305. for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
  306. AvailableIndirectStubs.push_back(IndirectStubInfo(
  307. StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
  308. StubExecutorAddr += ABI->getStubSize();
  309. PtrExecutorAddr += ABI->getPointerSize();
  310. }
  311. }
  312. assert(NumStubs <= AvailableIndirectStubs.size() &&
  313. "Sufficient stubs should have been allocated above");
  314. IndirectStubInfoVector Result;
  315. while (NumStubs--) {
  316. Result.push_back(AvailableIndirectStubs.back());
  317. AvailableIndirectStubs.pop_back();
  318. }
  319. return std::move(Result);
  320. }
  321. static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
  322. JITTargetAddress TrampolineAddr) {
  323. auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
  324. std::promise<JITTargetAddress> LandingAddrP;
  325. auto LandingAddrF = LandingAddrP.get_future();
  326. LCTM.resolveTrampolineLandingAddress(
  327. TrampolineAddr,
  328. [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); });
  329. return LandingAddrF.get();
  330. }
  331. Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) {
  332. auto &LCTM = EPCIU.getLazyCallThroughManager();
  333. return EPCIU
  334. .writeResolverBlock(pointerToJITTargetAddress(&reentry),
  335. pointerToJITTargetAddress(&LCTM))
  336. .takeError();
  337. }
  338. } // end namespace orc
  339. } // end namespace llvm