LLVM: lib/ExecutionEngine/JITLink/ELF_loongarch.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
20
24
25#define DEBUG_TYPE "jitlink"
26
27using namespace llvm;
30
31namespace {
32
33class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> {
34 friend class JITLinker<ELFJITLinker_loongarch>;
35
36public:
37 ELFJITLinker_loongarch(std::unique_ptr Ctx,
38 std::unique_ptr G,
40 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
41
42private:
45 }
46};
47
48namespace {
49
50struct SymbolAnchor {
53 bool End;
54};
55
56struct BlockRelaxAux {
57
58
60
61
63
64
66
68
69
71};
72
73struct RelaxAux {
75};
76
77}
78
81}
82
84 switch (E.getKind()) {
85 default:
86 return false;
88 return true;
89 }
90}
91
93 RelaxAux Aux;
94 for (auto &S : G.sections()) {
96 continue;
97 for (auto *B : S.blocks()) {
98 auto BlockEmplaceResult = Aux.Blocks.try_emplace(B);
99 assert(BlockEmplaceResult.second && "Block encountered twice");
100 auto &BlockAux = BlockEmplaceResult.first->second;
101
102 for (auto &E : B->edges())
104 BlockAux.RelaxEdges.push_back(&E);
105
106 if (BlockAux.RelaxEdges.empty()) {
107 Aux.Blocks.erase(BlockEmplaceResult.first);
108 continue;
109 }
110
111 const auto NumEdges = BlockAux.RelaxEdges.size();
112 BlockAux.RelocDeltas.resize(NumEdges, 0);
113 BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);
114
115
116 for (auto *Sym : S.symbols()) {
117 if (!Sym->isDefined() || &Sym->getBlock() != B)
118 continue;
119
120 BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false});
121 BlockAux.Anchors.push_back(
122 {Sym->getOffset() + Sym->getSize(), Sym, true});
123 }
124 }
125 }
126
127
128
129
130
131 for (auto &BlockAuxIter : Aux.Blocks) {
132 llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) {
133 return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End);
134 });
135 }
136
137 return Aux;
138}
139
141 Edge::Kind &NewEdgeKind) {
143 .getTarget().isDefined() ? Log2_64(E.getAddend()) + 1 : E.getAddend();
144 const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4;
146 const uint64_t MaxBytes = Addend >> 8;
148 const uint64_t CurBytes = Off == 0 ? 0 : Align - Off;
149
150
151 if (MaxBytes != 0 && CurBytes > MaxBytes)
152 Remove = AllBytes;
153 else
154 Remove = AllBytes - CurBytes;
155
156 assert(static_cast<int32_t>(Remove) >= 0 &&
157 "R_LARCH_ALIGN needs expanding the content");
159}
160
166
167 Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);
168 Aux.Writes.clear();
169
171 const auto Loc = BlockAddr + E->getOffset() - Delta;
172 auto &Cur = Aux.RelocDeltas[I];
174 switch (E->getKind()) {
177 break;
178 default:
180 }
181
182
183
184
186 if (SA[0].End)
187 SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset());
188 else
189 SA[0].Sym->setOffset(SA[0].Offset - Delta);
190 }
191
192 Delta += Remove;
193 if (Delta != Cur) {
194 Cur = Delta;
196 }
197 }
198
199 for (const SymbolAnchor &A : SA) {
200 if (A.End)
201 A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset());
202 else
203 A.Sym->setOffset(A.Offset - Delta);
204 }
205
207}
208
211
212 for (auto &[B, BlockAux] : Aux.Blocks)
214
216}
217
220 auto *Dest = Contents.data();
223
224
225
227 uint32_t Remove = Aux.RelocDeltas[I] - Delta;
228 Delta = Aux.RelocDeltas[I];
229 if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid)
230 continue;
231
232
233 const auto Size = E->getOffset() - Offset;
234 std::memmove(Dest, Contents.data() + Offset, Size);
235 Dest += Size;
236 Offset = E->getOffset() + Remove;
237 }
238
239 std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset);
240
241
242 Delta = 0;
243 size_t I = 0;
245 E.setOffset(E.getOffset() - Delta);
246
247 if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) {
248 if (Aux.EdgeKinds[I] != Edge::Invalid)
249 E.setKind(Aux.EdgeKinds[I]);
250
251 Delta = Aux.RelocDeltas[I];
252 ++I;
253 }
254 }
255
256
257
258
262 else
263 ++IE;
264 }
265}
266
268 for (auto &[B, BlockAux] : Aux.Blocks)
270}
271
275 }
278}
279
280template
282private:
286 switch (Type) {
287 case ELF::R_LARCH_64:
289 case ELF::R_LARCH_32:
291 case ELF::R_LARCH_32_PCREL:
293 case ELF::R_LARCH_B16:
295 case ELF::R_LARCH_B21:
297 case ELF::R_LARCH_B26:
299 case ELF::R_LARCH_PCALA_HI20:
301 case ELF::R_LARCH_PCALA_LO12:
303 case ELF::R_LARCH_GOT_PC_HI20:
305 case ELF::R_LARCH_GOT_PC_LO12:
307 case ELF::R_LARCH_CALL36:
309 case ELF::R_LARCH_ADD6:
311 case ELF::R_LARCH_ADD8:
313 case ELF::R_LARCH_ADD16:
315 case ELF::R_LARCH_ADD32:
317 case ELF::R_LARCH_ADD64:
319 case ELF::R_LARCH_ADD_ULEB128:
321 case ELF::R_LARCH_SUB6:
323 case ELF::R_LARCH_SUB8:
325 case ELF::R_LARCH_SUB16:
327 case ELF::R_LARCH_SUB32:
329 case ELF::R_LARCH_SUB64:
331 case ELF::R_LARCH_SUB_ULEB128:
333 case ELF::R_LARCH_ALIGN:
335 }
336
338 "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) +
340 }
341
343
344 return Kind;
345 }
346
347 Error addRelocations() override {
349
351 using Self = ELFLinkGraphBuilder_loongarch;
352 for (const auto &RelSect : Base::Sections)
353 if (Error Err = Base::forEachRelaRelocation(RelSect, this,
354 &Self::addSingleRelocation))
355 return Err;
356
358 }
359
360 Error addSingleRelocation(const typename ELFT::Rela &Rel,
361 const typename ELFT::Shdr &FixupSect,
362 Block &BlockToFix) {
364
366 int64_t Addend = Rel.r_addend;
367
368
369 if (Type == ELF::R_LARCH_MARK_LA)
371
372 if (Type == ELF::R_LARCH_RELAX) {
375 "R_LARCH_RELAX without preceding relocation",
377
378 auto &PrevEdge = *std::prev(BlockToFix.edges().end());
380 PrevEdge.setKind(getRelaxableRelocationKind(Kind));
382 }
383
385 if (!Kind)
386 return Kind.takeError();
387
388 uint32_t SymbolIndex = Rel.getSymbol(false);
389 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
390 if (!ObjSymbol)
391 return ObjSymbol.takeError();
392
393 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
394 if (!GraphSymbol)
396 formatv("Could not find symbol at given index, did you add it to "
397 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
398 SymbolIndex, (*ObjSymbol)->st_shndx,
399 Base::GraphSymbols.size()),
401
402 auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
403 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
404 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
406 dbgs() << " ";
408 dbgs() << "\n";
409 });
410
411 BlockToFix.addEdge(std::move(GE));
412
414 }
415
416public:
417 ELFLinkGraphBuilder_loongarch(StringRef FileName,
419 std::shared_ptrorc::SymbolStringPool SSP,
422 std::move(Features), FileName,
424};
425
428
433}
434
435}
436
437namespace llvm {
439
441 MemoryBufferRef ObjectBuffer, std::shared_ptrorc::SymbolStringPool SSP) {
443 dbgs() << "Building jitlink graph for new input "
445 });
446
448 if (!ELFObj)
449 return ELFObj.takeError();
450
451 auto Features = (*ELFObj)->getFeatures();
452 if (!Features)
453 return Features.takeError();
454
457 return ELFLinkGraphBuilder_loongarchobject::ELF64LE(
458 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
459 std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features))
460 .buildGraph();
461 }
462
464 "Invalid triple for LoongArch ELF object file");
466 return ELFLinkGraphBuilder_loongarchobject::ELF32LE(
467 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
468 (*ELFObj)->makeTriple(), std::move(*Features))
469 .buildGraph();
470}
471
473 std::unique_ptr Ctx) {
475 const Triple &TT = G->getTargetTriple();
476 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
477
483
484
485 if (auto MarkLive = Ctx->getMarkLivePass(TT))
486 Config.PrePrunePasses.push_back(std::move(MarkLive));
487 else
489
490
491 Config.PostPrunePasses.push_back(buildTables_ELF_loongarch);
492
493
495 }
496
497 if (auto Err = Ctx->modifyPassConfig(*G, Config))
498 return Ctx->notifyFailed(std::move(Err));
499
500 ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config));
501}
502
504
505}
506}
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")
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
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.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
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.
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
The instances of the Type class are immutable: once they are created, they are never changed.
orc::ExecutorAddr getAddress() const
An Addressable with content and edges.
edge_iterator removeEdge(edge_iterator I)
Remove the edge pointed to by the given iterator.
void addEdge(Edge::Kind K, Edge::OffsetT Offset, Symbol &Target, Edge::AddendT Addend)
Add an edge to this block.
iterator_range< edge_iterator > edges()
Return the list of edges attached to this content.
MutableArrayRef< char > getAlreadyMutableContent()
Get mutable content for this block.
bool edges_empty() const
Returns true if the list of edges is empty.
A LinkGraph pass that splits blocks in a section that follows the DWARF Record format into sub-blocks...
A LinkGraph pass that adds missing FDE-to-CIE, FDE-to-PC and FDE-to-LSDA edges.
LinkGraph building code that's specific to the given ELFT, but common across all architectures.
Represents fixups and constraints in the LinkGraph.
Represents an object file section.
iterator_range< symbol_iterator > symbols()
Returns an iterator over the symbols defined in this section.
iterator_range< block_iterator > blocks()
Returns an iterator over the blocks defined in this section.
orc::MemProt getMemProt() const
Returns the protection flags for this section.
Global Offset Table Builder.
Procedure Linkage Table Builder.
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Represents an address in the executor process.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI const char * getEdgeKindName(Edge::Kind K)
Returns a string name for the given loongarch edge.
EdgeKind_loongarch
Represents loongarch fixups.
@ Branch16PCRel
A 16-bit PC-relative branch.
@ Add16
16 bits label addition
@ AddUleb128
ULEB128 bits label addition.
@ RequestGOTAndTransformToPage20
A GOT entry getter/constructor, transformed to Page20 pointing at the GOT entry for the original targ...
@ Sub16
16 bits label subtraction
@ NegDelta32
A 32-bit negative delta.
@ SubUleb128
ULEB128 bits label subtraction.
@ Sub8
8 bits label subtraction
@ PageOffset12
The 12-bit offset of the target within its page.
@ Sub32
32 bits label subtraction
@ Add64
64 bits label addition
@ Sub6
low 6 bits label subtraction
@ Add8
8 bits label addition
@ Page20
The signed 20-bit delta from the fixup page to the page containing the target.
@ Pointer64
A plain 64-bit pointer value relocation.
@ RequestGOTAndTransformToPageOffset12
A GOT entry getter/constructor, transformed to Pageoffset12 pointing at the GOT entry for the origina...
@ Call36PCRel
A 36-bit PC-relative call.
@ Add6
low 6 bits label addition
@ Branch21PCRel
A 21-bit PC-relative branch.
@ Branch26PCRel
A 26-bit PC-relative branch.
@ Add32
32 bits label addition
@ Pointer32
A plain 32-bit pointer value relocation.
@ AlignRelaxable
Alignment requirement used by linker relaxation.
@ Sub64
64 bits label subtraction
Error applyFixup(LinkGraph &G, Block &B, const Edge &E)
Apply fixup expression for edge to block content.
unique_function< Error(LinkGraph &)> LinkGraphPassFunction
A function for mutating LinkGraphs.
static bool shouldRelax(const Section &S)
static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux)
static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove, Edge::Kind &NewEdgeKind)
static bool relaxOnce(LinkGraph &G, RelaxAux &Aux)
static Error relax(LinkGraph &G)
static bool isRelaxable(const Edge &E)
void visitExistingEdges(LinkGraph &G, VisitorTs &&...Vs)
For each edge in the given graph, apply a list of visitors to the edge, stopping when the first visit...
LLVM_ABI Error markAllSymbolsLive(LinkGraph &G)
Marks all symbols in a graph live.
LinkGraphPassFunction createRelaxationPass_ELF_loongarch()
Returns a pass that performs linker relaxation.
Definition ELF_loongarch.cpp:503
static RelaxAux initRelaxAux(LinkGraph &G)
Expected< std::unique_ptr< LinkGraph > > createLinkGraphFromELFObject_loongarch(MemoryBufferRef ObjectBuffer, std::shared_ptr< orc::SymbolStringPool > SSP)
Create a LinkGraph from an ELF/loongarch relocatable object.
Definition ELF_loongarch.cpp:440
LLVM_ABI void printEdge(raw_ostream &OS, const Block &B, const Edge &E, StringRef EdgeKindName)
static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux, const RelaxConfig &Config)
void link_ELF_loongarch(std::unique_ptr< LinkGraph > G, std::unique_ptr< JITLinkContext > Ctx)
jit-link the given object buffer, which must be an ELF loongarch object file.
Definition ELF_loongarch.cpp:472
static void finalizeRelax(LinkGraph &G, RelaxAux &Aux)
LLVM_ABI StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type)
This is an optimization pass for GlobalISel generic memory operations.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
This struct is a compact representation of a valid (non-zero power of two) alignment.
An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...
LinkGraphPassList PostAllocationPasses
Post-allocation passes.
LinkGraphPassList PostPrunePasses
Post-prune passes.
LinkGraphPassList PrePrunePasses
Pre-prune passes.