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)) {
42 [this](LinkGraph &G) { return gatherLoongArchPCAddHi20(G); });
43 }
44
45private:
47 RelPCAddHi20Map;
48
49 Error gatherLoongArchPCAddHi20(LinkGraph &G) {
50 for (Block *B : G.blocks())
51 for (Edge &E : B->edges())
52 if (E.getKind() == PCAddHi20)
53 RelPCAddHi20Map[{B, E.getOffset()}] = &E;
54
55 return Error::success();
56 }
57
58 Expected<const Edge &> getLoongArchPCAddHi20(const Edge &E) const {
59 using namespace loongarch;
60 assert((E.getKind() == PCAddLo12) &&
61 "Can only have high relocation for PCAddLo12");
62
63 const Symbol &Sym = E.getTarget();
64 const Block &B = Sym.getBlock();
65 orc::ExecutorAddrDiff Offset = Sym.getOffset() + E.getAddend();
66
67 auto It = RelPCAddHi20Map.find({&B, Offset});
68 if (It != RelPCAddHi20Map.end())
69 return *It->second;
70
71 return make_error<JITLinkError>("No PCAddHi20 relocation type be found "
72 "for PCAddLo12 relocation type");
73 }
74
75 /// Apply fixup expression for edge to block content.
76 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
77 using namespace support;
78
79 char *BlockWorkingMem = B.getAlreadyMutableContent().data();
80 char *FixupPtr = BlockWorkingMem + E.getOffset();
81 uint64_t FixupAddress = (B.getAddress() + E.getOffset()).getValue();
82 uint64_t TargetAddress = E.getTarget().getAddress().getValue();
83 int64_t Addend = E.getAddend();
84
85 switch (E.getKind()) {
86 case Pointer64:
87 *(ulittle64_t *)FixupPtr = TargetAddress + Addend;
88 break;
89 case Pointer32: {
90 uint64_t Value = TargetAddress + Addend;
91 if (Value > std::numeric_limits<uint32_t>::max())
93 *(ulittle32_t *)FixupPtr = Value;
94 break;
95 }
96 case Branch16PCRel: {
97 int64_t Value = TargetAddress - FixupAddress + Addend;
98
99 if (!isInt<18>(Value))
100 return makeTargetOutOfRangeError(G, B, E);
101
103 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
104
105 uint32_t RawInstr = *(little32_t *)FixupPtr;
106 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
107 uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
108 *(little32_t *)FixupPtr = RawInstr | Imm15_0;
109 break;
110 }
111 case Branch21PCRel: {
112 int64_t Value = TargetAddress - FixupAddress + Addend;
113
114 if (!isInt<23>(Value))
115 return makeTargetOutOfRangeError(G, B, E);
116
118 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
119
120 uint32_t RawInstr = *(little32_t *)FixupPtr;
121 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
122 uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
123 uint32_t Imm20_16 = extractBits(Imm, /*Hi=*/20, /*Lo=*/16);
124 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16;
125 break;
126 }
127 case Branch26PCRel: {
128 int64_t Value = TargetAddress - FixupAddress + Addend;
129
130 if (!isInt<28>(Value))
131 return makeTargetOutOfRangeError(G, B, E);
132
134 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
135
136 uint32_t RawInstr = *(little32_t *)FixupPtr;
137 uint32_t Imm = static_cast<uint32_t>(Value >> 2);
138 uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
139 uint32_t Imm25_16 = extractBits(Imm, /*Hi=*/25, /*Lo=*/16);
140 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm25_16;
141 break;
142 }
143 case Delta32: {
144 int64_t Value = TargetAddress - FixupAddress + Addend;
145
146 if (!isInt<32>(Value))
147 return makeTargetOutOfRangeError(G, B, E);
148 *(little32_t *)FixupPtr = Value;
149 break;
150 }
151 case NegDelta32: {
152 int64_t Value = FixupAddress - TargetAddress + Addend;
153 if (!isInt<32>(Value))
154 return makeTargetOutOfRangeError(G, B, E);
155 *(little32_t *)FixupPtr = Value;
156 break;
157 }
158 case Delta64:
159 *(little64_t *)FixupPtr = TargetAddress - FixupAddress + Addend;
160 break;
161 case Page20: {
162 uint64_t Target = TargetAddress + Addend;
163 uint64_t TargetPage =
164 (Target + (Target & 0x800)) & ~static_cast<uint64_t>(0xfff);
165 uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(0xfff);
166
167 int64_t PageDelta = TargetPage - PCPage;
168 if (!isInt<32>(PageDelta))
169 return makeTargetOutOfRangeError(G, B, E);
170
171 uint32_t RawInstr = *(little32_t *)FixupPtr;
172 uint32_t Imm31_12 = extractBits(PageDelta, /*Hi=*/31, /*Lo=*/12) << 5;
173 *(little32_t *)FixupPtr = RawInstr | Imm31_12;
174 break;
175 }
176 case PageOffset12: {
177 uint64_t TargetOffset = (TargetAddress + Addend) & 0xfff;
178
179 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
180 uint32_t Imm11_0 = TargetOffset << 10;
181 *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0;
182 break;
183 }
184 case PCAddHi20: {
185 uint64_t Target = TargetAddress + Addend;
186 int64_t Delta = Target - FixupAddress + 0x800;
187
188 if (!isInt<32>(Delta))
189 return makeTargetOutOfRangeError(G, B, E);
190
191 uint32_t RawInstr = *(little32_t *)FixupPtr;
192 uint32_t Imm31_12 = extractBits(Delta, /*Hi=*/31, /*Lo=*/12) << 5;
193 *(little32_t *)FixupPtr = RawInstr | Imm31_12;
194 break;
195 }
196 case PCAddLo12: {
197 auto RelPCAddHi20 = getLoongArchPCAddHi20(E);
198 if (!RelPCAddHi20)
199 return RelPCAddHi20.takeError();
200 int64_t Delta =
201 (RelPCAddHi20->getTarget().getAddress() + RelPCAddHi20->getAddend()) -
202 (E.getTarget().getAddress() + E.getAddend());
203
204 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
205 uint32_t Imm11_0 = extractBits(Delta, /*Hi=*/11, /*Lo=*/0) << 10;
206 *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0;
207 break;
208 }
209 case Call30PCRel: {
210 int64_t Value = TargetAddress - FixupAddress + Addend;
211
212 if (Value != llvm::SignExtend64(Value, 32))
213 return makeTargetOutOfRangeError(G, B, E);
214
216 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
217
218 uint32_t Pcaddu12i = *(little32_t *)FixupPtr;
219 uint32_t Hi20 = extractBits(Value, /*Hi=*/31, /*Lo=*/12) << 5;
220 *(little32_t *)FixupPtr = Pcaddu12i | Hi20;
221 uint32_t Jirl = *(little32_t *)(FixupPtr + 4);
222 uint32_t Lo10 = extractBits(Value, /*Hi=*/11, /*Lo=*/2) << 10;
223 *(little32_t *)(FixupPtr + 4) = Jirl | Lo10;
224 break;
225 }
226 case Call36PCRel: {
227 int64_t Value = TargetAddress - FixupAddress + Addend;
228
229 if ((Value + 0x20000) != llvm::SignExtend64(Value + 0x20000, 38))
230 return makeTargetOutOfRangeError(G, B, E);
231
233 return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
234
235 uint32_t Pcaddu18i = *(little32_t *)FixupPtr;
236 uint32_t Hi20 = extractBits(Value + (1 << 17), /*Hi=*/37, /*Lo=*/18) << 5;
237 *(little32_t *)FixupPtr = Pcaddu18i | Hi20;
238 uint32_t Jirl = *(little32_t *)(FixupPtr + 4);
239 uint32_t Lo16 = extractBits(Value, /*Hi=*/17, /*Lo=*/2) << 10;
240 *(little32_t *)(FixupPtr + 4) = Jirl | Lo16;
241 break;
242 }
243 case Add6: {
244 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr));
245 Value += ((TargetAddress + Addend) & 0x3f);
246 *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f);
247 break;
248 }
249 case Add8: {
250 int64_t Value = TargetAddress +
251 *(reinterpret_cast<const int8_t *>(FixupPtr)) + Addend;
252 *FixupPtr = static_cast<int8_t>(Value);
253 break;
254 }
255 case Add16: {
256 int64_t Value =
257 TargetAddress + support::endian::read16le(FixupPtr) + Addend;
258 *(little16_t *)FixupPtr = static_cast<int16_t>(Value);
259 break;
260 }
261 case Add32: {
262 int64_t Value =
263 TargetAddress + support::endian::read32le(FixupPtr) + Addend;
264 *(little32_t *)FixupPtr = static_cast<int32_t>(Value);
265 break;
266 }
267 case Add64: {
268 int64_t Value =
269 TargetAddress + support::endian::read64le(FixupPtr) + Addend;
270 *(little64_t *)FixupPtr = static_cast<int64_t>(Value);
271 break;
272 }
273 case AddUleb128: {
274 const uint32_t Maxcount = 1 + 64 / 7;
276 const char *Error = nullptr;
277 uint64_t Orig =
278 decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)), &Count,
279 nullptr, &Error);
280
281 if (Count > Maxcount || (Count == Maxcount && Error))
283 "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) +
284 ": extra space for uleb128");
285
286 uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL;
287 encodeULEB128((Orig + TargetAddress + Addend) & Mask,
288 (reinterpret_cast<uint8_t *>(FixupPtr)), Count);
289 break;
290 }
291 case Sub6: {
292 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr));
293 Value -= ((TargetAddress + Addend) & 0x3f);
294 *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<int8_t>(Value) & 0x3f);
295 break;
296 }
297 case Sub8: {
298 int64_t Value = *(reinterpret_cast<const int8_t *>(FixupPtr)) -
299 TargetAddress - Addend;
300 *FixupPtr = static_cast<int8_t>(Value);
301 break;
302 }
303 case Sub16: {
304 int64_t Value =
305 support::endian::read16le(FixupPtr) - TargetAddress - Addend;
306 *(little16_t *)FixupPtr = static_cast<int16_t>(Value);
307 break;
308 }
309 case Sub32: {
310 int64_t Value =
311 support::endian::read32le(FixupPtr) - TargetAddress - Addend;
312 *(little32_t *)FixupPtr = static_cast<int32_t>(Value);
313 break;
314 }
315 case Sub64: {
316 int64_t Value =
317 support::endian::read64le(FixupPtr) - TargetAddress - Addend;
318 *(little64_t *)FixupPtr = static_cast<int64_t>(Value);
319 break;
320 }
321 case SubUleb128: {
322 const uint32_t Maxcount = 1 + 64 / 7;
324 const char *Error = nullptr;
325 uint64_t Orig =
326 decodeULEB128((reinterpret_cast<const uint8_t *>(FixupPtr)), &Count,
327 nullptr, &Error);
328
329 if (Count > Maxcount || (Count == Maxcount && Error))
331 "0x" + llvm::utohexstr(orc::ExecutorAddr(FixupAddress).getValue()) +
332 ": extra space for uleb128");
333
334 uint64_t Mask = Count < Maxcount ? (1ULL << 7 * Count) - 1 : -1ULL;
335 encodeULEB128((Orig - TargetAddress - Addend) & Mask,
336 (reinterpret_cast<uint8_t *>(FixupPtr)), Count);
337 break;
338 }
339 case AlignRelaxable:
340 // Ignore when the relaxation pass did not run
341 break;
342 default:
344 "In graph " + G.getName() + ", section " + B.getSection().getName() +
345 " unsupported edge kind " + getEdgeKindName(E.getKind()));
346 }
347
348 return Error::success();
349 }
350};
351
352namespace {
353
354struct SymbolAnchor {
356 Symbol *Sym;
357 bool End; // true for the anchor of getOffset() + getSize()
358};
359
360struct BlockRelaxAux {
361 // This records symbol start and end offsets which will be adjusted according
362 // to the nearest RelocDeltas element.
364 // All edges that either 1) are R_LARCH_ALIGN or 2) have a R_LARCH_RELAX edge
365 // at the same offset.
366 SmallVector<Edge *, 0> RelaxEdges;
367 // For RelaxEdges[I], the actual offset is RelaxEdges[I]->getOffset() - (I ?
368 // RelocDeltas[I - 1] : 0).
369 SmallVector<uint32_t, 0> RelocDeltas;
370 // For RelaxEdges[I], the actual type is EdgeKinds[I].
372 // List of rewritten instructions. Contains one raw encoded instruction per
373 // element in EdgeKinds that isn't Invalid or R_LARCH_ALIGN.
375};
376
377struct RelaxAux {
379};
380
381} // namespace
382
383static bool shouldRelax(const Section &S) {
385}
386
387static bool isRelaxable(const Edge &E) {
388 switch (E.getKind()) {
389 default:
390 return false;
391 case AlignRelaxable:
392 return true;
393 }
394}
395
396static RelaxAux initRelaxAux(LinkGraph &G) {
397 RelaxAux Aux;
398 for (auto &S : G.sections()) {
399 if (!shouldRelax(S))
400 continue;
401 for (auto *B : S.blocks()) {
402 auto BlockEmplaceResult = Aux.Blocks.try_emplace(B);
403 assert(BlockEmplaceResult.second && "Block encountered twice");
404 auto &BlockAux = BlockEmplaceResult.first->second;
405
406 for (auto &E : B->edges())
407 if (isRelaxable(E))
408 BlockAux.RelaxEdges.push_back(&E);
409
410 if (BlockAux.RelaxEdges.empty()) {
411 Aux.Blocks.erase(BlockEmplaceResult.first);
412 continue;
413 }
414
415 const auto NumEdges = BlockAux.RelaxEdges.size();
416 BlockAux.RelocDeltas.resize(NumEdges, 0);
417 BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);
418
419 // Store anchors (offset and offset+size) for symbols.
420 for (auto *Sym : S.symbols()) {
421 if (!Sym->isDefined() || &Sym->getBlock() != B)
422 continue;
423
424 BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false});
425 BlockAux.Anchors.push_back(
426 {Sym->getOffset() + Sym->getSize(), Sym, true});
427 }
428 }
429 }
430
431 // Sort anchors by offset so that we can find the closest relocation
432 // efficiently. For a zero size symbol, ensure that its start anchor precedes
433 // its end anchor. For two symbols with anchors at the same offset, their
434 // order does not matter.
435 for (auto &BlockAuxIter : Aux.Blocks) {
436 llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) {
437 return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End);
438 });
439 }
440
441 return Aux;
442}
443
444static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove,
445 Edge::Kind &NewEdgeKind) {
446 const uint64_t Addend =
447 !E.getTarget().isDefined() ? Log2_64(E.getAddend()) + 1 : E.getAddend();
448 const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4;
449 const uint64_t Align = 1ULL << (Addend & 0xff);
450 const uint64_t MaxBytes = Addend >> 8;
451 const uint64_t Off = Loc.getValue() & (Align - 1);
452 const uint64_t CurBytes = Off == 0 ? 0 : Align - Off;
453 // All bytes beyond the alignment boundary should be removed.
454 // If emit bytes more than max bytes to emit, remove all.
455 if (MaxBytes != 0 && CurBytes > MaxBytes)
456 Remove = AllBytes;
457 else
458 Remove = AllBytes - CurBytes;
459
460 assert(static_cast<int32_t>(Remove) >= 0 &&
461 "R_LARCH_ALIGN needs expanding the content");
462 NewEdgeKind = AlignRelaxable;
463}
464
465static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) {
466 const auto BlockAddr = Block.getAddress();
467 bool Changed = false;
468 ArrayRef<SymbolAnchor> SA = ArrayRef(Aux.Anchors);
469 uint32_t Delta = 0;
470
471 Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);
472 Aux.Writes.clear();
473
474 for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) {
475 const auto Loc = BlockAddr + E->getOffset() - Delta;
476 auto &Cur = Aux.RelocDeltas[I];
477 uint32_t Remove = 0;
478 switch (E->getKind()) {
479 case AlignRelaxable:
480 relaxAlign(Loc, *E, Remove, Aux.EdgeKinds[I]);
481 break;
482 default:
483 llvm_unreachable("Unexpected relaxable edge kind");
484 }
485
486 // For all anchors whose offsets are <= E->getOffset(), they are preceded by
487 // the previous relocation whose RelocDeltas value equals Delta.
488 // Decrease their offset and update their size.
489 for (; SA.size() && SA[0].Offset <= E->getOffset(); SA = SA.slice(1)) {
490 if (SA[0].End)
491 SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset());
492 else
493 SA[0].Sym->setOffset(SA[0].Offset - Delta);
494 }
495
496 Delta += Remove;
497 if (Delta != Cur) {
498 Cur = Delta;
499 Changed = true;
500 }
501 }
502
503 for (const SymbolAnchor &A : SA) {
504 if (A.End)
505 A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset());
506 else
507 A.Sym->setOffset(A.Offset - Delta);
508 }
509
510 return Changed;
511}
512
513static bool relaxOnce(LinkGraph &G, RelaxAux &Aux) {
514 bool Changed = false;
515
516 for (auto &[B, BlockAux] : Aux.Blocks)
517 Changed |= relaxBlock(G, *B, BlockAux);
518
519 return Changed;
520}
521
522static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) {
523 auto Contents = Block.getAlreadyMutableContent();
524 auto *Dest = Contents.data();
525 uint32_t Offset = 0;
526 uint32_t Delta = 0;
527
528 // Update section content: remove NOPs for R_LARCH_ALIGN and rewrite
529 // instructions for relaxed relocations.
530 for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) {
531 uint32_t Remove = Aux.RelocDeltas[I] - Delta;
532 Delta = Aux.RelocDeltas[I];
533 if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid)
534 continue;
535
536 // Copy from last location to the current relocated location.
537 const auto Size = E->getOffset() - Offset;
538 std::memmove(Dest, Contents.data() + Offset, Size);
539 Dest += Size;
540 Offset = E->getOffset() + Remove;
541 }
542
543 std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset);
544
545 // Fixup edge offsets and kinds.
546 Delta = 0;
547 size_t I = 0;
548 for (auto &E : Block.edges()) {
549 E.setOffset(E.getOffset() - Delta);
550
551 if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) {
552 if (Aux.EdgeKinds[I] != Edge::Invalid)
553 E.setKind(Aux.EdgeKinds[I]);
554
555 Delta = Aux.RelocDeltas[I];
556 ++I;
557 }
558 }
559
560 // Remove AlignRelaxable edges: all other relaxable edges got modified and
561 // will be used later while linking. Alignment is entirely handled here so we
562 // don't need these edges anymore.
563 for (auto IE = Block.edges().begin(); IE != Block.edges().end();) {
564 if (IE->getKind() == AlignRelaxable)
565 IE = Block.removeEdge(IE);
566 else
567 ++IE;
568 }
569}
570
571static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) {
572 for (auto &[B, BlockAux] : Aux.Blocks)
573 finalizeBlockRelax(G, *B, BlockAux);
574}
575
576static Error relax(LinkGraph &G) {
577 auto Aux = initRelaxAux(G);
578 while (relaxOnce(G, Aux)) {
579 }
580 finalizeRelax(G, Aux);
581 return Error::success();
582}
583
584template <typename ELFT>
585class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> {
586private:
588 getRelocationKind(const uint32_t Type) {
589 using namespace loongarch;
590 switch (Type) {
591 case ELF::R_LARCH_64:
592 return Pointer64;
593 case ELF::R_LARCH_32:
594 return Pointer32;
595 case ELF::R_LARCH_32_PCREL:
596 return Delta32;
597 case ELF::R_LARCH_B16:
598 return Branch16PCRel;
599 case ELF::R_LARCH_B21:
600 return Branch21PCRel;
601 case ELF::R_LARCH_B26:
602 return Branch26PCRel;
603 case ELF::R_LARCH_PCALA_HI20:
604 return Page20;
605 case ELF::R_LARCH_PCALA_LO12:
606 return PageOffset12;
607 case ELF::R_LARCH_GOT_PC_HI20:
609 case ELF::R_LARCH_GOT_PC_LO12:
611 case ELF::R_LARCH_CALL30:
612 return Call30PCRel;
613 case ELF::R_LARCH_CALL36:
614 return Call36PCRel;
615 case ELF::R_LARCH_ADD6:
616 return Add6;
617 case ELF::R_LARCH_ADD8:
618 return Add8;
619 case ELF::R_LARCH_ADD16:
620 return Add16;
621 case ELF::R_LARCH_ADD32:
622 return Add32;
623 case ELF::R_LARCH_ADD64:
624 return Add64;
625 case ELF::R_LARCH_ADD_ULEB128:
626 return AddUleb128;
627 case ELF::R_LARCH_SUB6:
628 return Sub6;
629 case ELF::R_LARCH_SUB8:
630 return Sub8;
631 case ELF::R_LARCH_SUB16:
632 return Sub16;
633 case ELF::R_LARCH_SUB32:
634 return Sub32;
635 case ELF::R_LARCH_SUB64:
636 return Sub64;
637 case ELF::R_LARCH_SUB_ULEB128:
638 return SubUleb128;
639 case ELF::R_LARCH_ALIGN:
640 return AlignRelaxable;
641 case ELF::R_LARCH_PCADD_HI20:
642 return PCAddHi20;
643 case ELF::R_LARCH_PCADD_LO12:
644 case ELF::R_LARCH_GOT_PCADD_LO12:
645 return PCAddLo12;
646 case ELF::R_LARCH_GOT_PCADD_HI20:
648 }
649
651 "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) +
653 }
654
655 EdgeKind_loongarch getRelaxableRelocationKind(EdgeKind_loongarch Kind) {
656 // TODO: Implement more. Just ignore all relaxations now.
657 return Kind;
658 }
659
660 Error addRelocations() override {
661 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
662
664 using Self = ELFLinkGraphBuilder_loongarch<ELFT>;
665 for (const auto &RelSect : Base::Sections)
666 if (Error Err = Base::forEachRelaRelocation(RelSect, this,
667 &Self::addSingleRelocation))
668 return Err;
669
670 return Error::success();
671 }
672
673 Error addSingleRelocation(const typename ELFT::Rela &Rel,
674 const typename ELFT::Shdr &FixupSect,
675 Block &BlockToFix) {
677
678 uint32_t Type = Rel.getType(false);
679 int64_t Addend = Rel.r_addend;
680
681 // ignore
682 if (Type == ELF::R_LARCH_MARK_LA)
683 return Error::success();
684
685 if (Type == ELF::R_LARCH_RELAX) {
686 if (BlockToFix.edges_empty())
688 "R_LARCH_RELAX without preceding relocation",
690
691 auto &PrevEdge = *std::prev(BlockToFix.edges().end());
692 auto Kind = static_cast<EdgeKind_loongarch>(PrevEdge.getKind());
693 PrevEdge.setKind(getRelaxableRelocationKind(Kind));
694 return Error::success();
695 }
696
697 Expected<loongarch::EdgeKind_loongarch> Kind = getRelocationKind(Type);
698 if (!Kind)
699 return Kind.takeError();
700
701 uint32_t SymbolIndex = Rel.getSymbol(false);
702 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
703 if (!ObjSymbol)
704 return ObjSymbol.takeError();
705
706 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
707 if (!GraphSymbol)
709 formatv("Could not find symbol at given index, did you add it to "
710 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
711 SymbolIndex, (*ObjSymbol)->st_shndx,
712 Base::GraphSymbols.size()),
714
715 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
716 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
717 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
718 LLVM_DEBUG({
719 dbgs() << " ";
720 printEdge(dbgs(), BlockToFix, GE, loongarch::getEdgeKindName(*Kind));
721 dbgs() << "\n";
722 });
723
724 BlockToFix.addEdge(std::move(GE));
725
726 return Error::success();
727 }
728
729public:
730 ELFLinkGraphBuilder_loongarch(StringRef FileName,
731 const object::ELFFile<ELFT> &Obj,
732 std::shared_ptr<orc::SymbolStringPool> SSP,
733 Triple TT, SubtargetFeatures Features)
734 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
735 std::move(Features), FileName,
737};
738
739Error buildTables_ELF_loongarch(LinkGraph &G) {
740 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
741
742 GOTTableManager GOT;
743 PLTTableManager PLT(GOT);
744 visitExistingEdges(G, GOT, PLT);
745 return Error::success();
746}
747
748} // namespace
749
750namespace llvm {
751namespace jitlink {
752
754 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
755 LLVM_DEBUG({
756 dbgs() << "Building jitlink graph for new input "
757 << ObjectBuffer.getBufferIdentifier() << "...\n";
758 });
759
760 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
761 if (!ELFObj)
762 return ELFObj.takeError();
763
764 auto Features = (*ELFObj)->getFeatures();
765 if (!Features)
766 return Features.takeError();
767
768 if ((*ELFObj)->getArch() == Triple::loongarch64) {
769 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
770 return ELFLinkGraphBuilder_loongarch<object::ELF64LE>(
771 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
772 std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features))
773 .buildGraph();
774 }
775
776 assert((*ELFObj)->getArch() == Triple::loongarch32 &&
777 "Invalid triple for LoongArch ELF object file");
778 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
779 return ELFLinkGraphBuilder_loongarch<object::ELF32LE>(
780 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
781 (*ELFObj)->makeTriple(), std::move(*Features))
782 .buildGraph();
783}
784
785void link_ELF_loongarch(std::unique_ptr<LinkGraph> G,
786 std::unique_ptr<JITLinkContext> Ctx) {
787 PassConfiguration Config;
788 const Triple &TT = G->getTargetTriple();
789 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
790 // Add eh-frame passes.
791 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
792 Config.PrePrunePasses.push_back(
793 EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64,
795 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
796
797 // Add a mark-live pass.
798 if (auto MarkLive = Ctx->getMarkLivePass(TT))
799 Config.PrePrunePasses.push_back(std::move(MarkLive));
800 else
801 Config.PrePrunePasses.push_back(markAllSymbolsLive);
802
803 // Add an in-place GOT/PLTStubs build pass.
804 Config.PostPrunePasses.push_back(buildTables_ELF_loongarch);
805
806 // Add a linker relaxation pass.
807 Config.PostAllocationPasses.push_back(relax);
808 }
809
810 if (auto Err = Ctx->modifyPassConfig(*G, Config))
811 return Ctx->notifyFailed(std::move(Err));
812
813 ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config));
814}
815
817
818} // namespace jitlink
819} // 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
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:178
iterator end()
Definition DenseMap.h:81
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 ExecutorAddrDiff
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:2544
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:94
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