File indexing completed on 2026-05-10 08:43:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_EXECUTIONENGINE_JITLINK_LOONGARCH_H
0014 #define LLVM_EXECUTIONENGINE_JITLINK_LOONGARCH_H
0015
0016 #include "TableManager.h"
0017 #include "llvm/ADT/StringExtras.h"
0018 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
0019 #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
0020 #include "llvm/Support/LEB128.h"
0021
0022 namespace llvm {
0023 namespace jitlink {
0024 namespace loongarch {
0025
0026
0027 enum EdgeKind_loongarch : Edge::Kind {
0028
0029
0030
0031
0032
0033 Pointer64 = Edge::FirstRelocation,
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 Pointer32,
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 Branch16PCRel,
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 Branch21PCRel,
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 Branch26PCRel,
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 Delta32,
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 NegDelta32,
0137
0138
0139
0140
0141
0142
0143
0144
0145 Delta64,
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 Page20,
0162
0163
0164
0165
0166
0167
0168
0169
0170 PageOffset12,
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190 RequestGOTAndTransformToPage20,
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 RequestGOTAndTransformToPageOffset12,
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 Call36PCRel,
0230
0231
0232
0233
0234
0235
0236 Add6,
0237
0238
0239
0240
0241
0242
0243 Add8,
0244
0245
0246
0247
0248
0249
0250 Add16,
0251
0252
0253
0254
0255
0256
0257 Add32,
0258
0259
0260
0261
0262
0263
0264 Add64,
0265
0266
0267
0268
0269
0270
0271 AddUleb128,
0272
0273
0274
0275
0276
0277
0278 Sub6,
0279
0280
0281
0282
0283
0284
0285 Sub8,
0286
0287
0288
0289
0290
0291
0292 Sub16,
0293
0294
0295
0296
0297
0298
0299 Sub32,
0300
0301
0302
0303
0304
0305
0306 Sub64,
0307
0308
0309
0310
0311
0312
0313 SubUleb128,
0314
0315
0316
0317
0318
0319
0320 AlignRelaxable,
0321 };
0322
0323
0324
0325 const char *getEdgeKindName(Edge::Kind K);
0326
0327
0328 inline uint32_t extractBits(uint64_t Val, unsigned Hi, unsigned Lo) {
0329 return Hi == 63 ? Val >> Lo : (Val & ((((uint64_t)1 << (Hi + 1)) - 1))) >> Lo;
0330 }
0331
0332
0333 inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
0334 using namespace support;
0335
0336 char *BlockWorkingMem = B.getAlreadyMutableContent().data();
0337 char *FixupPtr = BlockWorkingMem + E.getOffset();
0338 uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
0339 uint64_t TargetAddress = E.getTarget().getAddress().getValue();
0340 int64_t Addend = E.getAddend();
0341
0342 switch (E.getKind()) {
0343 case Pointer64:
0344 *(ulittle64_t *)FixupPtr = TargetAddress + Addend;
0345 break;
0346 case Pointer32: {
0347 uint64_t Value = TargetAddress + Addend;
0348 if (Value > std::numeric_limits<uint32_t>::max())
0349 return makeTargetOutOfRangeError(G, B, E);
0350 *(ulittle32_t *)FixupPtr = Value;
0351 break;
0352 }
0353 case Branch16PCRel: {
0354 int64_t Value = TargetAddress - FixupAddress + Addend;
0355
0356 if (!isInt<18>(Value))
0357 return makeTargetOutOfRangeError(G, B, E);
0358
0359 if (!isShiftedInt<16, 2>(Value))
0360 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
0361
0362 uint32_t RawInstr = *(little32_t *)FixupPtr;
0363 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
0364 uint32_t Imm15_0 = extractBits(Imm, 15, 0) << 10;
0365 *(little32_t *)FixupPtr = RawInstr | Imm15_0;
0366 break;
0367 }
0368 case Branch21PCRel: {
0369 int64_t Value = TargetAddress - FixupAddress + Addend;
0370
0371 if (!isInt<23>(Value))
0372 return makeTargetOutOfRangeError(G, B, E);
0373
0374 if (!isShiftedInt<21, 2>(Value))
0375 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
0376
0377 uint32_t RawInstr = *(little32_t *)FixupPtr;
0378 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
0379 uint32_t Imm15_0 = extractBits(Imm, 15, 0) << 10;
0380 uint32_t Imm20_16 = extractBits(Imm, 20, 16);
0381 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16;
0382 break;
0383 }
0384 case Branch26PCRel: {
0385 int64_t Value = TargetAddress - FixupAddress + Addend;
0386
0387 if (!isInt<28>(Value))
0388 return makeTargetOutOfRangeError(G, B, E);
0389
0390 if (!isShiftedInt<26, 2>(Value))
0391 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
0392
0393 uint32_t RawInstr = *(little32_t *)FixupPtr;
0394 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
0395 uint32_t Imm15_0 = extractBits(Imm, 15, 0) << 10;
0396 uint32_t Imm25_16 = extractBits(Imm, 25, 16);
0397 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm25_16;
0398 break;
0399 }
0400 case Delta32: {
0401 int64_t Value = TargetAddress - FixupAddress + Addend;
0402
0403 if (!isInt<32>(Value))
0404 return makeTargetOutOfRangeError(G, B, E);
0405 *(little32_t *)FixupPtr = Value;
0406 break;
0407 }
0408 case NegDelta32: {
0409 int64_t Value = FixupAddress - TargetAddress + Addend;
0410 if (!isInt<32>(Value))
0411 return makeTargetOutOfRangeError(G, B, E);
0412 *(little32_t *)FixupPtr = Value;
0413 break;
0414 }
0415 case Delta64:
0416 *(little64_t *)FixupPtr = TargetAddress - FixupAddress + Addend;
0417 break;
0418 case Page20: {
0419 uint64_t Target = TargetAddress + Addend;
0420 uint64_t TargetPage =
0421 (Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff);
0422 uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(0xfff);
0423
0424 int64_t PageDelta = TargetPage - PCPage;
0425 if (!isInt<32>(PageDelta))
0426 return makeTargetOutOfRangeError(G, B, E);
0427
0428 uint32_t RawInstr = *(little32_t *)FixupPtr;
0429 uint32_t Imm31_12 = extractBits(PageDelta, 31, 12) << 5;
0430 *(little32_t *)FixupPtr = RawInstr | Imm31_12;
0431 break;
0432 }
0433 case PageOffset12: {
0434 uint64_t TargetOffset = (TargetAddress + Addend) & 0xfff;
0435
0436 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
0437 uint32_t Imm11_0 = TargetOffset << 10;
0438 *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0;
0439 break;
0440 }
0441 case Call36PCRel: {
0442 int64_t Value = TargetAddress - FixupAddress + Addend;
0443
0444 if ((Value + 0x20000) != llvm::SignExtend64(Value + 0x20000, 38))
0445 return makeTargetOutOfRangeError(G, B, E);
0446
0447 if (!isShiftedInt<36, 2>(Value))
0448 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
0449
0450 uint32_t Pcaddu18i = *(little32_t *)FixupPtr;
0451 uint32_t Hi20 = extractBits(Value + (1 << 17), 37, 18) << 5;
0452 *(little32_t *)FixupPtr = Pcaddu18i | Hi20;
0453 uint32_t Jirl = *(little32_t *)(FixupPtr + 4);
0454 uint32_t Lo16 = extractBits(Value, 17, 2) << 10;
0455 *(little32_t *)(FixupPtr + 4) = Jirl | Lo16;
0456 break;
0457 }
0458 case Add6: {
0459 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr));
0460 Value += ((TargetAddress + Addend) & 0x3f);
0461 *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f);
0462 break;
0463 }
0464 case Add8: {
0465 int64_t Value =
0466 TargetAddress + *(reinterpret_cast<const int8_t *>(FixupPtr)) + Addend;
0467 *FixupPtr = static_cast<int8_t>(Value);
0468 break;
0469 }
0470 case Add16: {
0471 int64_t Value =
0472 TargetAddress + support::endian::read16le(FixupPtr) + Addend;
0473 *(little16_t *)FixupPtr = static_cast<int16_t>(Value);
0474 break;
0475 }
0476 case Add32: {
0477 int64_t Value =
0478 TargetAddress + support::endian::read32le(FixupPtr) + Addend;
0479 *(little32_t *)FixupPtr = static_cast<int32_t>(Value);
0480 break;
0481 }
0482 case Add64: {
0483 int64_t Value =
0484 TargetAddress + support::endian::read64le(FixupPtr) + Addend;
0485 *(little64_t *)FixupPtr = static_cast<int64_t>(Value);
0486 break;
0487 }
0488 case AddUleb128: {
0489 const uint32_t Maxcount = 1 + 64 / 7;
0490 uint32_t Count;
0491 const char *Error = nullptr;
0492 uint64_t Orig = decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)),
0493 &Count, nullptr, &Error);
0494
0495 if (Count > Maxcount || (Count == Maxcount && Error))
0496 return make_error<JITLinkError>(
0497 "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) +
0498 ": extra space for uleb128");
0499
0500 uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL;
0501 encodeULEB128((Orig + TargetAddress + Addend) & Mask,
0502 (reinterpret_cast<uint8_t *>(FixupPtr)), Count);
0503 break;
0504 }
0505 case Sub6: {
0506 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr));
0507 Value -= ((TargetAddress + Addend) & 0x3f);
0508 *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f);
0509 break;
0510 }
0511 case Sub8: {
0512 int64_t Value =
0513 *(reinterpret_cast<const int8_t *>(FixupPtr)) - TargetAddress - Addend;
0514 *FixupPtr = static_cast<int8_t>(Value);
0515 break;
0516 }
0517 case Sub16: {
0518 int64_t Value =
0519 support::endian::read16le(FixupPtr) - TargetAddress - Addend;
0520 *(little16_t *)FixupPtr = static_cast<int16_t>(Value);
0521 break;
0522 }
0523 case Sub32: {
0524 int64_t Value =
0525 support::endian::read32le(FixupPtr) - TargetAddress - Addend;
0526 *(little32_t *)FixupPtr = static_cast<int32_t>(Value);
0527 break;
0528 }
0529 case Sub64: {
0530 int64_t Value =
0531 support::endian::read64le(FixupPtr) - TargetAddress - Addend;
0532 *(little64_t *)FixupPtr = static_cast<int64_t>(Value);
0533 break;
0534 }
0535 case SubUleb128: {
0536 const uint32_t Maxcount = 1 + 64 / 7;
0537 uint32_t Count;
0538 const char *Error = nullptr;
0539 uint64_t Orig = decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)),
0540 &Count, nullptr, &Error);
0541
0542 if (Count > Maxcount || (Count == Maxcount && Error))
0543 return make_error<JITLinkError>(
0544 "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) +
0545 ": extra space for uleb128");
0546
0547 uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL;
0548 encodeULEB128((Orig - TargetAddress - Addend) & Mask,
0549 (reinterpret_cast<uint8_t *>(FixupPtr)), Count);
0550 break;
0551 }
0552 case AlignRelaxable:
0553
0554 break;
0555 default:
0556 return make_error<JITLinkError>(
0557 "In graph " + G.getName() + ", section " + B.getSection().getName() +
0558 " unsupported edge kind " + getEdgeKindName(E.getKind()));
0559 }
0560
0561 return Error::success();
0562 }
0563
0564
0565 extern const char NullPointerContent[8];
0566 inline ArrayRef<char> getGOTEntryBlockContent(LinkGraph &G) {
0567 return {reinterpret_cast<const char *>(NullPointerContent),
0568 G.getPointerSize()};
0569 }
0570
0571
0572
0573
0574
0575
0576
0577
0578 constexpr size_t StubEntrySize = 12;
0579 extern const uint8_t LA64StubContent[StubEntrySize];
0580 extern const uint8_t LA32StubContent[StubEntrySize];
0581 inline ArrayRef<char> getStubBlockContent(LinkGraph &G) {
0582 auto StubContent =
0583 G.getPointerSize() == 8 ? LA64StubContent : LA32StubContent;
0584 return {reinterpret_cast<const char *>(StubContent), StubEntrySize};
0585 }
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596 inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection,
0597 Symbol *InitialTarget = nullptr,
0598 uint64_t InitialAddend = 0) {
0599 auto &B = G.createContentBlock(PointerSection, getGOTEntryBlockContent(G),
0600 orc::ExecutorAddr(), G.getPointerSize(), 0);
0601 if (InitialTarget)
0602 B.addEdge(G.getPointerSize() == 8 ? Pointer64 : Pointer32, 0,
0603 *InitialTarget, InitialAddend);
0604 return G.addAnonymousSymbol(B, 0, G.getPointerSize(), false, false);
0605 }
0606
0607
0608
0609 inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
0610 Section &StubSection,
0611 Symbol &PointerSymbol) {
0612 Block &StubContentBlock = G.createContentBlock(
0613 StubSection, getStubBlockContent(G), orc::ExecutorAddr(), 4, 0);
0614 StubContentBlock.addEdge(Page20, 0, PointerSymbol, 0);
0615 StubContentBlock.addEdge(PageOffset12, 4, PointerSymbol, 0);
0616 return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true, false);
0617 }
0618
0619
0620 class GOTTableManager : public TableManager<GOTTableManager> {
0621 public:
0622 static StringRef getSectionName() { return "$__GOT"; }
0623
0624 bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
0625 Edge::Kind KindToSet = Edge::Invalid;
0626 switch (E.getKind()) {
0627 case RequestGOTAndTransformToPage20:
0628 KindToSet = Page20;
0629 break;
0630 case RequestGOTAndTransformToPageOffset12:
0631 KindToSet = PageOffset12;
0632 break;
0633 default:
0634 return false;
0635 }
0636 assert(KindToSet != Edge::Invalid &&
0637 "Fell through switch, but no new kind to set");
0638 DEBUG_WITH_TYPE("jitlink", {
0639 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
0640 << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
0641 << formatv("{0:x}", E.getOffset()) << ")\n";
0642 });
0643 E.setKind(KindToSet);
0644 E.setTarget(getEntryForTarget(G, E.getTarget()));
0645 return true;
0646 }
0647
0648 Symbol &createEntry(LinkGraph &G, Symbol &Target) {
0649 return createAnonymousPointer(G, getGOTSection(G), &Target);
0650 }
0651
0652 private:
0653 Section &getGOTSection(LinkGraph &G) {
0654 if (!GOTSection)
0655 GOTSection = &G.createSection(getSectionName(),
0656 orc::MemProt::Read | orc::MemProt::Exec);
0657 return *GOTSection;
0658 }
0659
0660 Section *GOTSection = nullptr;
0661 };
0662
0663
0664 class PLTTableManager : public TableManager<PLTTableManager> {
0665 public:
0666 PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
0667
0668 static StringRef getSectionName() { return "$__STUBS"; }
0669
0670 bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
0671 if ((E.getKind() == Branch26PCRel || E.getKind() == Call36PCRel) &&
0672 !E.getTarget().isDefined()) {
0673 DEBUG_WITH_TYPE("jitlink", {
0674 dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
0675 << B->getFixupAddress(E) << " (" << B->getAddress() << " + "
0676 << formatv("{0:x}", E.getOffset()) << ")\n";
0677 });
0678 E.setTarget(getEntryForTarget(G, E.getTarget()));
0679 return true;
0680 }
0681 return false;
0682 }
0683
0684 Symbol &createEntry(LinkGraph &G, Symbol &Target) {
0685 return createAnonymousPointerJumpStub(G, getStubsSection(G),
0686 GOT.getEntryForTarget(G, Target));
0687 }
0688
0689 public:
0690 Section &getStubsSection(LinkGraph &G) {
0691 if (!StubsSection)
0692 StubsSection = &G.createSection(getSectionName(),
0693 orc::MemProt::Read | orc::MemProt::Exec);
0694 return *StubsSection;
0695 }
0696
0697 GOTTableManager &GOT;
0698 Section *StubsSection = nullptr;
0699 };
0700
0701 }
0702 }
0703 }
0704
0705 #endif