|
|
|||
File indexing completed on 2026-05-10 08:43:51
0001 //===-- x86_64.h - Generic JITLink x86-64 edge kinds, utilities -*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 // 0009 // Generic utilities for graphs representing x86-64 objects. 0010 // 0011 //===----------------------------------------------------------------------===// 0012 0013 #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H 0014 #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H 0015 0016 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 0017 #include "llvm/ExecutionEngine/JITLink/TableManager.h" 0018 0019 namespace llvm { 0020 namespace jitlink { 0021 namespace x86_64 { 0022 0023 /// Represents x86-64 fixups and other x86-64-specific edge kinds. 0024 enum EdgeKind_x86_64 : Edge::Kind { 0025 0026 /// A plain 64-bit pointer value relocation. 0027 /// 0028 /// Fixup expression: 0029 /// Fixup <- Target + Addend : uint64 0030 /// 0031 Pointer64 = Edge::FirstRelocation, 0032 0033 /// A plain 32-bit pointer value relocation. 0034 /// 0035 /// Fixup expression: 0036 /// Fixup <- Target + Addend : uint32 0037 /// 0038 /// Errors: 0039 /// - The target must reside in the low 32-bits of the address space, 0040 /// otherwise an out-of-range error will be returned. 0041 /// 0042 Pointer32, 0043 0044 /// A signed 32-bit pointer value relocation 0045 /// 0046 /// Fixup expression: 0047 /// Fixup <- Target + Addend : int32 0048 /// 0049 /// Errors: 0050 /// - The target must reside in the signed 32-bits([-2**31, 2**32 - 1]) of 0051 /// the address space, otherwise an out-of-range error will be returned. 0052 Pointer32Signed, 0053 0054 /// A plain 16-bit pointer value relocation. 0055 /// 0056 /// Fixup expression: 0057 /// Fixup <- Target + Addend : uint16 0058 /// 0059 /// Errors: 0060 /// - The target must reside in the low 16-bits of the address space, 0061 /// otherwise an out-of-range error will be returned. 0062 /// 0063 Pointer16, 0064 0065 /// A plain 8-bit pointer value relocation. 0066 /// 0067 /// Fixup expression: 0068 /// Fixup <- Target + Addend : uint8 0069 /// 0070 /// Errors: 0071 /// - The target must reside in the low 8-bits of the address space, 0072 /// otherwise an out-of-range error will be returned. 0073 /// 0074 Pointer8, 0075 0076 /// A 64-bit delta. 0077 /// 0078 /// Delta from the fixup to the target. 0079 /// 0080 /// Fixup expression: 0081 /// Fixup <- Target - Fixup + Addend : int64 0082 /// 0083 Delta64, 0084 0085 /// A 32-bit delta. 0086 /// 0087 /// Delta from the fixup to the target. 0088 /// 0089 /// Fixup expression: 0090 /// Fixup <- Target - Fixup + Addend : int32 0091 /// 0092 /// Errors: 0093 /// - The result of the fixup expression must fit into an int32, otherwise 0094 /// an out-of-range error will be returned. 0095 /// 0096 Delta32, 0097 0098 /// A 16-bit delta. 0099 /// 0100 /// Delta from the fixup to the target. 0101 /// 0102 /// Fixup expression: 0103 /// Fixup <- Target - Fixup + Addend : int16 0104 /// 0105 /// Errors: 0106 /// - The result of the fixup expression must fit into an int16, otherwise 0107 /// an out-of-range error will be returned. 0108 /// 0109 Delta16, 0110 0111 /// An 8-bit delta. 0112 /// 0113 /// Delta from the fixup to the target. 0114 /// 0115 /// Fixup expression: 0116 /// Fixup <- Target - Fixup + Addend : int8 0117 /// 0118 /// Errors: 0119 /// - The result of the fixup expression must fit into an int8, otherwise 0120 /// an out-of-range error will be returned. 0121 /// 0122 Delta8, 0123 0124 /// A 64-bit negative delta. 0125 /// 0126 /// Delta from target back to the fixup. 0127 /// 0128 /// Fixup expression: 0129 /// Fixup <- Fixup - Target + Addend : int64 0130 /// 0131 NegDelta64, 0132 0133 /// A 32-bit negative delta. 0134 /// 0135 /// Delta from the target back to the fixup. 0136 /// 0137 /// Fixup expression: 0138 /// Fixup <- Fixup - Target + Addend : int32 0139 /// 0140 /// Errors: 0141 /// - The result of the fixup expression must fit into an int32, otherwise 0142 /// an out-of-range error will be returned. 0143 NegDelta32, 0144 0145 /// A 64-bit size relocation. 0146 /// 0147 /// Fixup expression: 0148 /// Fixup <- Size + Addend : uint64 0149 /// 0150 Size64, 0151 0152 /// A 32-bit size relocation. 0153 /// 0154 /// Fixup expression: 0155 /// Fixup <- Size + Addend : uint32 0156 /// 0157 /// Errors: 0158 /// - The result of the fixup expression must fit into an uint32, otherwise 0159 /// an out-of-range error will be returned. 0160 /// 0161 Size32, 0162 0163 /// A 64-bit GOT delta. 0164 /// 0165 /// Delta from the global offset table to the target 0166 /// 0167 /// Fixup expression: 0168 /// Fixup <- Target - GOTSymbol + Addend : int64 0169 /// 0170 /// Errors: 0171 /// - *ASSERTION* Failure to a null pointer GOTSymbol, which the GOT section 0172 /// symbol was not been defined. 0173 Delta64FromGOT, 0174 0175 /// A 32-bit PC-relative branch. 0176 /// 0177 /// Represents a PC-relative call or branch to a target. This can be used to 0178 /// identify, record, and/or patch call sites. 0179 /// 0180 /// The fixup expression for this kind includes an implicit offset to account 0181 /// for the PC (unlike the Delta edges) so that a Branch32PCRel with a target 0182 /// T and addend zero is a call/branch to the start (offset zero) of T. 0183 /// 0184 /// Fixup expression: 0185 /// Fixup <- Target - (Fixup + 4) + Addend : int32 0186 /// 0187 /// Errors: 0188 /// - The result of the fixup expression must fit into an int32, otherwise 0189 /// an out-of-range error will be returned. 0190 /// 0191 BranchPCRel32, 0192 0193 /// A 32-bit PC-relative relocation. 0194 /// 0195 /// Represents a data/control flow instruction using PC-relative addressing 0196 /// to a target. 0197 /// 0198 /// The fixup expression for this kind includes an implicit offset to account 0199 /// for the PC (unlike the Delta edges) so that a PCRel32 with a target 0200 /// T and addend zero is a call/branch to the start (offset zero) of T. 0201 /// 0202 /// Fixup expression: 0203 /// Fixup <- Target - (Fixup + 4) + Addend : int32 0204 /// 0205 /// Errors: 0206 /// - The result of the fixup expression must fit into an int32, otherwise 0207 /// an out-of-range error will be returned. 0208 /// 0209 PCRel32, 0210 0211 /// A 32-bit PC-relative branch to a pointer jump stub. 0212 /// 0213 /// The target of this relocation should be a pointer jump stub of the form: 0214 /// 0215 /// \code{.s} 0216 /// .text 0217 /// jmpq *tgtptr(%rip) 0218 /// ; ... 0219 /// 0220 /// .data 0221 /// tgtptr: 0222 /// .quad 0 0223 /// \endcode 0224 /// 0225 /// This edge kind has the same fixup expression as BranchPCRel32, but further 0226 /// identifies the call/branch as being to a pointer jump stub. For edges of 0227 /// this kind the jump stub should not be bypassed (use 0228 /// BranchPCRel32ToPtrJumpStubBypassable for that), but the pointer location 0229 /// target may be recorded to allow manipulation at runtime. 0230 /// 0231 /// Fixup expression: 0232 /// Fixup <- Target - Fixup + Addend - 4 : int32 0233 /// 0234 /// Errors: 0235 /// - The result of the fixup expression must fit into an int32, otherwise 0236 /// an out-of-range error will be returned. 0237 /// 0238 BranchPCRel32ToPtrJumpStub, 0239 0240 /// A relaxable version of BranchPCRel32ToPtrJumpStub. 0241 /// 0242 /// The edge kind has the same fixup expression as BranchPCRel32ToPtrJumpStub, 0243 /// but identifies the call/branch as being to a pointer jump stub that may be 0244 /// bypassed with a direct jump to the ultimate target if the ultimate target 0245 /// is within range of the fixup location. 0246 /// 0247 /// Fixup expression: 0248 /// Fixup <- Target - Fixup + Addend - 4: int32 0249 /// 0250 /// Errors: 0251 /// - The result of the fixup expression must fit into an int32, otherwise 0252 /// an out-of-range error will be returned. 0253 /// 0254 BranchPCRel32ToPtrJumpStubBypassable, 0255 0256 /// A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT 0257 /// entry for the original target. 0258 /// 0259 /// Indicates that this edge should be transformed into a Delta32 targeting 0260 /// the GOT entry for the edge's current target, maintaining the same addend. 0261 /// A GOT entry for the target should be created if one does not already 0262 /// exist. 0263 /// 0264 /// Edges of this kind are usually handled by a GOT builder pass inserted by 0265 /// default. 0266 /// 0267 /// Fixup expression: 0268 /// NONE 0269 /// 0270 /// Errors: 0271 /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup 0272 /// phase will result in an assert/unreachable during the fixup phase. 0273 /// 0274 RequestGOTAndTransformToDelta32, 0275 0276 /// A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT 0277 /// entry for the original target. 0278 /// 0279 /// Indicates that this edge should be transformed into a Delta64 targeting 0280 /// the GOT entry for the edge's current target, maintaining the same addend. 0281 /// A GOT entry for the target should be created if one does not already 0282 /// exist. 0283 /// 0284 /// Edges of this kind are usually handled by a GOT builder pass inserted by 0285 /// default. 0286 /// 0287 /// Fixup expression: 0288 /// NONE 0289 /// 0290 /// Errors: 0291 /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup 0292 /// phase will result in an assert/unreachable during the fixup phase. 0293 /// 0294 RequestGOTAndTransformToDelta64, 0295 0296 /// A GOT entry offset within GOT getter/constructor, transformed to 0297 /// Delta64FromGOT 0298 /// pointing at the GOT entry for the original target 0299 /// 0300 /// Indicates that this edge should be transformed into a Delta64FromGOT 0301 /// targeting 0302 /// the GOT entry for the edge's current target, maintaining the same addend. 0303 /// A GOT entry for the target should be created if one does not already 0304 /// exist. 0305 /// 0306 /// Edges of this kind are usually handled by a GOT builder pass inserted by 0307 /// default 0308 /// 0309 /// Fixup expression: 0310 /// NONE 0311 /// 0312 /// Errors: 0313 /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup 0314 /// phase will result in an assert/unreachable during the fixup phase 0315 RequestGOTAndTransformToDelta64FromGOT, 0316 0317 /// A PC-relative load of a GOT entry, relaxable if GOT entry target is 0318 /// in-range of the fixup 0319 /// 0320 /// TODO: Explain the optimization 0321 /// 0322 /// Fixup expression 0323 /// Fixup <- Target - (Fixup + 4) + Addend : int32 0324 /// 0325 /// Errors: 0326 /// - The result of the fixup expression must fit into an int32, otherwise 0327 /// an out-of-range error will be returned. 0328 // 0329 PCRel32GOTLoadRelaxable, 0330 0331 /// A PC-relative REX load of a GOT entry, relaxable if GOT entry target 0332 /// is in-range of the fixup. 0333 /// 0334 /// If the GOT entry target is in-range of the fixup then the load from the 0335 /// GOT may be replaced with a direct memory address calculation. 0336 /// 0337 /// Fixup expression: 0338 /// Fixup <- Target - (Fixup + 4) + Addend : int32 0339 /// 0340 /// Errors: 0341 /// - The result of the fixup expression must fit into an int32, otherwise 0342 /// an out-of-range error will be returned. 0343 /// 0344 PCRel32GOTLoadREXRelaxable, 0345 0346 /// A GOT entry getter/constructor, transformed to 0347 /// PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry for the original 0348 /// target. 0349 /// 0350 /// Indicates that this edge should be lowered to a PC32ToGOTLoadREXRelaxable 0351 /// targeting the GOT entry for the edge's current target, maintaining the 0352 /// same addend. A GOT entry for the target should be created if one does not 0353 /// already exist. 0354 /// 0355 /// Edges of this kind are usually lowered by a GOT builder pass inserted by 0356 /// default. 0357 /// 0358 /// Fixup expression: 0359 /// NONE 0360 /// 0361 /// Errors: 0362 /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup 0363 /// phase will result in an assert/unreachable during the fixup phase. 0364 /// 0365 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable, 0366 0367 /// A GOT entry getter/constructor, transformed to 0368 /// PCRel32ToGOTLoadRelaxable pointing at the GOT entry for the original 0369 /// target. 0370 /// 0371 /// Indicates that this edge should be lowered to a PC32ToGOTLoadRelaxable 0372 /// targeting the GOT entry for the edge's current target, maintaining the 0373 /// same addend. A GOT entry for the target should be created if one does not 0374 /// already exist. 0375 /// 0376 /// Edges of this kind are usually lowered by a GOT builder pass inserted by 0377 /// default. 0378 /// 0379 /// Fixup expression: 0380 /// NONE 0381 /// 0382 /// Errors: 0383 /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup 0384 /// phase will result in an assert/unreachable during the fixup phase. 0385 /// 0386 RequestGOTAndTransformToPCRel32GOTLoadRelaxable, 0387 0388 /// A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry, 0389 /// relaxable if the TLVP entry target is in-range of the fixup. 0390 /// 0391 /// If the TLVP entry target is in-range of the fixup then the load from the 0392 /// TLVP may be replaced with a direct memory address calculation. 0393 /// 0394 /// The target of this edge must be a thread local variable entry of the form 0395 /// .quad <tlv getter thunk> 0396 /// .quad <tlv key> 0397 /// .quad <tlv initializer> 0398 /// 0399 /// Fixup expression: 0400 /// Fixup <- Target - (Fixup + 4) + Addend : int32 0401 /// 0402 /// Errors: 0403 /// - The result of the fixup expression must fit into an int32, otherwise 0404 /// an out-of-range error will be returned. 0405 /// - The target must be either external, or a TLV entry of the required 0406 /// form, otherwise a malformed TLV entry error will be returned. 0407 /// 0408 PCRel32TLVPLoadREXRelaxable, 0409 0410 /// TODO: Explain the generic edge kind 0411 RequestTLSDescInGOTAndTransformToDelta32, 0412 0413 /// A TLVP entry getter/constructor, transformed to 0414 /// Delta32ToTLVPLoadREXRelaxable. 0415 /// 0416 /// Indicates that this edge should be transformed into a 0417 /// Delta32ToTLVPLoadREXRelaxable targeting the TLVP entry for the edge's 0418 /// current target. A TLVP entry for the target should be created if one does 0419 /// not already exist. 0420 /// 0421 /// Fixup expression: 0422 /// NONE 0423 /// 0424 /// Errors: 0425 /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup 0426 /// phase will result in an assert/unreachable during the fixup phase. 0427 /// 0428 RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable, 0429 // First platform specific relocation. 0430 FirstPlatformRelocation 0431 }; 0432 0433 /// Returns a string name for the given x86-64 edge. For debugging purposes 0434 /// only. 0435 const char *getEdgeKindName(Edge::Kind K); 0436 0437 /// Apply fixup expression for edge to block content. 0438 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, 0439 const Symbol *GOTSymbol) { 0440 using namespace support; 0441 0442 char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 0443 char *FixupPtr = BlockWorkingMem + E.getOffset(); 0444 auto FixupAddress = B.getAddress() + E.getOffset(); 0445 0446 switch (E.getKind()) { 0447 0448 case Pointer64: { 0449 uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 0450 *(ulittle64_t *)FixupPtr = Value; 0451 break; 0452 } 0453 0454 case Pointer32: { 0455 uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 0456 if (LLVM_LIKELY(isUInt<32>(Value))) 0457 *(ulittle32_t *)FixupPtr = Value; 0458 else 0459 return makeTargetOutOfRangeError(G, B, E); 0460 break; 0461 } 0462 case Pointer32Signed: { 0463 int64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 0464 if (LLVM_LIKELY(isInt<32>(Value))) 0465 *(little32_t *)FixupPtr = Value; 0466 else 0467 return makeTargetOutOfRangeError(G, B, E); 0468 break; 0469 } 0470 0471 case Pointer16: { 0472 uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 0473 if (LLVM_LIKELY(isUInt<16>(Value))) 0474 *(ulittle16_t *)FixupPtr = Value; 0475 else 0476 return makeTargetOutOfRangeError(G, B, E); 0477 break; 0478 } 0479 0480 case Pointer8: { 0481 uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); 0482 if (LLVM_LIKELY(isUInt<8>(Value))) 0483 *(uint8_t *)FixupPtr = Value; 0484 else 0485 return makeTargetOutOfRangeError(G, B, E); 0486 break; 0487 } 0488 0489 case PCRel32: 0490 case BranchPCRel32: 0491 case BranchPCRel32ToPtrJumpStub: 0492 case BranchPCRel32ToPtrJumpStubBypassable: 0493 case PCRel32GOTLoadRelaxable: 0494 case PCRel32GOTLoadREXRelaxable: 0495 case PCRel32TLVPLoadREXRelaxable: { 0496 int64_t Value = 0497 E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend(); 0498 if (LLVM_LIKELY(isInt<32>(Value))) 0499 *(little32_t *)FixupPtr = Value; 0500 else 0501 return makeTargetOutOfRangeError(G, B, E); 0502 break; 0503 } 0504 0505 case Delta64: { 0506 int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 0507 *(little64_t *)FixupPtr = Value; 0508 break; 0509 } 0510 0511 case Delta32: { 0512 int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 0513 if (LLVM_LIKELY(isInt<32>(Value))) 0514 *(little32_t *)FixupPtr = Value; 0515 else 0516 return makeTargetOutOfRangeError(G, B, E); 0517 break; 0518 } 0519 0520 case Delta16: { 0521 int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 0522 if (LLVM_LIKELY(isInt<16>(Value))) 0523 *(little16_t *)FixupPtr = Value; 0524 else 0525 return makeTargetOutOfRangeError(G, B, E); 0526 break; 0527 } 0528 0529 case Delta8: { 0530 int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); 0531 if (LLVM_LIKELY(isInt<8>(Value))) 0532 *FixupPtr = Value; 0533 else 0534 return makeTargetOutOfRangeError(G, B, E); 0535 break; 0536 } 0537 0538 case NegDelta64: { 0539 int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); 0540 *(little64_t *)FixupPtr = Value; 0541 break; 0542 } 0543 0544 case NegDelta32: { 0545 int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); 0546 if (LLVM_LIKELY(isInt<32>(Value))) 0547 *(little32_t *)FixupPtr = Value; 0548 else 0549 return makeTargetOutOfRangeError(G, B, E); 0550 break; 0551 } 0552 0553 case Size64: { 0554 uint64_t Value = E.getTarget().getSize() + E.getAddend(); 0555 *(ulittle64_t *)FixupPtr = Value; 0556 break; 0557 } 0558 0559 case Size32: { 0560 uint64_t Value = E.getTarget().getSize() + E.getAddend(); 0561 if (LLVM_LIKELY(isUInt<32>(Value))) 0562 *(ulittle32_t *)FixupPtr = Value; 0563 else 0564 return makeTargetOutOfRangeError(G, B, E); 0565 break; 0566 } 0567 0568 case Delta64FromGOT: { 0569 assert(GOTSymbol && "No GOT section symbol"); 0570 int64_t Value = 0571 E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend(); 0572 *(little64_t *)FixupPtr = Value; 0573 break; 0574 } 0575 0576 default: 0577 return make_error<JITLinkError>( 0578 "In graph " + G.getName() + ", section " + B.getSection().getName() + 0579 " unsupported edge kind " + getEdgeKindName(E.getKind())); 0580 } 0581 0582 return Error::success(); 0583 } 0584 0585 /// x86_64 pointer size. 0586 constexpr uint64_t PointerSize = 8; 0587 0588 /// x86-64 null pointer content. 0589 extern const char NullPointerContent[PointerSize]; 0590 0591 /// x86-64 pointer jump stub content. 0592 /// 0593 /// Contains the instruction sequence for an indirect jump via an in-memory 0594 /// pointer: 0595 /// jmpq *ptr(%rip) 0596 extern const char PointerJumpStubContent[6]; 0597 0598 /// Creates a new pointer block in the given section and returns an anonymous 0599 /// symbol pointing to it. 0600 /// 0601 /// If InitialTarget is given then an Pointer64 relocation will be added to the 0602 /// block pointing at InitialTarget. 0603 /// 0604 /// The pointer block will have the following default values: 0605 /// alignment: 64-bit 0606 /// alignment-offset: 0 0607 /// address: highest allowable (~7U) 0608 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection, 0609 Symbol *InitialTarget = nullptr, 0610 uint64_t InitialAddend = 0) { 0611 auto &B = G.createContentBlock(PointerSection, NullPointerContent, 0612 orc::ExecutorAddr(~uint64_t(7)), 8, 0); 0613 if (InitialTarget) 0614 B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend); 0615 return G.addAnonymousSymbol(B, 0, 8, false, false); 0616 } 0617 0618 /// Create a jump stub block that jumps via the pointer at the given symbol. 0619 /// 0620 /// The stub block will have the following default values: 0621 /// alignment: 8-bit 0622 /// alignment-offset: 0 0623 /// address: highest allowable: (~5U) 0624 inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection, 0625 Symbol &PointerSymbol) { 0626 auto &B = G.createContentBlock(StubSection, PointerJumpStubContent, 0627 orc::ExecutorAddr(~uint64_t(5)), 1, 0); 0628 B.addEdge(BranchPCRel32, 2, PointerSymbol, 0); 0629 return B; 0630 } 0631 0632 /// Create a jump stub that jumps via the pointer at the given symbol and 0633 /// an anonymous symbol pointing to it. Return the anonymous symbol. 0634 /// 0635 /// The stub block will be created by createPointerJumpStubBlock. 0636 inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G, 0637 Section &StubSection, 0638 Symbol &PointerSymbol) { 0639 return G.addAnonymousSymbol( 0640 createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true, 0641 false); 0642 } 0643 0644 /// x86-64 reentry trampoline. 0645 /// 0646 /// Contains the instruction sequence for a trampoline that stores its return 0647 /// address on the stack and calls <reentry-symbol>: 0648 /// call <reentry-symbol> 0649 extern const char ReentryTrampolineContent[5]; 0650 0651 /// Create a block of N reentry trampolines. 0652 inline Block &createReentryTrampolineBlock(LinkGraph &G, 0653 Section &TrampolineSection, 0654 Symbol &ReentrySymbol) { 0655 auto &B = G.createContentBlock(TrampolineSection, ReentryTrampolineContent, 0656 orc::ExecutorAddr(~uint64_t(7)), 1, 0); 0657 B.addEdge(BranchPCRel32, 1, ReentrySymbol, 0); 0658 return B; 0659 } 0660 0661 inline Symbol &createAnonymousReentryTrampoline(LinkGraph &G, 0662 Section &TrampolineSection, 0663 Symbol &ReentrySymbol) { 0664 return G.addAnonymousSymbol( 0665 createReentryTrampolineBlock(G, TrampolineSection, ReentrySymbol), 0, 0666 sizeof(ReentryTrampolineContent), true, false); 0667 } 0668 0669 /// Global Offset Table Builder. 0670 class GOTTableManager : public TableManager<GOTTableManager> { 0671 public: 0672 static StringRef getSectionName() { return "$__GOT"; } 0673 0674 GOTTableManager(LinkGraph &G) { 0675 if ((GOTSection = G.findSectionByName(getSectionName()))) 0676 registerExistingEntries(); 0677 } 0678 0679 bool visitEdge(LinkGraph &G, Block *B, Edge &E) { 0680 Edge::Kind KindToSet = Edge::Invalid; 0681 switch (E.getKind()) { 0682 case x86_64::Delta64FromGOT: { 0683 // we need to make sure that the GOT section exists, but don't otherwise 0684 // need to fix up this edge 0685 getGOTSection(G); 0686 return false; 0687 } 0688 case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable: 0689 KindToSet = x86_64::PCRel32GOTLoadREXRelaxable; 0690 break; 0691 case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable: 0692 KindToSet = x86_64::PCRel32GOTLoadRelaxable; 0693 break; 0694 case x86_64::RequestGOTAndTransformToDelta64: 0695 KindToSet = x86_64::Delta64; 0696 break; 0697 case x86_64::RequestGOTAndTransformToDelta64FromGOT: 0698 KindToSet = x86_64::Delta64FromGOT; 0699 break; 0700 case x86_64::RequestGOTAndTransformToDelta32: 0701 KindToSet = x86_64::Delta32; 0702 break; 0703 default: 0704 return false; 0705 } 0706 assert(KindToSet != Edge::Invalid && 0707 "Fell through switch, but no new kind to set"); 0708 DEBUG_WITH_TYPE("jitlink", { 0709 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " 0710 << B->getFixupAddress(E) << " (" << B->getAddress() << " + " 0711 << formatv("{0:x}", E.getOffset()) << ")\n"; 0712 }); 0713 E.setKind(KindToSet); 0714 E.setTarget(getEntryForTarget(G, E.getTarget())); 0715 return true; 0716 } 0717 0718 Symbol &createEntry(LinkGraph &G, Symbol &Target) { 0719 return createAnonymousPointer(G, getGOTSection(G), &Target); 0720 } 0721 0722 private: 0723 Section &getGOTSection(LinkGraph &G) { 0724 if (!GOTSection) 0725 GOTSection = &G.createSection(getSectionName(), orc::MemProt::Read); 0726 return *GOTSection; 0727 } 0728 0729 void registerExistingEntries(); 0730 0731 Section *GOTSection = nullptr; 0732 }; 0733 0734 /// Procedure Linkage Table Builder. 0735 class PLTTableManager : public TableManager<PLTTableManager> { 0736 public: 0737 static StringRef getSectionName() { return "$__STUBS"; } 0738 0739 PLTTableManager(LinkGraph &G, GOTTableManager &GOT) : GOT(GOT) { 0740 if ((StubsSection = G.findSectionByName(getSectionName()))) 0741 registerExistingEntries(); 0742 } 0743 0744 bool visitEdge(LinkGraph &G, Block *B, Edge &E) { 0745 if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) { 0746 DEBUG_WITH_TYPE("jitlink", { 0747 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " 0748 << B->getFixupAddress(E) << " (" << B->getAddress() << " + " 0749 << formatv("{0:x}", E.getOffset()) << ")\n"; 0750 }); 0751 // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to 0752 // be optimized when the target is in-range. 0753 E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable); 0754 E.setTarget(getEntryForTarget(G, E.getTarget())); 0755 return true; 0756 } 0757 return false; 0758 } 0759 0760 Symbol &createEntry(LinkGraph &G, Symbol &Target) { 0761 return createAnonymousPointerJumpStub(G, getStubsSection(G), 0762 GOT.getEntryForTarget(G, Target)); 0763 } 0764 0765 public: 0766 Section &getStubsSection(LinkGraph &G) { 0767 if (!StubsSection) 0768 StubsSection = &G.createSection(getSectionName(), 0769 orc::MemProt::Read | orc::MemProt::Exec); 0770 return *StubsSection; 0771 } 0772 0773 void registerExistingEntries(); 0774 0775 GOTTableManager &GOT; 0776 Section *StubsSection = nullptr; 0777 }; 0778 0779 /// Optimize the GOT and Stub relocations if the edge target address is in range 0780 /// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range, 0781 /// then replace GOT load with lea 0782 /// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is 0783 /// in range, replace a indirect jump by plt stub with a direct jump to the 0784 /// target 0785 Error optimizeGOTAndStubAccesses(LinkGraph &G); 0786 0787 } // namespace x86_64 0788 } // end namespace jitlink 0789 } // end namespace llvm 0790 0791 #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|