x86_64.h 22 KB

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