MachO_x86_64.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
  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. //
  9. // MachO/x86-64 jit-link implementation.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
  13. #include "llvm/ExecutionEngine/JITLink/x86_64.h"
  14. #include "MachOLinkGraphBuilder.h"
  15. #include "PerGraphGOTAndPLTStubsBuilder.h"
  16. #define DEBUG_TYPE "jitlink"
  17. using namespace llvm;
  18. using namespace llvm::jitlink;
  19. namespace {
  20. class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
  21. public:
  22. MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
  23. : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"),
  24. x86_64::getEdgeKindName) {}
  25. private:
  26. enum MachONormalizedRelocationType : unsigned {
  27. MachOBranch32,
  28. MachOPointer32,
  29. MachOPointer64,
  30. MachOPointer64Anon,
  31. MachOPCRel32,
  32. MachOPCRel32Minus1,
  33. MachOPCRel32Minus2,
  34. MachOPCRel32Minus4,
  35. MachOPCRel32Anon,
  36. MachOPCRel32Minus1Anon,
  37. MachOPCRel32Minus2Anon,
  38. MachOPCRel32Minus4Anon,
  39. MachOPCRel32GOTLoad,
  40. MachOPCRel32GOT,
  41. MachOPCRel32TLV,
  42. MachOSubtractor32,
  43. MachOSubtractor64,
  44. };
  45. static Expected<MachONormalizedRelocationType>
  46. getRelocKind(const MachO::relocation_info &RI) {
  47. switch (RI.r_type) {
  48. case MachO::X86_64_RELOC_UNSIGNED:
  49. if (!RI.r_pcrel) {
  50. if (RI.r_length == 3)
  51. return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
  52. else if (RI.r_extern && RI.r_length == 2)
  53. return MachOPointer32;
  54. }
  55. break;
  56. case MachO::X86_64_RELOC_SIGNED:
  57. if (RI.r_pcrel && RI.r_length == 2)
  58. return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon;
  59. break;
  60. case MachO::X86_64_RELOC_BRANCH:
  61. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  62. return MachOBranch32;
  63. break;
  64. case MachO::X86_64_RELOC_GOT_LOAD:
  65. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  66. return MachOPCRel32GOTLoad;
  67. break;
  68. case MachO::X86_64_RELOC_GOT:
  69. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  70. return MachOPCRel32GOT;
  71. break;
  72. case MachO::X86_64_RELOC_SUBTRACTOR:
  73. if (!RI.r_pcrel && RI.r_extern) {
  74. if (RI.r_length == 2)
  75. return MachOSubtractor32;
  76. else if (RI.r_length == 3)
  77. return MachOSubtractor64;
  78. }
  79. break;
  80. case MachO::X86_64_RELOC_SIGNED_1:
  81. if (RI.r_pcrel && RI.r_length == 2)
  82. return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon;
  83. break;
  84. case MachO::X86_64_RELOC_SIGNED_2:
  85. if (RI.r_pcrel && RI.r_length == 2)
  86. return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon;
  87. break;
  88. case MachO::X86_64_RELOC_SIGNED_4:
  89. if (RI.r_pcrel && RI.r_length == 2)
  90. return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon;
  91. break;
  92. case MachO::X86_64_RELOC_TLV:
  93. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  94. return MachOPCRel32TLV;
  95. break;
  96. }
  97. return make_error<JITLinkError>(
  98. "Unsupported x86-64 relocation: address=" +
  99. formatv("{0:x8}", RI.r_address) +
  100. ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
  101. ", kind=" + formatv("{0:x1}", RI.r_type) +
  102. ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
  103. ", extern=" + (RI.r_extern ? "true" : "false") +
  104. ", length=" + formatv("{0:d}", RI.r_length));
  105. }
  106. using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
  107. // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
  108. // returns the edge kind and addend to be used.
  109. Expected<PairRelocInfo> parsePairRelocation(
  110. Block &BlockToFix, MachONormalizedRelocationType SubtractorKind,
  111. const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress,
  112. const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
  113. object::relocation_iterator &RelEnd) {
  114. using namespace support;
  115. assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) ||
  116. (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) &&
  117. "Subtractor kind should match length");
  118. assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
  119. assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
  120. if (UnsignedRelItr == RelEnd)
  121. return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
  122. "UNSIGNED relocation");
  123. auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
  124. if (SubRI.r_address != UnsignedRI.r_address)
  125. return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
  126. "point to different addresses");
  127. if (SubRI.r_length != UnsignedRI.r_length)
  128. return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
  129. "UNSIGNED reloc must match");
  130. Symbol *FromSymbol;
  131. if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
  132. FromSymbol = FromSymbolOrErr->GraphSymbol;
  133. else
  134. return FromSymbolOrErr.takeError();
  135. // Read the current fixup value.
  136. uint64_t FixupValue = 0;
  137. if (SubRI.r_length == 3)
  138. FixupValue = *(const little64_t *)FixupContent;
  139. else
  140. FixupValue = *(const little32_t *)FixupContent;
  141. // Find 'ToSymbol' using symbol number or address, depending on whether the
  142. // paired UNSIGNED relocation is extern.
  143. Symbol *ToSymbol = nullptr;
  144. if (UnsignedRI.r_extern) {
  145. // Find target symbol by symbol index.
  146. if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
  147. ToSymbol = ToSymbolOrErr->GraphSymbol;
  148. else
  149. return ToSymbolOrErr.takeError();
  150. } else {
  151. auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
  152. if (!ToSymbolSec)
  153. return ToSymbolSec.takeError();
  154. ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
  155. assert(ToSymbol && "No symbol for section");
  156. FixupValue -= ToSymbol->getAddress().getValue();
  157. }
  158. Edge::Kind DeltaKind;
  159. Symbol *TargetSymbol;
  160. uint64_t Addend;
  161. if (&BlockToFix == &FromSymbol->getAddressable()) {
  162. TargetSymbol = ToSymbol;
  163. DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32;
  164. Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
  165. // FIXME: handle extern 'from'.
  166. } else if (&BlockToFix == &ToSymbol->getAddressable()) {
  167. TargetSymbol = FromSymbol;
  168. DeltaKind =
  169. (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32;
  170. Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
  171. } else {
  172. // BlockToFix was neither FromSymbol nor ToSymbol.
  173. return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
  174. "either 'A' or 'B' (or a symbol in one "
  175. "of their alt-entry chains)");
  176. }
  177. return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
  178. }
  179. Error addRelocations() override {
  180. using namespace support;
  181. auto &Obj = getObject();
  182. LLVM_DEBUG(dbgs() << "Processing relocations:\n");
  183. for (auto &S : Obj.sections()) {
  184. orc::ExecutorAddr SectionAddress(S.getAddress());
  185. // Skip relocations virtual sections.
  186. if (S.isVirtual()) {
  187. if (S.relocation_begin() != S.relocation_end())
  188. return make_error<JITLinkError>("Virtual section contains "
  189. "relocations");
  190. continue;
  191. }
  192. auto NSec =
  193. findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
  194. if (!NSec)
  195. return NSec.takeError();
  196. // Skip relocations for MachO sections without corresponding graph
  197. // sections.
  198. {
  199. if (!NSec->GraphSection) {
  200. LLVM_DEBUG({
  201. dbgs() << " Skipping relocations for MachO section "
  202. << NSec->SegName << "/" << NSec->SectName
  203. << " which has no associated graph section\n";
  204. });
  205. continue;
  206. }
  207. }
  208. // Add relocations for section.
  209. for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
  210. RelItr != RelEnd; ++RelItr) {
  211. MachO::relocation_info RI = getRelocationInfo(RelItr);
  212. // Find the address of the value to fix up.
  213. auto FixupAddress = SectionAddress + (uint32_t)RI.r_address;
  214. LLVM_DEBUG({
  215. dbgs() << " " << NSec->SectName << " + "
  216. << formatv("{0:x8}", RI.r_address) << ":\n";
  217. });
  218. // Find the block that the fixup points to.
  219. Block *BlockToFix = nullptr;
  220. {
  221. auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
  222. if (!SymbolToFixOrErr)
  223. return SymbolToFixOrErr.takeError();
  224. BlockToFix = &SymbolToFixOrErr->getBlock();
  225. }
  226. if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
  227. BlockToFix->getAddress() + BlockToFix->getContent().size())
  228. return make_error<JITLinkError>(
  229. "Relocation extends past end of fixup block");
  230. // Get a pointer to the fixup content.
  231. const char *FixupContent = BlockToFix->getContent().data() +
  232. (FixupAddress - BlockToFix->getAddress());
  233. size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
  234. // The target symbol and addend will be populated by the switch below.
  235. Symbol *TargetSymbol = nullptr;
  236. uint64_t Addend = 0;
  237. // Validate the relocation kind.
  238. auto MachORelocKind = getRelocKind(RI);
  239. if (!MachORelocKind)
  240. return MachORelocKind.takeError();
  241. Edge::Kind Kind = Edge::Invalid;
  242. switch (*MachORelocKind) {
  243. case MachOBranch32:
  244. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  245. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  246. else
  247. return TargetSymbolOrErr.takeError();
  248. Addend = *(const little32_t *)FixupContent;
  249. Kind = x86_64::BranchPCRel32;
  250. break;
  251. case MachOPCRel32:
  252. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  253. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  254. else
  255. return TargetSymbolOrErr.takeError();
  256. Addend = *(const little32_t *)FixupContent - 4;
  257. Kind = x86_64::Delta32;
  258. break;
  259. case MachOPCRel32GOTLoad:
  260. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  261. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  262. else
  263. return TargetSymbolOrErr.takeError();
  264. Addend = *(const little32_t *)FixupContent;
  265. Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
  266. if (FixupOffset < 3)
  267. return make_error<JITLinkError>("GOTLD at invalid offset " +
  268. formatv("{0}", FixupOffset));
  269. break;
  270. case MachOPCRel32GOT:
  271. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  272. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  273. else
  274. return TargetSymbolOrErr.takeError();
  275. Addend = *(const little32_t *)FixupContent - 4;
  276. Kind = x86_64::RequestGOTAndTransformToDelta32;
  277. break;
  278. case MachOPCRel32TLV:
  279. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  280. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  281. else
  282. return TargetSymbolOrErr.takeError();
  283. Addend = *(const little32_t *)FixupContent;
  284. Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
  285. if (FixupOffset < 3)
  286. return make_error<JITLinkError>("TLV at invalid offset " +
  287. formatv("{0}", FixupOffset));
  288. break;
  289. case MachOPointer32:
  290. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  291. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  292. else
  293. return TargetSymbolOrErr.takeError();
  294. Addend = *(const ulittle32_t *)FixupContent;
  295. Kind = x86_64::Pointer32;
  296. break;
  297. case MachOPointer64:
  298. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  299. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  300. else
  301. return TargetSymbolOrErr.takeError();
  302. Addend = *(const ulittle64_t *)FixupContent;
  303. Kind = x86_64::Pointer64;
  304. break;
  305. case MachOPointer64Anon: {
  306. orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
  307. auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
  308. if (!TargetNSec)
  309. return TargetNSec.takeError();
  310. if (auto TargetSymbolOrErr =
  311. findSymbolByAddress(*TargetNSec, TargetAddress))
  312. TargetSymbol = &*TargetSymbolOrErr;
  313. else
  314. return TargetSymbolOrErr.takeError();
  315. Addend = TargetAddress - TargetSymbol->getAddress();
  316. Kind = x86_64::Pointer64;
  317. break;
  318. }
  319. case MachOPCRel32Minus1:
  320. case MachOPCRel32Minus2:
  321. case MachOPCRel32Minus4:
  322. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  323. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  324. else
  325. return TargetSymbolOrErr.takeError();
  326. Addend = *(const little32_t *)FixupContent - 4;
  327. Kind = x86_64::Delta32;
  328. break;
  329. case MachOPCRel32Anon: {
  330. orc::ExecutorAddr TargetAddress(FixupAddress + 4 +
  331. *(const little32_t *)FixupContent);
  332. auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
  333. if (!TargetNSec)
  334. return TargetNSec.takeError();
  335. if (auto TargetSymbolOrErr =
  336. findSymbolByAddress(*TargetNSec, TargetAddress))
  337. TargetSymbol = &*TargetSymbolOrErr;
  338. else
  339. return TargetSymbolOrErr.takeError();
  340. Addend = TargetAddress - TargetSymbol->getAddress() - 4;
  341. Kind = x86_64::Delta32;
  342. break;
  343. }
  344. case MachOPCRel32Minus1Anon:
  345. case MachOPCRel32Minus2Anon:
  346. case MachOPCRel32Minus4Anon: {
  347. orc::ExecutorAddrDiff Delta =
  348. 4 + orc::ExecutorAddrDiff(
  349. 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
  350. orc::ExecutorAddr TargetAddress =
  351. FixupAddress + Delta + *(const little32_t *)FixupContent;
  352. auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
  353. if (!TargetNSec)
  354. return TargetNSec.takeError();
  355. if (auto TargetSymbolOrErr =
  356. findSymbolByAddress(*TargetNSec, TargetAddress))
  357. TargetSymbol = &*TargetSymbolOrErr;
  358. else
  359. return TargetSymbolOrErr.takeError();
  360. Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
  361. Kind = x86_64::Delta32;
  362. break;
  363. }
  364. case MachOSubtractor32:
  365. case MachOSubtractor64: {
  366. // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
  367. // parsePairRelocation handles the paired reloc, and returns the
  368. // edge kind to be used (either Delta32/Delta64, or
  369. // NegDelta32/NegDelta64, depending on the direction of the
  370. // subtraction) along with the addend.
  371. auto PairInfo =
  372. parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
  373. FixupAddress, FixupContent, ++RelItr, RelEnd);
  374. if (!PairInfo)
  375. return PairInfo.takeError();
  376. std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
  377. assert(TargetSymbol && "No target symbol from parsePairRelocation?");
  378. break;
  379. }
  380. }
  381. LLVM_DEBUG({
  382. dbgs() << " ";
  383. Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
  384. Addend);
  385. printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
  386. dbgs() << "\n";
  387. });
  388. BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
  389. *TargetSymbol, Addend);
  390. }
  391. }
  392. return Error::success();
  393. }
  394. };
  395. Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
  396. x86_64::GOTTableManager GOT;
  397. x86_64::PLTTableManager PLT(GOT);
  398. visitExistingEdges(G, GOT, PLT);
  399. return Error::success();
  400. }
  401. } // namespace
  402. namespace llvm {
  403. namespace jitlink {
  404. class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
  405. friend class JITLinker<MachOJITLinker_x86_64>;
  406. public:
  407. MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
  408. std::unique_ptr<LinkGraph> G,
  409. PassConfiguration PassConfig)
  410. : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
  411. private:
  412. Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
  413. return x86_64::applyFixup(G, B, E, nullptr);
  414. }
  415. };
  416. Expected<std::unique_ptr<LinkGraph>>
  417. createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
  418. auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
  419. if (!MachOObj)
  420. return MachOObj.takeError();
  421. return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
  422. }
  423. void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
  424. std::unique_ptr<JITLinkContext> Ctx) {
  425. PassConfiguration Config;
  426. if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
  427. // Add eh-frame passses.
  428. Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
  429. Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
  430. // Add compact unwind splitter pass.
  431. Config.PrePrunePasses.push_back(
  432. CompactUnwindSplitter("__LD,__compact_unwind"));
  433. // Add a mark-live pass.
  434. if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
  435. Config.PrePrunePasses.push_back(std::move(MarkLive));
  436. else
  437. Config.PrePrunePasses.push_back(markAllSymbolsLive);
  438. // Add an in-place GOT/Stubs pass.
  439. Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
  440. // Add GOT/Stubs optimizer pass.
  441. Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
  442. }
  443. if (auto Err = Ctx->modifyPassConfig(*G, Config))
  444. return Ctx->notifyFailed(std::move(Err));
  445. // Construct a JITLinker and run the link function.
  446. MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
  447. }
  448. LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
  449. return EHFrameSplitter("__TEXT,__eh_frame");
  450. }
  451. LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
  452. return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
  453. x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
  454. }
  455. } // end namespace jitlink
  456. } // end namespace llvm