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