x86_64.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- x86_64.h - Generic JITLink x86-64 edge kinds, utilities -*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Generic utilities for graphs representing x86-64 objects.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
  18. #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
  19. #include "llvm/ExecutionEngine/JITLink/JITLink.h"
  20. #include "llvm/ExecutionEngine/JITLink/TableManager.h"
  21. #include <limits>
  22. namespace llvm {
  23. namespace jitlink {
  24. namespace x86_64 {
  25. /// Represents x86-64 fixups and other x86-64-specific edge kinds.
  26. enum EdgeKind_x86_64 : Edge::Kind {
  27. /// A plain 64-bit pointer value relocation.
  28. ///
  29. /// Fixup expression:
  30. /// Fixup <- Target + Addend : uint64
  31. ///
  32. Pointer64 = Edge::FirstRelocation,
  33. /// A plain 32-bit pointer value relocation.
  34. ///
  35. /// Fixup expression:
  36. /// Fixup <- Target + Addend : uint32
  37. ///
  38. /// Errors:
  39. /// - The target must reside in the low 32-bits of the address space,
  40. /// otherwise an out-of-range error will be returned.
  41. ///
  42. Pointer32,
  43. /// A signed 32-bit pointer value relocation
  44. ///
  45. /// Fixup expression:
  46. /// Fixup <- Target + Addend : int32
  47. ///
  48. /// Errors:
  49. /// - The target must reside in the signed 32-bits([-2**31, 2**32 - 1]) of
  50. /// the address space, otherwise an out-of-range error will be returned.
  51. Pointer32Signed,
  52. /// A 64-bit delta.
  53. ///
  54. /// Delta from the fixup to the target.
  55. ///
  56. /// Fixup expression:
  57. /// Fixup <- Target - Fixup + Addend : int64
  58. ///
  59. Delta64,
  60. /// A 32-bit delta.
  61. ///
  62. /// Delta from the fixup to the target.
  63. ///
  64. /// Fixup expression:
  65. /// Fixup <- Target - Fixup + Addend : int64
  66. ///
  67. /// Errors:
  68. /// - The result of the fixup expression must fit into an int32, otherwise
  69. /// an out-of-range error will be returned.
  70. ///
  71. Delta32,
  72. /// A 64-bit negative delta.
  73. ///
  74. /// Delta from target back to the fixup.
  75. ///
  76. /// Fixup expression:
  77. /// Fixup <- Fixup - Target + Addend : int64
  78. ///
  79. NegDelta64,
  80. /// A 32-bit negative delta.
  81. ///
  82. /// Delta from the target back to the fixup.
  83. ///
  84. /// Fixup expression:
  85. /// Fixup <- Fixup - Target + Addend : int32
  86. ///
  87. /// Errors:
  88. /// - The result of the fixup expression must fit into an int32, otherwise
  89. /// an out-of-range error will be returned.
  90. NegDelta32,
  91. /// A 64-bit GOT delta.
  92. ///
  93. /// Delta from the global offset table to the target
  94. ///
  95. /// Fixup expression:
  96. /// Fixup <- Target - GOTSymbol + Addend : int64
  97. ///
  98. /// Errors:
  99. /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section
  100. /// symbol was not been defined.
  101. Delta64FromGOT,
  102. /// A 32-bit PC-relative branch.
  103. ///
  104. /// Represents a PC-relative call or branch to a target. This can be used to
  105. /// identify, record, and/or patch call sites.
  106. ///
  107. /// The fixup expression for this kind includes an implicit offset to account
  108. /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target
  109. /// T and addend zero is a call/branch to the start (offset zero) of T.
  110. ///
  111. /// Fixup expression:
  112. /// Fixup <- Target - (Fixup + 4) + Addend : int32
  113. ///
  114. /// Errors:
  115. /// - The result of the fixup expression must fit into an int32, otherwise
  116. /// an out-of-range error will be returned.
  117. ///
  118. BranchPCRel32,
  119. /// A 32-bit PC-relative branch to a pointer jump stub.
  120. ///
  121. /// The target of this relocation should be a pointer jump stub of the form:
  122. ///
  123. /// \code{.s}
  124. /// .text
  125. /// jmpq *tgtptr(%rip)
  126. /// ; ...
  127. ///
  128. /// .data
  129. /// tgtptr:
  130. /// .quad 0
  131. /// \endcode
  132. ///
  133. /// This edge kind has the same fixup expression as BranchPCRel32, but further
  134. /// identifies the call/branch as being to a pointer jump stub. For edges of
  135. /// this kind the jump stub should not be bypassed (use
  136. /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location
  137. /// target may be recorded to allow manipulation at runtime.
  138. ///
  139. /// Fixup expression:
  140. /// Fixup <- Target - Fixup + Addend - 4 : int32
  141. ///
  142. /// Errors:
  143. /// - The result of the fixup expression must fit into an int32, otherwise
  144. /// an out-of-range error will be returned.
  145. ///
  146. BranchPCRel32ToPtrJumpStub,
  147. /// A relaxable version of BranchPCRel32ToPtrJumpStub.
  148. ///
  149. /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub,
  150. /// but identifies the call/branch as being to a pointer jump stub that may be
  151. /// bypassed with a direct jump to the ultimate target if the ultimate target
  152. /// is within range of the fixup location.
  153. ///
  154. /// Fixup expression:
  155. /// Fixup <- Target - Fixup + Addend - 4: int32
  156. ///
  157. /// Errors:
  158. /// - The result of the fixup expression must fit into an int32, otherwise
  159. /// an out-of-range error will be returned.
  160. ///
  161. BranchPCRel32ToPtrJumpStubBypassable,
  162. /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT
  163. /// entry for the original target.
  164. ///
  165. /// Indicates that this edge should be transformed into a Delta32 targeting
  166. /// the GOT entry for the edge's current target, maintaining the same addend.
  167. /// A GOT entry for the target should be created if one does not already
  168. /// exist.
  169. ///
  170. /// Edges of this kind are usually handled by a GOT builder pass inserted by
  171. /// default.
  172. ///
  173. /// Fixup expression:
  174. /// NONE
  175. ///
  176. /// Errors:
  177. /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  178. /// phase will result in an assert/unreachable during the fixup phase.
  179. ///
  180. RequestGOTAndTransformToDelta32,
  181. /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT
  182. /// entry for the original target.
  183. ///
  184. /// Indicates that this edge should be transformed into a Delta64 targeting
  185. /// the GOT entry for the edge's current target, maintaining the same addend.
  186. /// A GOT entry for the target should be created if one does not already
  187. /// exist.
  188. ///
  189. /// Edges of this kind are usually handled by a GOT builder pass inserted by
  190. /// default.
  191. ///
  192. /// Fixup expression:
  193. /// NONE
  194. ///
  195. /// Errors:
  196. /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  197. /// phase will result in an assert/unreachable during the fixup phase.
  198. ///
  199. RequestGOTAndTransformToDelta64,
  200. /// A GOT entry offset within GOT getter/constructor, transformed to
  201. /// Delta64FromGOT
  202. /// pointing at the GOT entry for the original target
  203. ///
  204. /// Indicates that this edge should be transformed into a Delta64FromGOT
  205. /// targeting
  206. /// the GOT entry for the edge's current target, maintaining the same addend.
  207. /// A GOT entry for the target should be created if one does not already
  208. /// exist.
  209. ///
  210. /// Edges of this kind are usually handled by a GOT builder pass inserted by
  211. /// default
  212. ///
  213. /// Fixup expression:
  214. /// NONE
  215. ///
  216. /// Errors:
  217. /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  218. /// phase will result in an assert/unreachable during the fixup phase
  219. RequestGOTAndTransformToDelta64FromGOT,
  220. /// A PC-relative load of a GOT entry, relaxable if GOT entry target is
  221. /// in-range of the fixup
  222. ///
  223. /// TODO: Explain the optimization
  224. ///
  225. /// Fixup expression
  226. /// Fixup <- Target - (Fixup + 4) + Addend : int32
  227. ///
  228. /// Errors:
  229. /// - The result of the fixup expression must fit into an int32, otherwise
  230. /// an out-of-range error will be returned.
  231. //
  232. PCRel32GOTLoadRelaxable,
  233. /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target
  234. /// is in-range of the fixup.
  235. ///
  236. /// If the GOT entry target is in-range of the fixup then the load from the
  237. /// GOT may be replaced with a direct memory address calculation.
  238. ///
  239. /// Fixup expression:
  240. /// Fixup <- Target - (Fixup + 4) + Addend : int32
  241. ///
  242. /// Errors:
  243. /// - The result of the fixup expression must fit into an int32, otherwise
  244. /// an out-of-range error will be returned.
  245. ///
  246. PCRel32GOTLoadREXRelaxable,
  247. /// A GOT entry getter/constructor, transformed to
  248. /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original
  249. /// target.
  250. ///
  251. /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable
  252. /// targeting the GOT entry for the edge's current target, maintaining the
  253. /// same addend. A GOT entry for the target should be created if one does not
  254. /// already exist.
  255. ///
  256. /// Edges of this kind are usually lowered by a GOT builder pass inserted by
  257. /// default.
  258. ///
  259. /// Fixup expression:
  260. /// NONE
  261. ///
  262. /// Errors:
  263. /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  264. /// phase will result in an assert/unreachable during the fixup phase.
  265. ///
  266. RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable,
  267. /// A GOT entry getter/constructor, transformed to
  268. /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original
  269. /// target.
  270. ///
  271. /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable
  272. /// targeting the GOT entry for the edge's current target, maintaining the
  273. /// same addend. A GOT entry for the target should be created if one does not
  274. /// already exist.
  275. ///
  276. /// Edges of this kind are usually lowered by a GOT builder pass inserted by
  277. /// default.
  278. ///
  279. /// Fixup expression:
  280. /// NONE
  281. ///
  282. /// Errors:
  283. /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  284. /// phase will result in an assert/unreachable during the fixup phase.
  285. ///
  286. RequestGOTAndTransformToPCRel32GOTLoadRelaxable,
  287. /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry,
  288. /// relaxable if the TLVP entry target is in-range of the fixup.
  289. ///
  290. /// If the TLVP entry target is in-range of the fixup then the load from the
  291. /// TLVP may be replaced with a direct memory address calculation.
  292. ///
  293. /// The target of this edge must be a thread local variable entry of the form
  294. /// .quad <tlv getter thunk>
  295. /// .quad <tlv key>
  296. /// .quad <tlv initializer>
  297. ///
  298. /// Fixup expression:
  299. /// Fixup <- Target - (Fixup + 4) + Addend : int32
  300. ///
  301. /// Errors:
  302. /// - The result of the fixup expression must fit into an int32, otherwise
  303. /// an out-of-range error will be returned.
  304. /// - The target must be either external, or a TLV entry of the required
  305. /// form, otherwise a malformed TLV entry error will be returned.
  306. ///
  307. PCRel32TLVPLoadREXRelaxable,
  308. /// TODO: Explain the generic edge kind
  309. RequestTLSDescInGOTAndTransformToDelta32,
  310. /// A TLVP entry getter/constructor, transformed to
  311. /// Delta32ToTLVPLoadREXRelaxable.
  312. ///
  313. /// Indicates that this edge should be transformed into a
  314. /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's
  315. /// current target. A TLVP entry for the target should be created if one does
  316. /// not already exist.
  317. ///
  318. /// Fixup expression:
  319. /// NONE
  320. ///
  321. /// Errors:
  322. /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup
  323. /// phase will result in an assert/unreachable during the fixup phase.
  324. ///
  325. RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
  326. };
  327. /// Returns a string name for the given x86-64 edge. For debugging purposes
  328. /// only.
  329. const char *getEdgeKindName(Edge::Kind K);
  330. /// Returns true if the given uint64_t value is in range for a uint32_t.
  331. inline bool isInRangeForImmU32(uint64_t Value) {
  332. return Value <= std::numeric_limits<uint32_t>::max();
  333. }
  334. /// Returns true if the given int64_t value is in range for an int32_t.
  335. inline bool isInRangeForImmS32(int64_t Value) {
  336. return (Value >= std::numeric_limits<int32_t>::min() &&
  337. Value <= std::numeric_limits<int32_t>::max());
  338. }
  339. /// Apply fixup expression for edge to block content.
  340. inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
  341. const Symbol *GOTSymbol) {
  342. using namespace support;
  343. char *BlockWorkingMem = B.getAlreadyMutableContent().data();
  344. char *FixupPtr = BlockWorkingMem + E.getOffset();
  345. auto FixupAddress = B.getAddress() + E.getOffset();
  346. switch (E.getKind()) {
  347. case Pointer64: {
  348. uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  349. *(ulittle64_t *)FixupPtr = Value;
  350. break;
  351. }
  352. case Pointer32: {
  353. uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  354. if (LLVM_LIKELY(isInRangeForImmU32(Value)))
  355. *(ulittle32_t *)FixupPtr = Value;
  356. else
  357. return makeTargetOutOfRangeError(G, B, E);
  358. break;
  359. }
  360. case Pointer32Signed: {
  361. int64_t Value = E.getTarget().getAddress().getValue() + E.getAddend();
  362. if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  363. *(little32_t *)FixupPtr = Value;
  364. else
  365. return makeTargetOutOfRangeError(G, B, E);
  366. break;
  367. }
  368. case BranchPCRel32:
  369. case BranchPCRel32ToPtrJumpStub:
  370. case BranchPCRel32ToPtrJumpStubBypassable:
  371. case PCRel32GOTLoadRelaxable:
  372. case PCRel32GOTLoadREXRelaxable:
  373. case PCRel32TLVPLoadREXRelaxable: {
  374. int64_t Value =
  375. E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
  376. if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  377. *(little32_t *)FixupPtr = Value;
  378. else
  379. return makeTargetOutOfRangeError(G, B, E);
  380. break;
  381. }
  382. case Delta64: {
  383. int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  384. *(little64_t *)FixupPtr = Value;
  385. break;
  386. }
  387. case Delta32: {
  388. int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  389. if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  390. *(little32_t *)FixupPtr = Value;
  391. else
  392. return makeTargetOutOfRangeError(G, B, E);
  393. break;
  394. }
  395. case NegDelta64: {
  396. int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
  397. *(little64_t *)FixupPtr = Value;
  398. break;
  399. }
  400. case NegDelta32: {
  401. int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
  402. if (LLVM_LIKELY(isInRangeForImmS32(Value)))
  403. *(little32_t *)FixupPtr = Value;
  404. else
  405. return makeTargetOutOfRangeError(G, B, E);
  406. break;
  407. }
  408. case Delta64FromGOT: {
  409. assert(GOTSymbol && "No GOT section symbol");
  410. int64_t Value =
  411. E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend();
  412. *(little64_t *)FixupPtr = Value;
  413. break;
  414. }
  415. default: {
  416. // If you hit this you should check that *constructor and other non-fixup
  417. // edges have been removed prior to applying fixups.
  418. llvm_unreachable("Graph contains edge kind with no fixup expression");
  419. }
  420. }
  421. return Error::success();
  422. }
  423. /// x86_64 pointer size.
  424. constexpr uint64_t PointerSize = 8;
  425. /// x86-64 null pointer content.
  426. extern const char NullPointerContent[PointerSize];
  427. /// x86-64 pointer jump stub content.
  428. ///
  429. /// Contains the instruction sequence for an indirect jump via an in-memory
  430. /// pointer:
  431. /// jmpq *ptr(%rip)
  432. extern const char PointerJumpStubContent[6];
  433. /// Creates a new pointer block in the given section and returns an anonymous
  434. /// symbol pointing to it.
  435. ///
  436. /// If InitialTarget is given then an Pointer64 relocation will be added to the
  437. /// block pointing at InitialTarget.
  438. ///
  439. /// The pointer block will have the following default values:
  440. /// alignment: 64-bit
  441. /// alignment-offset: 0
  442. /// address: highest allowable (~7U)
  443. inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
  444. Symbol *InitialTarget = nullptr,
  445. uint64_t InitialAddend = 0) {
  446. auto &B = G.createContentBlock(PointerSection, NullPointerContent,
  447. orc::ExecutorAddr(~uint64_t(7)), 8, 0);
  448. if (InitialTarget)
  449. B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend);
  450. return G.addAnonymousSymbol(B, 0, 8, false, false);
  451. }
  452. /// Create a jump stub block that jumps via the pointer at the given symbol.
  453. ///
  454. /// The stub block will have the following default values:
  455. /// alignment: 8-bit
  456. /// alignment-offset: 0
  457. /// address: highest allowable: (~5U)
  458. inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection,
  459. Symbol &PointerSymbol) {
  460. auto &B = G.createContentBlock(StubSection, PointerJumpStubContent,
  461. orc::ExecutorAddr(~uint64_t(5)), 1, 0);
  462. B.addEdge(Delta32, 2, PointerSymbol, -4);
  463. return B;
  464. }
  465. /// Create a jump stub that jumps via the pointer at the given symbol and
  466. /// an anonymous symbol pointing to it. Return the anonymous symbol.
  467. ///
  468. /// The stub block will be created by createPointerJumpStubBlock.
  469. inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
  470. Section &StubSection,
  471. Symbol &PointerSymbol) {
  472. return G.addAnonymousSymbol(
  473. createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true,
  474. false);
  475. }
  476. /// Global Offset Table Builder.
  477. class GOTTableManager : public TableManager<GOTTableManager> {
  478. public:
  479. static StringRef getSectionName() { return "$__GOT"; }
  480. bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
  481. Edge::Kind KindToSet = Edge::Invalid;
  482. switch (E.getKind()) {
  483. case x86_64::Delta64FromGOT: {
  484. // we need to make sure that the GOT section exists, but don't otherwise
  485. // need to fix up this edge
  486. getGOTSection(G);
  487. return false;
  488. }
  489. case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
  490. KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
  491. break;
  492. case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
  493. KindToSet = x86_64::PCRel32GOTLoadRelaxable;
  494. break;
  495. case x86_64::RequestGOTAndTransformToDelta64:
  496. KindToSet = x86_64::Delta64;
  497. break;
  498. case x86_64::RequestGOTAndTransformToDelta64FromGOT:
  499. KindToSet = x86_64::Delta64FromGOT;
  500. break;
  501. case x86_64::RequestGOTAndTransformToDelta32:
  502. KindToSet = x86_64::Delta32;
  503. break;
  504. default:
  505. return false;
  506. }
  507. assert(KindToSet != Edge::Invalid &&
  508. "Fell through switch, but no new kind to set");
  509. DEBUG_WITH_TYPE("jitlink", {
  510. dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
  511. << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
  512. << formatv("{0:x}", E.getOffset()) << ")\n";
  513. });
  514. E.setKind(KindToSet);
  515. E.setTarget(getEntryForTarget(G, E.getTarget()));
  516. return true;
  517. }
  518. Symbol &createEntry(LinkGraph &G, Symbol &Target) {
  519. return createAnonymousPointer(G, getGOTSection(G), &Target);
  520. }
  521. private:
  522. Section &getGOTSection(LinkGraph &G) {
  523. if (!GOTSection)
  524. GOTSection = &G.createSection(getSectionName(), MemProt::Read);
  525. return *GOTSection;
  526. }
  527. Section *GOTSection = nullptr;
  528. };
  529. /// Procedure Linkage Table Builder.
  530. class PLTTableManager : public TableManager<PLTTableManager> {
  531. public:
  532. PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
  533. static StringRef getSectionName() { return "$__STUBS"; }
  534. bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
  535. if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
  536. DEBUG_WITH_TYPE("jitlink", {
  537. dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
  538. << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
  539. << formatv("{0:x}", E.getOffset()) << ")\n";
  540. });
  541. // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
  542. // be optimized when the target is in-range.
  543. E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
  544. E.setTarget(getEntryForTarget(G, E.getTarget()));
  545. return true;
  546. }
  547. return false;
  548. }
  549. Symbol &createEntry(LinkGraph &G, Symbol &Target) {
  550. return createAnonymousPointerJumpStub(G, getStubsSection(G),
  551. GOT.getEntryForTarget(G, Target));
  552. }
  553. public:
  554. Section &getStubsSection(LinkGraph &G) {
  555. if (!PLTSection)
  556. PLTSection =
  557. &G.createSection(getSectionName(), MemProt::Read | MemProt::Exec);
  558. return *PLTSection;
  559. }
  560. GOTTableManager &GOT;
  561. Section *PLTSection = nullptr;
  562. };
  563. /// Optimize the GOT and Stub relocations if the edge target address is in range
  564. /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
  565. /// then replace GOT load with lea
  566. /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
  567. /// in range, replace a indirect jump by plt stub with a direct jump to the
  568. /// target
  569. Error optimizeGOTAndStubAccesses(LinkGraph &G);
  570. } // namespace x86_64
  571. } // end namespace jitlink
  572. } // end namespace llvm
  573. #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
  574. #ifdef __GNUC__
  575. #pragma GCC diagnostic pop
  576. #endif