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)) {
42 [
this](
LinkGraph &
G) {
return gatherLoongArchPCAddHi20(
G); });
53 RelPCAddHi20Map[{
B,
E.getOffset()}] = &
E;
61 "Can only have high relocation for PCAddLo12");
63 const Symbol &Sym =
E.getTarget();
68 if (It != RelPCAddHi20Map.
end())
72 "for PCAddLo12 relocation type");
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();
85 switch (
E.getKind()) {
87 *(ulittle64_t *)FixupPtr = TargetAddress + Addend;
91 if (
Value > std::numeric_limits<uint32_t>::max())
93 *(ulittle32_t *)FixupPtr =
Value;
97 int64_t
Value = TargetAddress - FixupAddress + Addend;
105 uint32_t RawInstr = *(little32_t *)FixupPtr;
108 *(little32_t *)FixupPtr = RawInstr | Imm15_0;
112 int64_t
Value = TargetAddress - FixupAddress + Addend;
120 uint32_t RawInstr = *(little32_t *)FixupPtr;
124 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16;
128 int64_t
Value = TargetAddress - FixupAddress + Addend;
136 uint32_t RawInstr = *(little32_t *)FixupPtr;
140 *(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm25_16;
144 int64_t
Value = TargetAddress - FixupAddress + Addend;
148 *(little32_t *)FixupPtr =
Value;
152 int64_t
Value = FixupAddress - TargetAddress + Addend;
155 *(little32_t *)FixupPtr =
Value;
159 *(little64_t *)FixupPtr = TargetAddress - FixupAddress + Addend;
165 uint64_t PCPage = FixupAddress & ~static_cast<uint64_t>(0xfff);
167 int64_t PageDelta = TargetPage - PCPage;
171 uint32_t RawInstr = *(little32_t *)FixupPtr;
173 *(little32_t *)FixupPtr = RawInstr | Imm31_12;
177 uint64_t TargetOffset = (TargetAddress + Addend) & 0xfff;
179 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
180 uint32_t Imm11_0 = TargetOffset << 10;
181 *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0;
186 int64_t Delta =
Target - FixupAddress + 0x800;
191 uint32_t RawInstr = *(little32_t *)FixupPtr;
193 *(little32_t *)FixupPtr = RawInstr | Imm31_12;
197 auto RelPCAddHi20 = getLoongArchPCAddHi20(
E);
199 return RelPCAddHi20.takeError();
201 (RelPCAddHi20->getTarget().getAddress() + RelPCAddHi20->getAddend()) -
202 (
E.getTarget().getAddress() +
E.getAddend());
204 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
206 *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0;
210 int64_t
Value = TargetAddress - FixupAddress + Addend;
218 uint32_t Pcaddu12i = *(little32_t *)FixupPtr;
220 *(little32_t *)FixupPtr = Pcaddu12i | Hi20;
221 uint32_t Jirl = *(little32_t *)(FixupPtr + 4);
223 *(little32_t *)(FixupPtr + 4) = Jirl | Lo10;
227 int64_t
Value = TargetAddress - FixupAddress + Addend;
235 uint32_t Pcaddu18i = *(little32_t *)FixupPtr;
237 *(little32_t *)FixupPtr = Pcaddu18i | Hi20;
238 uint32_t Jirl = *(little32_t *)(FixupPtr + 4);
240 *(little32_t *)(FixupPtr + 4) = Jirl | Lo16;
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);
250 int64_t
Value = TargetAddress +
251 *(
reinterpret_cast<const int8_t *
>(FixupPtr)) + Addend;
252 *FixupPtr =
static_cast<int8_t
>(
Value);
258 *(little16_t *)FixupPtr =
static_cast<int16_t
>(
Value);
264 *(little32_t *)FixupPtr =
static_cast<int32_t
>(
Value);
270 *(little64_t *)FixupPtr =
static_cast<int64_t
>(
Value);
274 const uint32_t Maxcount = 1 + 64 / 7;
276 const char *
Error =
nullptr;
284 ": extra space for uleb128");
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);
298 int64_t
Value = *(
reinterpret_cast<const int8_t *
>(FixupPtr)) -
299 TargetAddress - Addend;
300 *FixupPtr =
static_cast<int8_t
>(
Value);
306 *(little16_t *)FixupPtr =
static_cast<int16_t
>(
Value);
312 *(little32_t *)FixupPtr =
static_cast<int32_t
>(
Value);
318 *(little64_t *)FixupPtr =
static_cast<int64_t
>(
Value);
322 const uint32_t Maxcount = 1 + 64 / 7;
324 const char *
Error =
nullptr;
332 ": extra space for uleb128");
344 "In graph " +
G.getName() +
", section " +
B.getSection().getName() +
360struct BlockRelaxAux {
388 switch (
E.getKind()) {
398 for (
auto &S :
G.sections()) {
402 auto BlockEmplaceResult = Aux.Blocks.try_emplace(
B);
403 assert(BlockEmplaceResult.second &&
"Block encountered twice");
404 auto &BlockAux = BlockEmplaceResult.first->second;
406 for (
auto &
E :
B->edges())
408 BlockAux.RelaxEdges.push_back(&
E);
410 if (BlockAux.RelaxEdges.empty()) {
411 Aux.Blocks.erase(BlockEmplaceResult.first);
415 const auto NumEdges = BlockAux.RelaxEdges.size();
416 BlockAux.RelocDeltas.resize(NumEdges, 0);
417 BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);
420 for (
auto *Sym : S.
symbols()) {
421 if (!Sym->isDefined() || &Sym->getBlock() !=
B)
424 BlockAux.Anchors.push_back({Sym->getOffset(), Sym,
false});
425 BlockAux.Anchors.push_back(
426 {Sym->getOffset() + Sym->getSize(), Sym,
true});
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);
445 Edge::Kind &NewEdgeKind) {
447 !
E.getTarget().isDefined() ?
Log2_64(
E.getAddend()) + 1 :
E.getAddend();
448 const uint64_t AllBytes = (1ULL << (Addend & 0xff)) - 4;
450 const uint64_t MaxBytes = Addend >> 8;
455 if (MaxBytes != 0 && CurBytes > MaxBytes)
458 Remove = AllBytes - CurBytes;
460 assert(
static_cast<int32_t
>(Remove) >= 0 &&
461 "R_LARCH_ALIGN needs expanding the content");
471 Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);
475 const auto Loc = BlockAddr +
E->getOffset() - Delta;
476 auto &Cur = Aux.RelocDeltas[
I];
478 switch (
E->getKind()) {
491 SA[0].Sym->setSize(SA[0].
Offset - Delta - SA[0].Sym->getOffset());
493 SA[0].Sym->setOffset(SA[0].
Offset - Delta);
503 for (
const SymbolAnchor &
A : SA) {
505 A.Sym->setSize(
A.Offset - Delta -
A.Sym->getOffset());
507 A.Sym->setOffset(
A.Offset - Delta);
516 for (
auto &[
B, BlockAux] : Aux.Blocks)
524 auto *Dest = Contents.
data();
531 uint32_t Remove = Aux.RelocDeltas[
I] - Delta;
532 Delta = Aux.RelocDeltas[
I];
533 if (Remove == 0 && Aux.EdgeKinds[
I] == Edge::Invalid)
538 std::memmove(Dest, Contents.data() +
Offset,
Size);
540 Offset =
E->getOffset() + Remove;
543 std::memmove(Dest, Contents.data() +
Offset, Contents.size() -
Offset);
549 E.setOffset(
E.getOffset() - Delta);
551 if (
I < Aux.RelaxEdges.size() && Aux.RelaxEdges[
I] == &
E) {
552 if (Aux.EdgeKinds[
I] != Edge::Invalid)
553 E.setKind(Aux.EdgeKinds[
I]);
555 Delta = Aux.RelocDeltas[
I];
572 for (
auto &[
B, BlockAux] : Aux.Blocks)
584template <
typename ELFT>
591 case ELF::R_LARCH_64:
593 case ELF::R_LARCH_32:
595 case ELF::R_LARCH_32_PCREL:
597 case ELF::R_LARCH_B16:
599 case ELF::R_LARCH_B21:
601 case ELF::R_LARCH_B26:
603 case ELF::R_LARCH_PCALA_HI20:
605 case ELF::R_LARCH_PCALA_LO12:
607 case ELF::R_LARCH_GOT_PC_HI20:
609 case ELF::R_LARCH_GOT_PC_LO12:
611 case ELF::R_LARCH_CALL30:
613 case ELF::R_LARCH_CALL36:
615 case ELF::R_LARCH_ADD6:
617 case ELF::R_LARCH_ADD8:
619 case ELF::R_LARCH_ADD16:
621 case ELF::R_LARCH_ADD32:
623 case ELF::R_LARCH_ADD64:
625 case ELF::R_LARCH_ADD_ULEB128:
627 case ELF::R_LARCH_SUB6:
629 case ELF::R_LARCH_SUB8:
631 case ELF::R_LARCH_SUB16:
633 case ELF::R_LARCH_SUB32:
635 case ELF::R_LARCH_SUB64:
637 case ELF::R_LARCH_SUB_ULEB128:
639 case ELF::R_LARCH_ALIGN:
641 case ELF::R_LARCH_PCADD_HI20:
643 case ELF::R_LARCH_PCADD_LO12:
644 case ELF::R_LARCH_GOT_PCADD_LO12:
646 case ELF::R_LARCH_GOT_PCADD_HI20:
651 "Unsupported loongarch relocation:" +
formatv(
"{0:d}: ",
Type) +
660 Error addRelocations()
override {
664 using Self = ELFLinkGraphBuilder_loongarch<ELFT>;
665 for (
const auto &RelSect : Base::Sections)
666 if (
Error Err = Base::forEachRelaRelocation(RelSect,
this,
667 &Self::addSingleRelocation))
673 Error addSingleRelocation(
const typename ELFT::Rela &Rel,
674 const typename ELFT::Shdr &FixupSect,
679 int64_t Addend = Rel.r_addend;
682 if (
Type == ELF::R_LARCH_MARK_LA)
685 if (
Type == ELF::R_LARCH_RELAX) {
688 "R_LARCH_RELAX without preceding relocation",
691 auto &PrevEdge = *std::prev(BlockToFix.
edges().end());
693 PrevEdge.setKind(getRelaxableRelocationKind(Kind));
699 return Kind.takeError();
701 uint32_t SymbolIndex = Rel.getSymbol(
false);
702 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
704 return ObjSymbol.takeError();
706 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
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()),
724 BlockToFix.
addEdge(std::move(GE));
730 ELFLinkGraphBuilder_loongarch(
StringRef FileName,
732 std::shared_ptr<orc::SymbolStringPool> SSP,
735 std::move(Features), FileName,
754 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
756 dbgs() <<
"Building jitlink graph for new input "
762 return ELFObj.takeError();
764 auto Features = (*ELFObj)->getFeatures();
766 return Features.takeError();
770 return ELFLinkGraphBuilder_loongarch<object::ELF64LE>(
771 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
772 std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features))
777 "Invalid triple for LoongArch ELF object file");
779 return ELFLinkGraphBuilder_loongarch<object::ELF32LE>(
780 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
781 (*ELFObj)->makeTriple(), std::move(*Features))
786 std::unique_ptr<JITLinkContext> Ctx) {
788 const Triple &TT =
G->getTargetTriple();
789 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
798 if (
auto MarkLive = Ctx->getMarkLivePass(TT))
810 if (
auto Err = Ctx->modifyPassConfig(*
G, Config))
811 return Ctx->notifyFailed(std::move(Err));
813 ELFJITLinker_loongarch::link(std::move(Ctx), std::move(
G), std::move(Config));
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.
iterator find(const_arg_type_t< KeyT > Val)
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.
Target - Wrapper for Target specific information.
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.
LLVM Value Representation.
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.
PassConfiguration & getPassConfig()
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.
Block & getBlock()
Return the Block for this Symbol (Symbol must be defined).
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.
#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.
@ PCAddHi20
The upper 20 bits of the offset from the fixup to the target.
@ 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
@ RequestGOTAndTransformToPCAddHi20
A GOT entry getter/constructor, transformed to PCAddHi20 pointing at the GOT entry for the original t...
@ PCAddLo12
The lower 12 bits of the offset from the paired PCADDU12I (the initial target) to the final target it...
@ 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
@ Call30PCRel
A 30-bit PC-relative call.
@ 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
uint32_t extractBits(uint64_t Val, unsigned Hi, unsigned Lo)
unique_function< Error(LinkGraph &)> LinkGraphPassFunction
A function for mutating LinkGraphs.
LLVM_ABI Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B, const Edge &E)
Create an out of range error for the given edge in the given block.
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)
LLVM_ABI Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N, const Edge &E)
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.
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.
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.
static void finalizeRelax(LinkGraph &G, RelaxAux &Aux)
LLVM_ABI StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type)
uint64_t ExecutorAddrDiff
uint64_t read64le(const void *P)
uint16_t read16le(const void *P)
uint32_t read32le(const void *P)
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
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...
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.
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.
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.
FunctionAddr VTableAddr Count
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
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.