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