MachO_arm64.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. //===---- MachO_arm64.cpp - JIT linker implementation for MachO/arm64 -----===//
  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/arm64 jit-link implementation.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
  13. #include "MachOLinkGraphBuilder.h"
  14. #include "PerGraphGOTAndPLTStubsBuilder.h"
  15. #define DEBUG_TYPE "jitlink"
  16. using namespace llvm;
  17. using namespace llvm::jitlink;
  18. using namespace llvm::jitlink::MachO_arm64_Edges;
  19. namespace {
  20. class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
  21. public:
  22. MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj)
  23. : MachOLinkGraphBuilder(Obj, Triple("arm64-apple-darwin"),
  24. getMachOARM64RelocationKindName),
  25. NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
  26. private:
  27. static Expected<MachOARM64RelocationKind>
  28. getRelocationKind(const MachO::relocation_info &RI) {
  29. switch (RI.r_type) {
  30. case MachO::ARM64_RELOC_UNSIGNED:
  31. if (!RI.r_pcrel) {
  32. if (RI.r_length == 3)
  33. return RI.r_extern ? Pointer64 : Pointer64Anon;
  34. else if (RI.r_length == 2)
  35. return Pointer32;
  36. }
  37. break;
  38. case MachO::ARM64_RELOC_SUBTRACTOR:
  39. // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
  40. // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
  41. // They may be turned into NegDelta<W> by parsePairRelocation.
  42. if (!RI.r_pcrel && RI.r_extern) {
  43. if (RI.r_length == 2)
  44. return Delta32;
  45. else if (RI.r_length == 3)
  46. return Delta64;
  47. }
  48. break;
  49. case MachO::ARM64_RELOC_BRANCH26:
  50. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  51. return Branch26;
  52. break;
  53. case MachO::ARM64_RELOC_PAGE21:
  54. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  55. return Page21;
  56. break;
  57. case MachO::ARM64_RELOC_PAGEOFF12:
  58. if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  59. return PageOffset12;
  60. break;
  61. case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
  62. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  63. return GOTPage21;
  64. break;
  65. case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
  66. if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  67. return GOTPageOffset12;
  68. break;
  69. case MachO::ARM64_RELOC_POINTER_TO_GOT:
  70. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  71. return PointerToGOT;
  72. break;
  73. case MachO::ARM64_RELOC_ADDEND:
  74. if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
  75. return PairedAddend;
  76. break;
  77. case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
  78. if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  79. return TLVPage21;
  80. break;
  81. case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
  82. if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
  83. return TLVPageOffset12;
  84. break;
  85. }
  86. return make_error<JITLinkError>(
  87. "Unsupported arm64 relocation: address=" +
  88. formatv("{0:x8}", RI.r_address) +
  89. ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
  90. ", kind=" + formatv("{0:x1}", RI.r_type) +
  91. ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
  92. ", extern=" + (RI.r_extern ? "true" : "false") +
  93. ", length=" + formatv("{0:d}", RI.r_length));
  94. }
  95. using PairRelocInfo =
  96. std::tuple<MachOARM64RelocationKind, Symbol *, uint64_t>;
  97. // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
  98. // returns the edge kind and addend to be used.
  99. Expected<PairRelocInfo>
  100. parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
  101. const MachO::relocation_info &SubRI,
  102. orc::ExecutorAddr FixupAddress, const char *FixupContent,
  103. object::relocation_iterator &UnsignedRelItr,
  104. object::relocation_iterator &RelEnd) {
  105. using namespace support;
  106. assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
  107. (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
  108. "Subtractor kind should match length");
  109. assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
  110. assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
  111. if (UnsignedRelItr == RelEnd)
  112. return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
  113. "UNSIGNED relocation");
  114. auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
  115. if (SubRI.r_address != UnsignedRI.r_address)
  116. return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
  117. "point to different addresses");
  118. if (SubRI.r_length != UnsignedRI.r_length)
  119. return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
  120. "UNSIGNED reloc must match");
  121. Symbol *FromSymbol;
  122. if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
  123. FromSymbol = FromSymbolOrErr->GraphSymbol;
  124. else
  125. return FromSymbolOrErr.takeError();
  126. // Read the current fixup value.
  127. uint64_t FixupValue = 0;
  128. if (SubRI.r_length == 3)
  129. FixupValue = *(const little64_t *)FixupContent;
  130. else
  131. FixupValue = *(const little32_t *)FixupContent;
  132. // Find 'ToSymbol' using symbol number or address, depending on whether the
  133. // paired UNSIGNED relocation is extern.
  134. Symbol *ToSymbol = nullptr;
  135. if (UnsignedRI.r_extern) {
  136. // Find target symbol by symbol index.
  137. if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
  138. ToSymbol = ToSymbolOrErr->GraphSymbol;
  139. else
  140. return ToSymbolOrErr.takeError();
  141. } else {
  142. auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
  143. if (!ToSymbolSec)
  144. return ToSymbolSec.takeError();
  145. ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
  146. assert(ToSymbol && "No symbol for section");
  147. FixupValue -= ToSymbol->getAddress().getValue();
  148. }
  149. MachOARM64RelocationKind DeltaKind;
  150. Symbol *TargetSymbol;
  151. uint64_t Addend;
  152. if (&BlockToFix == &FromSymbol->getAddressable()) {
  153. TargetSymbol = ToSymbol;
  154. DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
  155. Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
  156. // FIXME: handle extern 'from'.
  157. } else if (&BlockToFix == &ToSymbol->getAddressable()) {
  158. TargetSymbol = &*FromSymbol;
  159. DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
  160. Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
  161. } else {
  162. // BlockToFix was neither FromSymbol nor ToSymbol.
  163. return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
  164. "either 'A' or 'B' (or a symbol in one "
  165. "of their alt-entry groups)");
  166. }
  167. return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
  168. }
  169. Error addRelocations() override {
  170. using namespace support;
  171. auto &Obj = getObject();
  172. LLVM_DEBUG(dbgs() << "Processing relocations:\n");
  173. for (auto &S : Obj.sections()) {
  174. orc::ExecutorAddr SectionAddress(S.getAddress());
  175. // Skip relocations virtual sections.
  176. if (S.isVirtual()) {
  177. if (S.relocation_begin() != S.relocation_end())
  178. return make_error<JITLinkError>("Virtual section contains "
  179. "relocations");
  180. continue;
  181. }
  182. auto NSec =
  183. findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
  184. if (!NSec)
  185. return NSec.takeError();
  186. // Skip relocations for MachO sections without corresponding graph
  187. // sections.
  188. {
  189. if (!NSec->GraphSection) {
  190. LLVM_DEBUG({
  191. dbgs() << " Skipping relocations for MachO section "
  192. << NSec->SegName << "/" << NSec->SectName
  193. << " which has no associated graph section\n";
  194. });
  195. continue;
  196. }
  197. }
  198. for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
  199. RelItr != RelEnd; ++RelItr) {
  200. MachO::relocation_info RI = getRelocationInfo(RelItr);
  201. // Validate the relocation kind.
  202. auto Kind = getRelocationKind(RI);
  203. if (!Kind)
  204. return Kind.takeError();
  205. // Find the address of the value to fix up.
  206. orc::ExecutorAddr FixupAddress =
  207. SectionAddress + (uint32_t)RI.r_address;
  208. LLVM_DEBUG({
  209. dbgs() << " " << NSec->SectName << " + "
  210. << formatv("{0:x8}", RI.r_address) << ":\n";
  211. });
  212. // Find the block that the fixup points to.
  213. Block *BlockToFix = nullptr;
  214. {
  215. auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
  216. if (!SymbolToFixOrErr)
  217. return SymbolToFixOrErr.takeError();
  218. BlockToFix = &SymbolToFixOrErr->getBlock();
  219. }
  220. if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
  221. BlockToFix->getAddress() + BlockToFix->getContent().size())
  222. return make_error<JITLinkError>(
  223. "Relocation content extends past end of fixup block");
  224. // Get a pointer to the fixup content.
  225. const char *FixupContent = BlockToFix->getContent().data() +
  226. (FixupAddress - BlockToFix->getAddress());
  227. // The target symbol and addend will be populated by the switch below.
  228. Symbol *TargetSymbol = nullptr;
  229. uint64_t Addend = 0;
  230. if (*Kind == PairedAddend) {
  231. // If this is an Addend relocation then process it and move to the
  232. // paired reloc.
  233. Addend = SignExtend64(RI.r_symbolnum, 24);
  234. if (RelItr == RelEnd)
  235. return make_error<JITLinkError>("Unpaired Addend reloc at " +
  236. formatv("{0:x16}", FixupAddress));
  237. ++RelItr;
  238. RI = getRelocationInfo(RelItr);
  239. Kind = getRelocationKind(RI);
  240. if (!Kind)
  241. return Kind.takeError();
  242. if (*Kind != Branch26 && *Kind != Page21 && *Kind != PageOffset12)
  243. return make_error<JITLinkError>(
  244. "Invalid relocation pair: Addend + " +
  245. StringRef(getMachOARM64RelocationKindName(*Kind)));
  246. LLVM_DEBUG({
  247. dbgs() << " Addend: value = " << formatv("{0:x6}", Addend)
  248. << ", pair is " << getMachOARM64RelocationKindName(*Kind)
  249. << "\n";
  250. });
  251. // Find the address of the value to fix up.
  252. orc::ExecutorAddr PairedFixupAddress =
  253. SectionAddress + (uint32_t)RI.r_address;
  254. if (PairedFixupAddress != FixupAddress)
  255. return make_error<JITLinkError>("Paired relocation points at "
  256. "different target");
  257. }
  258. switch (*Kind) {
  259. case Branch26: {
  260. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  261. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  262. else
  263. return TargetSymbolOrErr.takeError();
  264. uint32_t Instr = *(const ulittle32_t *)FixupContent;
  265. if ((Instr & 0x7fffffff) != 0x14000000)
  266. return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
  267. "instruction with a zero addend");
  268. break;
  269. }
  270. case Pointer32:
  271. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  272. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  273. else
  274. return TargetSymbolOrErr.takeError();
  275. Addend = *(const ulittle32_t *)FixupContent;
  276. break;
  277. case Pointer64:
  278. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  279. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  280. else
  281. return TargetSymbolOrErr.takeError();
  282. Addend = *(const ulittle64_t *)FixupContent;
  283. break;
  284. case Pointer64Anon: {
  285. orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
  286. auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
  287. if (!TargetNSec)
  288. return TargetNSec.takeError();
  289. if (auto TargetSymbolOrErr =
  290. findSymbolByAddress(*TargetNSec, TargetAddress))
  291. TargetSymbol = &*TargetSymbolOrErr;
  292. else
  293. return TargetSymbolOrErr.takeError();
  294. Addend = TargetAddress - TargetSymbol->getAddress();
  295. break;
  296. }
  297. case Page21:
  298. case TLVPage21:
  299. case GOTPage21: {
  300. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  301. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  302. else
  303. return TargetSymbolOrErr.takeError();
  304. uint32_t Instr = *(const ulittle32_t *)FixupContent;
  305. if ((Instr & 0xffffffe0) != 0x90000000)
  306. return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
  307. "ADRP instruction with a zero "
  308. "addend");
  309. break;
  310. }
  311. case PageOffset12: {
  312. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  313. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  314. else
  315. return TargetSymbolOrErr.takeError();
  316. uint32_t Instr = *(const ulittle32_t *)FixupContent;
  317. uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10;
  318. if (EncodedAddend != 0)
  319. return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero "
  320. "encoded addend");
  321. break;
  322. }
  323. case TLVPageOffset12:
  324. case GOTPageOffset12: {
  325. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  326. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  327. else
  328. return TargetSymbolOrErr.takeError();
  329. uint32_t Instr = *(const ulittle32_t *)FixupContent;
  330. if ((Instr & 0xfffffc00) != 0xf9400000)
  331. return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
  332. "immediate instruction with a zero "
  333. "addend");
  334. break;
  335. }
  336. case PointerToGOT:
  337. if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
  338. TargetSymbol = TargetSymbolOrErr->GraphSymbol;
  339. else
  340. return TargetSymbolOrErr.takeError();
  341. break;
  342. case Delta32:
  343. case Delta64: {
  344. // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
  345. // parsePairRelocation handles the paired reloc, and returns the
  346. // edge kind to be used (either Delta32/Delta64, or
  347. // NegDelta32/NegDelta64, depending on the direction of the
  348. // subtraction) along with the addend.
  349. auto PairInfo =
  350. parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
  351. FixupContent, ++RelItr, RelEnd);
  352. if (!PairInfo)
  353. return PairInfo.takeError();
  354. std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
  355. assert(TargetSymbol && "No target symbol from parsePairRelocation?");
  356. break;
  357. }
  358. default:
  359. llvm_unreachable("Special relocation kind should not appear in "
  360. "mach-o file");
  361. }
  362. LLVM_DEBUG({
  363. dbgs() << " ";
  364. Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
  365. Addend);
  366. printEdge(dbgs(), *BlockToFix, GE,
  367. getMachOARM64RelocationKindName(*Kind));
  368. dbgs() << "\n";
  369. });
  370. BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
  371. *TargetSymbol, Addend);
  372. }
  373. }
  374. return Error::success();
  375. }
  376. unsigned NumSymbols = 0;
  377. };
  378. class PerGraphGOTAndPLTStubsBuilder_MachO_arm64
  379. : public PerGraphGOTAndPLTStubsBuilder<
  380. PerGraphGOTAndPLTStubsBuilder_MachO_arm64> {
  381. public:
  382. using PerGraphGOTAndPLTStubsBuilder<
  383. PerGraphGOTAndPLTStubsBuilder_MachO_arm64>::PerGraphGOTAndPLTStubsBuilder;
  384. bool isGOTEdgeToFix(Edge &E) const {
  385. return E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
  386. E.getKind() == TLVPage21 || E.getKind() == TLVPageOffset12 ||
  387. E.getKind() == PointerToGOT;
  388. }
  389. Symbol &createGOTEntry(Symbol &Target) {
  390. auto &GOTEntryBlock = G.createContentBlock(
  391. getGOTSection(), getGOTEntryBlockContent(), orc::ExecutorAddr(), 8, 0);
  392. GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
  393. return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
  394. }
  395. void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
  396. if (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
  397. E.getKind() == TLVPage21 || E.getKind() == TLVPageOffset12) {
  398. // Update the target, but leave the edge addend as-is.
  399. E.setTarget(GOTEntry);
  400. } else if (E.getKind() == PointerToGOT) {
  401. E.setTarget(GOTEntry);
  402. E.setKind(Delta32);
  403. } else
  404. llvm_unreachable("Not a GOT edge?");
  405. }
  406. bool isExternalBranchEdge(Edge &E) {
  407. return E.getKind() == Branch26 && !E.getTarget().isDefined();
  408. }
  409. Symbol &createPLTStub(Symbol &Target) {
  410. auto &StubContentBlock = G.createContentBlock(
  411. getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 1, 0);
  412. // Re-use GOT entries for stub targets.
  413. auto &GOTEntrySymbol = getGOTEntry(Target);
  414. StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0);
  415. return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false);
  416. }
  417. void fixPLTEdge(Edge &E, Symbol &Stub) {
  418. assert(E.getKind() == Branch26 && "Not a Branch32 edge?");
  419. assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
  420. E.setTarget(Stub);
  421. }
  422. private:
  423. Section &getGOTSection() {
  424. if (!GOTSection)
  425. GOTSection = &G.createSection("$__GOT", MemProt::Read | MemProt::Exec);
  426. return *GOTSection;
  427. }
  428. Section &getStubsSection() {
  429. if (!StubsSection)
  430. StubsSection =
  431. &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
  432. return *StubsSection;
  433. }
  434. ArrayRef<char> getGOTEntryBlockContent() {
  435. return {reinterpret_cast<const char *>(NullGOTEntryContent),
  436. sizeof(NullGOTEntryContent)};
  437. }
  438. ArrayRef<char> getStubBlockContent() {
  439. return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
  440. }
  441. static const uint8_t NullGOTEntryContent[8];
  442. static const uint8_t StubContent[8];
  443. Section *GOTSection = nullptr;
  444. Section *StubsSection = nullptr;
  445. };
  446. const uint8_t
  447. PerGraphGOTAndPLTStubsBuilder_MachO_arm64::NullGOTEntryContent[8] = {
  448. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  449. const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = {
  450. 0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
  451. 0x00, 0x02, 0x1f, 0xd6 // BR x16
  452. };
  453. } // namespace
  454. namespace llvm {
  455. namespace jitlink {
  456. class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
  457. friend class JITLinker<MachOJITLinker_arm64>;
  458. public:
  459. MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
  460. std::unique_ptr<LinkGraph> G,
  461. PassConfiguration PassConfig)
  462. : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
  463. private:
  464. static unsigned getPageOffset12Shift(uint32_t Instr) {
  465. constexpr uint32_t LoadStoreImm12Mask = 0x3b000000;
  466. constexpr uint32_t Vec128Mask = 0x04800000;
  467. if ((Instr & LoadStoreImm12Mask) == 0x39000000) {
  468. uint32_t ImplicitShift = Instr >> 30;
  469. if (ImplicitShift == 0)
  470. if ((Instr & Vec128Mask) == Vec128Mask)
  471. ImplicitShift = 4;
  472. return ImplicitShift;
  473. }
  474. return 0;
  475. }
  476. Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
  477. using namespace support;
  478. char *BlockWorkingMem = B.getAlreadyMutableContent().data();
  479. char *FixupPtr = BlockWorkingMem + E.getOffset();
  480. orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
  481. switch (E.getKind()) {
  482. case Branch26: {
  483. assert((FixupAddress.getValue() & 0x3) == 0 &&
  484. "Branch-inst is not 32-bit aligned");
  485. int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  486. if (static_cast<uint64_t>(Value) & 0x3)
  487. return make_error<JITLinkError>("Branch26 target is not 32-bit "
  488. "aligned");
  489. if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
  490. return makeTargetOutOfRangeError(G, B, E);
  491. uint32_t RawInstr = *(little32_t *)FixupPtr;
  492. assert((RawInstr & 0x7fffffff) == 0x14000000 &&
  493. "RawInstr isn't a B or BR immediate instruction");
  494. uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
  495. uint32_t FixedInstr = RawInstr | Imm;
  496. *(little32_t *)FixupPtr = FixedInstr;
  497. break;
  498. }
  499. case Pointer32: {
  500. uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  501. if (Value > std::numeric_limits<uint32_t>::max())
  502. return makeTargetOutOfRangeError(G, B, E);
  503. *(ulittle32_t *)FixupPtr = Value;
  504. break;
  505. }
  506. case Pointer64:
  507. case Pointer64Anon: {
  508. uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  509. *(ulittle64_t *)FixupPtr = Value;
  510. break;
  511. }
  512. case Page21:
  513. case TLVPage21:
  514. case GOTPage21: {
  515. assert((E.getKind() != GOTPage21 || E.getAddend() == 0) &&
  516. "GOTPAGE21 with non-zero addend");
  517. uint64_t TargetPage =
  518. (E.getTarget().getAddress().getValue() + E.getAddend()) &
  519. ~static_cast<uint64_t>(4096 - 1);
  520. uint64_t PCPage =
  521. FixupAddress.getValue() & ~static_cast<uint64_t>(4096 - 1);
  522. int64_t PageDelta = TargetPage - PCPage;
  523. if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1))
  524. return makeTargetOutOfRangeError(G, B, E);
  525. uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
  526. assert((RawInstr & 0xffffffe0) == 0x90000000 &&
  527. "RawInstr isn't an ADRP instruction");
  528. uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
  529. uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
  530. uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
  531. *(ulittle32_t *)FixupPtr = FixedInstr;
  532. break;
  533. }
  534. case PageOffset12: {
  535. uint64_t TargetOffset =
  536. (E.getTarget().getAddress() + E.getAddend()).getValue() & 0xfff;
  537. uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
  538. unsigned ImmShift = getPageOffset12Shift(RawInstr);
  539. if (TargetOffset & ((1 << ImmShift) - 1))
  540. return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
  541. uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
  542. uint32_t FixedInstr = RawInstr | EncodedImm;
  543. *(ulittle32_t *)FixupPtr = FixedInstr;
  544. break;
  545. }
  546. case TLVPageOffset12:
  547. case GOTPageOffset12: {
  548. assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
  549. uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
  550. assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
  551. "RawInstr isn't a 64-bit LDR immediate");
  552. uint32_t TargetOffset = E.getTarget().getAddress().getValue() & 0xfff;
  553. assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned");
  554. uint32_t EncodedImm = (TargetOffset >> 3) << 10;
  555. uint32_t FixedInstr = RawInstr | EncodedImm;
  556. *(ulittle32_t *)FixupPtr = FixedInstr;
  557. break;
  558. }
  559. case LDRLiteral19: {
  560. assert((FixupAddress.getValue() & 0x3) == 0 &&
  561. "LDR is not 32-bit aligned");
  562. assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
  563. uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
  564. assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
  565. int64_t Delta = E.getTarget().getAddress() - FixupAddress;
  566. if (Delta & 0x3)
  567. return make_error<JITLinkError>("LDR literal target is not 32-bit "
  568. "aligned");
  569. if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
  570. return makeTargetOutOfRangeError(G, B, E);
  571. uint32_t EncodedImm =
  572. ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5;
  573. uint32_t FixedInstr = RawInstr | EncodedImm;
  574. *(ulittle32_t *)FixupPtr = FixedInstr;
  575. break;
  576. }
  577. case Delta32:
  578. case Delta64:
  579. case NegDelta32:
  580. case NegDelta64: {
  581. int64_t Value;
  582. if (E.getKind() == Delta32 || E.getKind() == Delta64)
  583. Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  584. else
  585. Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
  586. if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
  587. if (Value < std::numeric_limits<int32_t>::min() ||
  588. Value > std::numeric_limits<int32_t>::max())
  589. return makeTargetOutOfRangeError(G, B, E);
  590. *(little32_t *)FixupPtr = Value;
  591. } else
  592. *(little64_t *)FixupPtr = Value;
  593. break;
  594. }
  595. default:
  596. llvm_unreachable("Unrecognized edge kind");
  597. }
  598. return Error::success();
  599. }
  600. uint64_t NullValue = 0;
  601. };
  602. Expected<std::unique_ptr<LinkGraph>>
  603. createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer) {
  604. auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
  605. if (!MachOObj)
  606. return MachOObj.takeError();
  607. return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
  608. }
  609. void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
  610. std::unique_ptr<JITLinkContext> Ctx) {
  611. PassConfiguration Config;
  612. if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
  613. // Add a mark-live pass.
  614. if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
  615. Config.PrePrunePasses.push_back(std::move(MarkLive));
  616. else
  617. Config.PrePrunePasses.push_back(markAllSymbolsLive);
  618. // Add compact unwind splitter pass.
  619. Config.PrePrunePasses.push_back(
  620. CompactUnwindSplitter("__LD,__compact_unwind"));
  621. // Add eh-frame passses.
  622. // FIXME: Prune eh-frames for which compact-unwind is available once
  623. // we support compact-unwind registration with libunwind.
  624. Config.PrePrunePasses.push_back(EHFrameSplitter("__TEXT,__eh_frame"));
  625. Config.PrePrunePasses.push_back(
  626. EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Delta64, Delta32, NegDelta32));
  627. // Add an in-place GOT/Stubs pass.
  628. Config.PostPrunePasses.push_back(
  629. PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass);
  630. }
  631. if (auto Err = Ctx->modifyPassConfig(*G, Config))
  632. return Ctx->notifyFailed(std::move(Err));
  633. // Construct a JITLinker and run the link function.
  634. MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
  635. }
  636. const char *getMachOARM64RelocationKindName(Edge::Kind R) {
  637. switch (R) {
  638. case Branch26:
  639. return "Branch26";
  640. case Pointer64:
  641. return "Pointer64";
  642. case Pointer64Anon:
  643. return "Pointer64Anon";
  644. case Page21:
  645. return "Page21";
  646. case PageOffset12:
  647. return "PageOffset12";
  648. case GOTPage21:
  649. return "GOTPage21";
  650. case GOTPageOffset12:
  651. return "GOTPageOffset12";
  652. case TLVPage21:
  653. return "TLVPage21";
  654. case TLVPageOffset12:
  655. return "TLVPageOffset12";
  656. case PointerToGOT:
  657. return "PointerToGOT";
  658. case PairedAddend:
  659. return "PairedAddend";
  660. case LDRLiteral19:
  661. return "LDRLiteral19";
  662. case Delta32:
  663. return "Delta32";
  664. case Delta64:
  665. return "Delta64";
  666. case NegDelta32:
  667. return "NegDelta32";
  668. case NegDelta64:
  669. return "NegDelta64";
  670. default:
  671. return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
  672. }
  673. }
  674. } // end namespace jitlink
  675. } // end namespace llvm