25#define DEBUG_TYPE "jitlink"
33class ELFJITLinker_loongarch :
public JITLinker<ELFJITLinker_loongarch> {
34 friend class JITLinker<ELFJITLinker_loongarch>;
37 ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx,
38 std::unique_ptr<LinkGraph>
G,
40 :
JITLinker(std::move(Ctx), std::move(
G), std::move(PassConfig)) {}
80 return (S.
getMemProt() & orc::MemProt::Exec) != orc::MemProt::None;
94 for (
auto &S :
G.sections()) {
98 auto BlockEmplaceResult = Aux.Blocks.try_emplace(
B);
99 assert(BlockEmplaceResult.second &&
"Block encountered twice");
100 auto &BlockAux = BlockEmplaceResult.first->second;
102 for (
auto &E :
B->edges())
104 BlockAux.RelaxEdges.push_back(&E);
106 if (BlockAux.RelaxEdges.empty()) {
107 Aux.Blocks.erase(BlockEmplaceResult.first);
111 const auto NumEdges = BlockAux.RelaxEdges.size();
112 BlockAux.RelocDeltas.resize(NumEdges, 0);
113 BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);
121 BlockAux.Anchors.push_back(
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);
144 const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4;
146 const uint64_t MaxBytes = Addend >> 8;
151 if (MaxBytes != 0 && CurBytes > MaxBytes)
154 Remove = AllBytes - CurBytes;
156 assert(
static_cast<int32_t
>(Remove) >= 0 &&
157 "R_LARCH_ALIGN needs expanding the content");
163 bool Changed =
false;
167 Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);
171 const auto Loc = BlockAddr + E->
getOffset() - Delta;
172 auto &Cur = Aux.RelocDeltas[
I];
189 SA[0].Sym->setOffset(SA[0].
Offset - Delta);
199 for (
const SymbolAnchor &
A : SA) {
201 A.Sym->setSize(
A.Offset - Delta -
A.Sym->getOffset());
203 A.Sym->setOffset(
A.Offset - Delta);
210 bool Changed =
false;
212 for (
auto &[
B, BlockAux] : Aux.Blocks)
220 auto *Dest = Contents.
data();
227 uint32_t Remove = Aux.RelocDeltas[
I] - Delta;
228 Delta = Aux.RelocDeltas[
I];
229 if (Remove == 0 && Aux.EdgeKinds[
I] == Edge::Invalid)
234 std::memmove(Dest, Contents.data() +
Offset,
Size);
239 std::memmove(Dest, Contents.data() +
Offset, Contents.size() -
Offset);
247 if (
I < Aux.RelaxEdges.size() && Aux.RelaxEdges[
I] == &E) {
248 if (Aux.EdgeKinds[
I] != Edge::Invalid)
251 Delta = Aux.RelocDeltas[
I];
268 for (
auto &[
B, BlockAux] : Aux.Blocks)
280template <
typename ELFT>
285 using namespace loongarch;
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:
337 return make_error<JITLinkError>(
338 "Unsupported loongarch relocation:" +
formatv(
"{0:d}: ",
Type) +
351 using Self = ELFLinkGraphBuilder_loongarch<ELFT>;
352 for (
const auto &RelSect : Base::Sections)
353 if (
Error Err = Base::forEachRelaRelocation(RelSect,
this,
354 &Self::addSingleRelocation))
360 Error addSingleRelocation(
const typename ELFT::Rela &Rel,
361 const typename ELFT::Shdr &FixupSect,
366 int64_t Addend = Rel.r_addend;
368 if (
Type == ELF::R_LARCH_RELAX) {
370 return make_error<StringError>(
371 "R_LARCH_RELAX without preceding relocation",
374 auto &PrevEdge = *std::prev(BlockToFix.
edges().end());
376 PrevEdge.setKind(getRelaxableRelocationKind(Kind));
382 return Kind.takeError();
384 uint32_t SymbolIndex = Rel.getSymbol(
false);
385 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
387 return ObjSymbol.takeError();
389 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
391 return make_error<StringError>(
392 formatv(
"Could not find symbol at given index, did you add it to "
393 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
394 SymbolIndex, (*ObjSymbol)->st_shndx,
395 Base::GraphSymbols.size()),
407 BlockToFix.
addEdge(std::move(GE));
413 ELFLinkGraphBuilder_loongarch(
StringRef FileName,
415 std::shared_ptr<orc::SymbolStringPool> SSP,
418 std::move(Features), FileName,
437 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
439 dbgs() <<
"Building jitlink graph for new input "
445 return ELFObj.takeError();
447 auto Features = (*ELFObj)->getFeatures();
449 return Features.takeError();
452 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
453 return ELFLinkGraphBuilder_loongarch<object::ELF64LE>(
454 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
455 std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features))
460 "Invalid triple for LoongArch ELF object file");
461 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
462 return ELFLinkGraphBuilder_loongarch<object::ELF32LE>(
463 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
464 (*ELFObj)->makeTriple(), std::move(*Features))
469 std::unique_ptr<JITLinkContext> Ctx) {
471 const Triple &TT =
G->getTargetTriple();
472 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
475 Config.PrePrunePasses.push_back(
481 if (
auto MarkLive = Ctx->getMarkLivePass(TT))
482 Config.PrePrunePasses.push_back(std::move(MarkLive));
487 Config.PostPrunePasses.push_back(buildTables_ELF_loongarch);
493 if (
auto Err = Ctx->modifyPassConfig(*
G,
Config))
494 return Ctx->notifyFailed(std::move(Err));
496 ELFJITLinker_loongarch::link(std::move(Ctx), std::move(
G), std::move(
Config));
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
DenseMap< Block *, BlockRelaxAux > Blocks
SmallVector< uint32_t, 0 > Writes
SmallVector< uint32_t, 0 > RelocDeltas
SmallVector< Edge *, 0 > RelaxEdges
SmallVector< Edge::Kind, 0 > EdgeKinds
SmallVector< SymbolAnchor, 0 > Anchors
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
virtual Error addRelocations()=0
Call to derived class to handle relocations.
Represents fixups and constraints in the LinkGraph.
Symbol & getTarget() const
AddendT getAddend() const
OffsetT getOffset() const
void setOffset(OffsetT Offset)
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.
bool isDefined() const
Returns true if this Symbol has content (potentially) defined within this object file (i....
Block & getBlock()
Return the Block for this Symbol (Symbol must be defined).
orc::ExecutorAddrDiff getSize() const
Returns the size of this symbol.
orc::ExecutorAddrDiff getOffset() const
Returns the offset for this symbol within the underlying addressable.
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.
uint64_t getValue() const
unique_function is a type-erasing functor similar to std::function.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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.
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...
Error markAllSymbolsLive(LinkGraph &G)
Marks all symbols in a graph live.
LinkGraphPassFunction createRelaxationPass_ELF_loongarch()
Returns a pass that performs linker relaxation.
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.
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.
static void finalizeRelax(LinkGraph &G, RelaxAux &Aux)
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,...
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)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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...