LLVM 23.0.0git
ELF_loongarch.cpp
Go to the documentation of this file.
1//===--- ELF_loongarch.cpp - JIT linker implementation for ELF/loongarch --===//
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// ELF/loongarch jit-link implementation.
10//
11//===----------------------------------------------------------------------===//
12
18#include "llvm/Object/ELF.h"
20
21#include "EHFrameSupportImpl.h"
22#include "ELFLinkGraphBuilder.h"
23#include "JITLinkGeneric.h"
24
25#define DEBUG_TYPE "jitlink"
26
27using namespace llvm;
28using namespace llvm::jitlink;
29using namespace llvm::jitlink::loongarch;
30
31namespace {
32
33class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> {
34 friend class JITLinker<ELFJITLinker_loongarch>;
35
36public:
37 ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx,
38 std::unique_ptr<LinkGraph> G,
39 PassConfiguration PassConfig)
40 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
41
42private:
43 /// Apply fixup expression for edge to block content.
44 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
45 using namespace support;
46
47 char *BlockWorkingMem = B.getAlreadyMutableContent().data();
48 char *FixupPtr = BlockWorkingMem + E.getOffset();
49 uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
50 uint64_t TargetAddress = E.getTarget().getAddress().getValue();
51 int64_t Addend = E.getAddend();
52
53 switch (E.getKind()) {
54 case Pointer64:
55 *(ulittle64_t *)FixupPtr = TargetAddress + Addend;
56 break;
57 case Pointer32: {
58 uint64_t Value = TargetAddress + Addend;
59 if (Value > std::numeric_limits<uint32_t>::max())
61 *(ulittle32_t *)FixupPtr = Value;
62 break;
63 }
64 case Branch16PCRel: {
65 int64_t Value = TargetAddress - FixupAddress + Addend;
66
67 if (!isInt<18>(Value))
69
71 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
72
73 uint32_t RawInstr = *(little32_t *)FixupPtr;
74 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
75 uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
76 *(little32_t *)FixupPtr = RawInstr | Imm15_0;
77 break;
78 }
79 case Branch21PCRel: {
80 int64_t Value = TargetAddress - FixupAddress + Addend;
81
82 if (!isInt<23>(Value))
84
86 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
87
88 uint32_t RawInstr = *(little32_t *)FixupPtr;
89 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
90 uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
91 uint32_t Imm20_16 = extractBits(Imm, /*Hi=*/20, /*Lo=*/16);
92 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16;
93 break;
94 }
95 case Branch26PCRel: {
96 int64_t Value = TargetAddress - FixupAddress + Addend;
97
98 if (!isInt<28>(Value))
100
102 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
103
104 uint32_t RawInstr = *(little32_t *)FixupPtr;
105 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
106 uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
107 uint32_t Imm25_16 = extractBits(Imm, /*Hi=*/25, /*Lo=*/16);
108 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm25_16;
109 break;
110 }
111 case Delta32: {
112 int64_t Value = TargetAddress - FixupAddress + Addend;
113
114 if (!isInt<32>(Value))
115 return makeTargetOutOfRangeError(G, B, E);
116 *(little32_t *)FixupPtr = Value;
117 break;
118 }
119 case NegDelta32: {
120 int64_t Value = FixupAddress - TargetAddress + Addend;
121 if (!isInt<32>(Value))
122 return makeTargetOutOfRangeError(G, B, E);
123 *(little32_t *)FixupPtr = Value;
124 break;
125 }
126 case Delta64:
127 *(little64_t *)FixupPtr = TargetAddress - FixupAddress + Addend;
128 break;
129 case Page20: {
130 uint64_t Target = TargetAddress + Addend;
131 uint64_t TargetPage =
132 (Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff);
133 uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(0xfff);
134
135 int64_t PageDelta = TargetPage - PCPage;
136 if (!isInt<32>(PageDelta))
137 return makeTargetOutOfRangeError(G, B, E);
138
139 uint32_t RawInstr = *(little32_t *)FixupPtr;
140 uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5;
141 *(little32_t *)FixupPtr = RawInstr | Imm31_12;
142 break;
143 }
144 case PageOffset12: {
145 uint64_t TargetOffset = (TargetAddress + Addend) & 0xfff;
146
147 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
148 uint32_t Imm11_0 = TargetOffset << 10;
149 *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0;
150 break;
151 }
152 case Call36PCRel: {
153 int64_t Value = TargetAddress - FixupAddress + Addend;
154
155 if ((Value + 0x20000) != llvm::SignExtend64(Value + 0x20000, 38))
156 return makeTargetOutOfRangeError(G, B, E);
157
159 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
160
161 uint32_t Pcaddu18i = *(little32_t *)FixupPtr;
162 uint32_t Hi20 = extractBits(Value + (1 << 17), /*Hi=*/37, /*Lo=*/18) << 5;
163 *(little32_t *)FixupPtr = Pcaddu18i | Hi20;
164 uint32_t Jirl = *(little32_t *)(FixupPtr + 4);
165 uint32_t Lo16 = extractBits(Value, /*Hi=*/17, /*Lo=*/2) << 10;
166 *(little32_t *)(FixupPtr + 4) = Jirl | Lo16;
167 break;
168 }
169 case Add6: {
170 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr));
171 Value += ((TargetAddress + Addend) & 0x3f);
172 *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f);
173 break;
174 }
175 case Add8: {
176 int64_t Value = TargetAddress +
177 *(reinterpret_cast<const int8_t *>(FixupPtr)) + Addend;
178 *FixupPtr = static_cast<int8_t>(Value);
179 break;
180 }
181 case Add16: {
182 int64_t Value =
183 TargetAddress + support::endian::read16le(FixupPtr) + Addend;
184 *(little16_t *)FixupPtr = static_cast<int16_t>(Value);
185 break;
186 }
187 case Add32: {
188 int64_t Value =
189 TargetAddress + support::endian::read32le(FixupPtr) + Addend;
190 *(little32_t *)FixupPtr = static_cast<int32_t>(Value);
191 break;
192 }
193 case Add64: {
194 int64_t Value =
195 TargetAddress + support::endian::read64le(FixupPtr) + Addend;
196 *(little64_t *)FixupPtr = static_cast<int64_t>(Value);
197 break;
198 }
199 case AddUleb128: {
200 const uint32_t Maxcount = 1 + 64 / 7;
202 const char *Error = nullptr;
203 uint64_t Orig =
204 decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)), &Count,
205 nullptr, &Error);
206
207 if (Count > Maxcount || (Count == Maxcount && Error))
209 "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) +
210 ": extra space for uleb128");
211
212 uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL;
213 encodeULEB128((Orig + TargetAddress + Addend) & Mask,
214 (reinterpret_cast<uint8_t *>(FixupPtr)), Count);
215 break;
216 }
217 case Sub6: {
218 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr));
219 Value -= ((TargetAddress + Addend) & 0x3f);
220 *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f);
221 break;
222 }
223 case Sub8: {
224 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr)) -
225 TargetAddress - Addend;
226 *FixupPtr = static_cast<int8_t>(Value);
227 break;
228 }
229 case Sub16: {
230 int64_t Value =
231 support::endian::read16le(FixupPtr) - TargetAddress - Addend;
232 *(little16_t *)FixupPtr = static_cast<int16_t>(Value);
233 break;
234 }
235 case Sub32: {
236 int64_t Value =
237 support::endian::read32le(FixupPtr) - TargetAddress - Addend;
238 *(little32_t *)FixupPtr = static_cast<int32_t>(Value);
239 break;
240 }
241 case Sub64: {
242 int64_t Value =
243 support::endian::read64le(FixupPtr) - TargetAddress - Addend;
244 *(little64_t *)FixupPtr = static_cast<int64_t>(Value);
245 break;
246 }
247 case SubUleb128: {
248 const uint32_t Maxcount = 1 + 64 / 7;
250 const char *Error = nullptr;
251 uint64_t Orig =
252 decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)), &Count,
253 nullptr, &Error);
254
255 if (Count > Maxcount || (Count == Maxcount && Error))
257 "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) +
258 ": extra space for uleb128");
259
260 uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL;
261 encodeULEB128((Orig - TargetAddress - Addend) & Mask,
262 (reinterpret_cast<uint8_t *>(FixupPtr)), Count);
263 break;
264 }
265 case AlignRelaxable:
266 // Ignore when the relaxation pass did not run
267 break;
268 default:
270 "In graph " + G.getName() + ", section " + B.getSection().getName() +
271 " unsupported edge kind " + getEdgeKindName(E.getKind()));
272 }
273
274 return Error::success();
275 }
276};
277
278namespace {
279
280struct SymbolAnchor {
282 Symbol *Sym;
283 bool End; // true for the anchor of getOffset() + getSize()
284};
285
286struct BlockRelaxAux {
287 // This records symbol start and end offsets which will be adjusted according
288 // to the nearest RelocDeltas element.
290 // All edges that either 1) are R_LARCH_ALIGN or 2) have a R_LARCH_RELAX edge
291 // at the same offset.
292 SmallVector<Edge *, 0> RelaxEdges;
293 // For RelaxEdges[I], the actual offset is RelaxEdges[I]->getOffset() - (I ?
294 // RelocDeltas[I - 1] : 0).
295 SmallVector<uint32_t, 0> RelocDeltas;
296 // For RelaxEdges[I], the actual type is EdgeKinds[I].
298 // List of rewritten instructions. Contains one raw encoded instruction per
299 // element in EdgeKinds that isn't Invalid or R_LARCH_ALIGN.
301};
302
303struct RelaxAux {
305};
306
307} // namespace
308
309static bool shouldRelax(const Section &S) {
311}
312
313static bool isRelaxable(const Edge &E) {
314 switch (E.getKind()) {
315 default:
316 return false;
317 case AlignRelaxable:
318 return true;
319 }
320}
321
322static RelaxAux initRelaxAux(LinkGraph &G) {
323 RelaxAux Aux;
324 for (auto &S : G.sections()) {
325 if (!shouldRelax(S))
326 continue;
327 for (auto *B : S.blocks()) {
328 auto BlockEmplaceResult = Aux.Blocks.try_emplace(B);
329 assert(BlockEmplaceResult.second && "Block encountered twice");
330 auto &BlockAux = BlockEmplaceResult.first->second;
331
332 for (auto &E : B->edges())
333 if (isRelaxable(E))
334 BlockAux.RelaxEdges.push_back(&E);
335
336 if (BlockAux.RelaxEdges.empty()) {
337 Aux.Blocks.erase(BlockEmplaceResult.first);
338 continue;
339 }
340
341 const auto NumEdges = BlockAux.RelaxEdges.size();
342 BlockAux.RelocDeltas.resize(NumEdges, 0);
343 BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);
344
345 // Store anchors (offset and offset+size) for symbols.
346 for (auto *Sym : S.symbols()) {
347 if (!Sym->isDefined() || &Sym->getBlock() != B)
348 continue;
349
350 BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false});
351 BlockAux.Anchors.push_back(
352 {Sym->getOffset() + Sym->getSize(), Sym, true});
353 }
354 }
355 }
356
357 // Sort anchors by offset so that we can find the closest relocation
358 // efficiently. For a zero size symbol, ensure that its start anchor precedes
359 // its end anchor. For two symbols with anchors at the same offset, their
360 // order does not matter.
361 for (auto &BlockAuxIter : Aux.Blocks) {
362 llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) {
363 return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End);
364 });
365 }
366
367 return Aux;
368}
369
370static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove,
371 Edge::Kind &NewEdgeKind) {
372 const uint64_t Addend =
373 !E.getTarget().isDefined() ? Log2_64(E.getAddend()) + 1 : E.getAddend();
374 const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4;
375 const uint64_t Align = 1ULL << (Addend & 0xff);
376 const uint64_t MaxBytes = Addend >> 8;
377 const uint64_t Off = Loc.getValue() & (Align - 1);
378 const uint64_t CurBytes = Off == 0 ? 0 : Align - Off;
379 // All bytes beyond the alignment boundary should be removed.
380 // If emit bytes more than max bytes to emit, remove all.
381 if (MaxBytes != 0 && CurBytes > MaxBytes)
382 Remove = AllBytes;
383 else
384 Remove = AllBytes - CurBytes;
385
386 assert(static_cast<int32_t>(Remove) >= 0 &&
387 "R_LARCH_ALIGN needs expanding the content");
388 NewEdgeKind = AlignRelaxable;
389}
390
391static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) {
392 const auto BlockAddr = Block.getAddress();
393 bool Changed = false;
394 ArrayRef<SymbolAnchor> SA = ArrayRef(Aux.Anchors);
395 uint32_t Delta = 0;
396
397 Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);
398 Aux.Writes.clear();
399
400 for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) {
401 const auto Loc = BlockAddr + E->getOffset() - Delta;
402 auto &Cur = Aux.RelocDeltas[I];
403 uint32_t Remove = 0;
404 switch (E->getKind()) {
405 case AlignRelaxable:
406 relaxAlign(Loc, *E, Remove, Aux.EdgeKinds[I]);
407 break;
408 default:
409 llvm_unreachable("Unexpected relaxable edge kind");
410 }
411
412 // For all anchors whose offsets are <= E->getOffset(), they are preceded by
413 // the previous relocation whose RelocDeltas value equals Delta.
414 // Decrease their offset and update their size.
415 for (; SA.size() && SA[0].Offset <= E->getOffset(); SA = SA.slice(1)) {
416 if (SA[0].End)
417 SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset());
418 else
419 SA[0].Sym->setOffset(SA[0].Offset - Delta);
420 }
421
422 Delta += Remove;
423 if (Delta != Cur) {
424 Cur = Delta;
425 Changed = true;
426 }
427 }
428
429 for (const SymbolAnchor &A : SA) {
430 if (A.End)
431 A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset());
432 else
433 A.Sym->setOffset(A.Offset - Delta);
434 }
435
436 return Changed;
437}
438
439static bool relaxOnce(LinkGraph &G, RelaxAux &Aux) {
440 bool Changed = false;
441
442 for (auto &[B, BlockAux] : Aux.Blocks)
443 Changed |= relaxBlock(G, *B, BlockAux);
444
445 return Changed;
446}
447
448static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) {
449 auto Contents = Block.getAlreadyMutableContent();
450 auto *Dest = Contents.data();
451 uint32_t Offset = 0;
452 uint32_t Delta = 0;
453
454 // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite
455 // instructions for relaxed relocations.
456 for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) {
457 uint32_t Remove = Aux.RelocDeltas[I] - Delta;
458 Delta = Aux.RelocDeltas[I];
459 if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid)
460 continue;
461
462 // Copy from last location to the current relocated location.
463 const auto Size = E->getOffset() - Offset;
464 std::memmove(Dest, Contents.data() + Offset, Size);
465 Dest += Size;
466 Offset = E->getOffset() + Remove;
467 }
468
469 std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset);
470
471 // Fixup edge offsets and kinds.
472 Delta = 0;
473 size_t I = 0;
474 for (auto &E : Block.edges()) {
475 E.setOffset(E.getOffset() - Delta);
476
477 if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) {
478 if (Aux.EdgeKinds[I] != Edge::Invalid)
479 E.setKind(Aux.EdgeKinds[I]);
480
481 Delta = Aux.RelocDeltas[I];
482 ++I;
483 }
484 }
485
486 // Remove AlignRelaxable edges: all other relaxable edges got modified and
487 // will be used later while linking. Alignment is entirely handled here so we
488 // don't need these edges anymore.
489 for (auto IE = Block.edges().begin(); IE != Block.edges().end();) {
490 if (IE->getKind() == AlignRelaxable)
491 IE = Block.removeEdge(IE);
492 else
493 ++IE;
494 }
495}
496
497static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) {
498 for (auto &[B, BlockAux] : Aux.Blocks)
499 finalizeBlockRelax(G, *B, BlockAux);
500}
501
502static Error relax(LinkGraph &G) {
503 auto Aux = initRelaxAux(G);
504 while (relaxOnce(G, Aux)) {
505 }
506 finalizeRelax(G, Aux);
507 return Error::success();
508}
509
510template <typename ELFT>
511class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> {
512private:
514 getRelocationKind(const uint32_t Type) {
515 using namespace loongarch;
516 switch (Type) {
517 case ELF::R_LARCH_64:
518 return Pointer64;
519 case ELF::R_LARCH_32:
520 return Pointer32;
521 case ELF::R_LARCH_32_PCREL:
522 return Delta32;
523 case ELF::R_LARCH_B16:
524 return Branch16PCRel;
525 case ELF::R_LARCH_B21:
526 return Branch21PCRel;
527 case ELF::R_LARCH_B26:
528 return Branch26PCRel;
529 case ELF::R_LARCH_PCALA_HI20:
530 return Page20;
531 case ELF::R_LARCH_PCALA_LO12:
532 return PageOffset12;
533 case ELF::R_LARCH_GOT_PC_HI20:
535 case ELF::R_LARCH_GOT_PC_LO12:
537 case ELF::R_LARCH_CALL36:
538 return Call36PCRel;
539 case ELF::R_LARCH_ADD6:
540 return Add6;
541 case ELF::R_LARCH_ADD8:
542 return Add8;
543 case ELF::R_LARCH_ADD16:
544 return Add16;
545 case ELF::R_LARCH_ADD32:
546 return Add32;
547 case ELF::R_LARCH_ADD64:
548 return Add64;
549 case ELF::R_LARCH_ADD_ULEB128:
550 return AddUleb128;
551 case ELF::R_LARCH_SUB6:
552 return Sub6;
553 case ELF::R_LARCH_SUB8:
554 return Sub8;
555 case ELF::R_LARCH_SUB16:
556 return Sub16;
557 case ELF::R_LARCH_SUB32:
558 return Sub32;
559 case ELF::R_LARCH_SUB64:
560 return Sub64;
561 case ELF::R_LARCH_SUB_ULEB128:
562 return SubUleb128;
563 case ELF::R_LARCH_ALIGN:
564 return AlignRelaxable;
565 }
566
568 "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) +
570 }
571
572 EdgeKind_loongarch getRelaxableRelocationKind(EdgeKind_loongarch Kind) {
573 // TODO: Implement more. Just ignore all relaxations now.
574 return Kind;
575 }
576
577 Error addRelocations() override {
578 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
579
581 using Self = ELFLinkGraphBuilder_loongarch<ELFT>;
582 for (const auto &RelSect : Base::Sections)
583 if (Error Err = Base::forEachRelaRelocation(RelSect, this,
584 &Self::addSingleRelocation))
585 return Err;
586
587 return Error::success();
588 }
589
590 Error addSingleRelocation(const typename ELFT::Rela &Rel,
591 const typename ELFT::Shdr &FixupSect,
592 Block &BlockToFix) {
594
595 uint32_t Type = Rel.getType(false);
596 int64_t Addend = Rel.r_addend;
597
598 // ignore
599 if (Type == ELF::R_LARCH_MARK_LA)
600 return Error::success();
601
602 if (Type == ELF::R_LARCH_RELAX) {
603 if (BlockToFix.edges_empty())
605 "R_LARCH_RELAX without preceding relocation",
607
608 auto &PrevEdge = *std::prev(BlockToFix.edges().end());
609 auto Kind = static_cast<EdgeKind_loongarch>(PrevEdge.getKind());
610 PrevEdge.setKind(getRelaxableRelocationKind(Kind));
611 return Error::success();
612 }
613
614 Expected<loongarch::EdgeKind_loongarch> Kind = getRelocationKind(Type);
615 if (!Kind)
616 return Kind.takeError();
617
618 uint32_t SymbolIndex = Rel.getSymbol(false);
619 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
620 if (!ObjSymbol)
621 return ObjSymbol.takeError();
622
623 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
624 if (!GraphSymbol)
626 formatv("Could not find symbol at given index, did you add it to "
627 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
628 SymbolIndex, (*ObjSymbol)->st_shndx,
629 Base::GraphSymbols.size()),
631
632 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
633 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
634 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
635 LLVM_DEBUG({
636 dbgs() << " ";
637 printEdge(dbgs(), BlockToFix, GE, loongarch::getEdgeKindName(*Kind));
638 dbgs() << "\n";
639 });
640
641 BlockToFix.addEdge(std::move(GE));
642
643 return Error::success();
644 }
645
646public:
647 ELFLinkGraphBuilder_loongarch(StringRef FileName,
648 const object::ELFFile<ELFT> &Obj,
649 std::shared_ptr<orc::SymbolStringPool> SSP,
650 Triple TT, SubtargetFeatures Features)
651 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
652 std::move(Features), FileName,
654};
655
656Error buildTables_ELF_loongarch(LinkGraph &G) {
657 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
658
659 GOTTableManager GOT;
660 PLTTableManager PLT(GOT);
661 visitExistingEdges(G, GOT, PLT);
662 return Error::success();
663}
664
665} // namespace
666
667namespace llvm {
668namespace jitlink {
669
671 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
672 LLVM_DEBUG({
673 dbgs() << "Building jitlink graph for new input "
674 << ObjectBuffer.getBufferIdentifier() << "...\n";
675 });
676
677 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
678 if (!ELFObj)
679 return ELFObj.takeError();
680
681 auto Features = (*ELFObj)->getFeatures();
682 if (!Features)
683 return Features.takeError();
684
685 if ((*ELFObj)->getArch() == Triple::loongarch64) {
686 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
687 return ELFLinkGraphBuilder_loongarch<object::ELF64LE>(
688 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
689 std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features))
690 .buildGraph();
691 }
692
693 assert((*ELFObj)->getArch() == Triple::loongarch32 &&
694 "Invalid triple for LoongArch ELF object file");
695 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
696 return ELFLinkGraphBuilder_loongarch<object::ELF32LE>(
697 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
698 (*ELFObj)->makeTriple(), std::move(*Features))
699 .buildGraph();
700}
701
702void link_ELF_loongarch(std::unique_ptr<LinkGraph> G,
703 std::unique_ptr<JITLinkContext> Ctx) {
704 PassConfiguration Config;
705 const Triple &TT = G->getTargetTriple();
706 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
707 // Add eh-frame passes.
708 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
709 Config.PrePrunePasses.push_back(
710 EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64,
712 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
713
714 // Add a mark-live pass.
715 if (auto MarkLive = Ctx->getMarkLivePass(TT))
716 Config.PrePrunePasses.push_back(std::move(MarkLive));
717 else
718 Config.PrePrunePasses.push_back(markAllSymbolsLive);
719
720 // Add an in-place GOT/PLTStubs build pass.
721 Config.PostPrunePasses.push_back(buildTables_ELF_loongarch);
722
723 // Add a linker relaxation pass.
724 Config.PostAllocationPasses.push_back(relax);
725 }
726
727 if (auto Err = Ctx->modifyPassConfig(*G, Config))
728 return Ctx->notifyFailed(std::move(Err));
729
730 ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config));
731}
732
734
735} // namespace jitlink
736} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
#define LLVM_DEBUG(...)
Definition Debug.h:114
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
Definition ArrayRef.h:186
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
StringRef getBufferIdentifier() const
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Manages the enabling and disabling of subtarget specific features.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
@ loongarch32
Definition Triple.h:64
@ loongarch64
Definition Triple.h:65
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
LLVM Value Representation.
Definition Value.h:75
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Represents an address in the executor process.
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ EM_LOONGARCH
Definition ELF.h:327
LLVM_ABI StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type)
Definition ELF.cpp:25
uint64_t read64le(const void *P)
Definition Endian.h:435
uint16_t read16le(const void *P)
Definition Endian.h:429
uint32_t read32le(const void *P)
Definition Endian.h:432
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:165
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2530
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
uint64_t decodeULEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a ULEB128 value.
Definition LEB128.h:130
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:337
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1634
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
Definition MathExtras.h:182
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition LEB128.h:79
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
Definition MathExtras.h:572
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39