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