xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1*bdd1243dSDimitry Andric //===--- ELF_loongarch.cpp - JIT linker implementation for ELF/loongarch --===//
2*bdd1243dSDimitry Andric //
3*bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*bdd1243dSDimitry Andric //
7*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8*bdd1243dSDimitry Andric //
9*bdd1243dSDimitry Andric // ELF/loongarch jit-link implementation.
10*bdd1243dSDimitry Andric //
11*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
12*bdd1243dSDimitry Andric 
13*bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/ELF_loongarch.h"
14*bdd1243dSDimitry Andric #include "llvm/BinaryFormat/ELF.h"
15*bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
16*bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17*bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/loongarch.h"
18*bdd1243dSDimitry Andric #include "llvm/Object/ELF.h"
19*bdd1243dSDimitry Andric #include "llvm/Object/ELFObjectFile.h"
20*bdd1243dSDimitry Andric 
21*bdd1243dSDimitry Andric #include "EHFrameSupportImpl.h"
22*bdd1243dSDimitry Andric #include "ELFLinkGraphBuilder.h"
23*bdd1243dSDimitry Andric #include "JITLinkGeneric.h"
24*bdd1243dSDimitry Andric 
25*bdd1243dSDimitry Andric #define DEBUG_TYPE "jitlink"
26*bdd1243dSDimitry Andric 
27*bdd1243dSDimitry Andric using namespace llvm;
28*bdd1243dSDimitry Andric using namespace llvm::jitlink;
29*bdd1243dSDimitry Andric using namespace llvm::jitlink::loongarch;
30*bdd1243dSDimitry Andric 
31*bdd1243dSDimitry Andric namespace {
32*bdd1243dSDimitry Andric 
33*bdd1243dSDimitry Andric class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> {
34*bdd1243dSDimitry Andric   friend class JITLinker<ELFJITLinker_loongarch>;
35*bdd1243dSDimitry Andric 
36*bdd1243dSDimitry Andric public:
37*bdd1243dSDimitry Andric   ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx,
38*bdd1243dSDimitry Andric                          std::unique_ptr<LinkGraph> G,
39*bdd1243dSDimitry Andric                          PassConfiguration PassConfig)
40*bdd1243dSDimitry Andric       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
41*bdd1243dSDimitry Andric 
42*bdd1243dSDimitry Andric private:
43*bdd1243dSDimitry Andric   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
44*bdd1243dSDimitry Andric     return loongarch::applyFixup(G, B, E);
45*bdd1243dSDimitry Andric   }
46*bdd1243dSDimitry Andric };
47*bdd1243dSDimitry Andric 
48*bdd1243dSDimitry Andric template <typename ELFT>
49*bdd1243dSDimitry Andric class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> {
50*bdd1243dSDimitry Andric private:
51*bdd1243dSDimitry Andric   static Expected<loongarch::EdgeKind_loongarch>
52*bdd1243dSDimitry Andric   getRelocationKind(const uint32_t Type) {
53*bdd1243dSDimitry Andric     using namespace loongarch;
54*bdd1243dSDimitry Andric     switch (Type) {
55*bdd1243dSDimitry Andric     case ELF::R_LARCH_64:
56*bdd1243dSDimitry Andric       return Pointer64;
57*bdd1243dSDimitry Andric     case ELF::R_LARCH_32:
58*bdd1243dSDimitry Andric       return Pointer32;
59*bdd1243dSDimitry Andric     case ELF::R_LARCH_32_PCREL:
60*bdd1243dSDimitry Andric       return Delta32;
61*bdd1243dSDimitry Andric     case ELF::R_LARCH_B26:
62*bdd1243dSDimitry Andric       return Branch26PCRel;
63*bdd1243dSDimitry Andric     case ELF::R_LARCH_PCALA_HI20:
64*bdd1243dSDimitry Andric       return Page20;
65*bdd1243dSDimitry Andric     case ELF::R_LARCH_PCALA_LO12:
66*bdd1243dSDimitry Andric       return PageOffset12;
67*bdd1243dSDimitry Andric     case ELF::R_LARCH_GOT_PC_HI20:
68*bdd1243dSDimitry Andric       return RequestGOTAndTransformToPage20;
69*bdd1243dSDimitry Andric     case ELF::R_LARCH_GOT_PC_LO12:
70*bdd1243dSDimitry Andric       return RequestGOTAndTransformToPageOffset12;
71*bdd1243dSDimitry Andric     }
72*bdd1243dSDimitry Andric 
73*bdd1243dSDimitry Andric     return make_error<JITLinkError>(
74*bdd1243dSDimitry Andric         "Unsupported loongarch relocation:" + formatv("{0:d}: ", Type) +
75*bdd1243dSDimitry Andric         object::getELFRelocationTypeName(ELF::EM_LOONGARCH, Type));
76*bdd1243dSDimitry Andric   }
77*bdd1243dSDimitry Andric 
78*bdd1243dSDimitry Andric   Error addRelocations() override {
79*bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
80*bdd1243dSDimitry Andric 
81*bdd1243dSDimitry Andric     using Base = ELFLinkGraphBuilder<ELFT>;
82*bdd1243dSDimitry Andric     using Self = ELFLinkGraphBuilder_loongarch<ELFT>;
83*bdd1243dSDimitry Andric     for (const auto &RelSect : Base::Sections)
84*bdd1243dSDimitry Andric       if (Error Err = Base::forEachRelaRelocation(RelSect, this,
85*bdd1243dSDimitry Andric                                                   &Self::addSingleRelocation))
86*bdd1243dSDimitry Andric         return Err;
87*bdd1243dSDimitry Andric 
88*bdd1243dSDimitry Andric     return Error::success();
89*bdd1243dSDimitry Andric   }
90*bdd1243dSDimitry Andric 
91*bdd1243dSDimitry Andric   Error addSingleRelocation(const typename ELFT::Rela &Rel,
92*bdd1243dSDimitry Andric                             const typename ELFT::Shdr &FixupSect,
93*bdd1243dSDimitry Andric                             Block &BlockToFix) {
94*bdd1243dSDimitry Andric     using Base = ELFLinkGraphBuilder<ELFT>;
95*bdd1243dSDimitry Andric 
96*bdd1243dSDimitry Andric     uint32_t SymbolIndex = Rel.getSymbol(false);
97*bdd1243dSDimitry Andric     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
98*bdd1243dSDimitry Andric     if (!ObjSymbol)
99*bdd1243dSDimitry Andric       return ObjSymbol.takeError();
100*bdd1243dSDimitry Andric 
101*bdd1243dSDimitry Andric     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
102*bdd1243dSDimitry Andric     if (!GraphSymbol)
103*bdd1243dSDimitry Andric       return make_error<StringError>(
104*bdd1243dSDimitry Andric           formatv("Could not find symbol at given index, did you add it to "
105*bdd1243dSDimitry Andric                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
106*bdd1243dSDimitry Andric                   SymbolIndex, (*ObjSymbol)->st_shndx,
107*bdd1243dSDimitry Andric                   Base::GraphSymbols.size()),
108*bdd1243dSDimitry Andric           inconvertibleErrorCode());
109*bdd1243dSDimitry Andric 
110*bdd1243dSDimitry Andric     uint32_t Type = Rel.getType(false);
111*bdd1243dSDimitry Andric     Expected<loongarch::EdgeKind_loongarch> Kind = getRelocationKind(Type);
112*bdd1243dSDimitry Andric     if (!Kind)
113*bdd1243dSDimitry Andric       return Kind.takeError();
114*bdd1243dSDimitry Andric 
115*bdd1243dSDimitry Andric     int64_t Addend = Rel.r_addend;
116*bdd1243dSDimitry Andric     auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
117*bdd1243dSDimitry Andric     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
118*bdd1243dSDimitry Andric     Edge GE(*Kind, Offset, *GraphSymbol, Addend);
119*bdd1243dSDimitry Andric     LLVM_DEBUG({
120*bdd1243dSDimitry Andric       dbgs() << "    ";
121*bdd1243dSDimitry Andric       printEdge(dbgs(), BlockToFix, GE, loongarch::getEdgeKindName(*Kind));
122*bdd1243dSDimitry Andric       dbgs() << "\n";
123*bdd1243dSDimitry Andric     });
124*bdd1243dSDimitry Andric 
125*bdd1243dSDimitry Andric     BlockToFix.addEdge(std::move(GE));
126*bdd1243dSDimitry Andric 
127*bdd1243dSDimitry Andric     return Error::success();
128*bdd1243dSDimitry Andric   }
129*bdd1243dSDimitry Andric 
130*bdd1243dSDimitry Andric public:
131*bdd1243dSDimitry Andric   ELFLinkGraphBuilder_loongarch(StringRef FileName,
132*bdd1243dSDimitry Andric                                 const object::ELFFile<ELFT> &Obj,
133*bdd1243dSDimitry Andric                                 const Triple T)
134*bdd1243dSDimitry Andric       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
135*bdd1243dSDimitry Andric                                   loongarch::getEdgeKindName) {}
136*bdd1243dSDimitry Andric };
137*bdd1243dSDimitry Andric 
138*bdd1243dSDimitry Andric Error buildTables_ELF_loongarch(LinkGraph &G) {
139*bdd1243dSDimitry Andric   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
140*bdd1243dSDimitry Andric 
141*bdd1243dSDimitry Andric   GOTTableManager GOT;
142*bdd1243dSDimitry Andric   PLTTableManager PLT(GOT);
143*bdd1243dSDimitry Andric   visitExistingEdges(G, GOT, PLT);
144*bdd1243dSDimitry Andric   return Error::success();
145*bdd1243dSDimitry Andric }
146*bdd1243dSDimitry Andric 
147*bdd1243dSDimitry Andric } // namespace
148*bdd1243dSDimitry Andric 
149*bdd1243dSDimitry Andric namespace llvm {
150*bdd1243dSDimitry Andric namespace jitlink {
151*bdd1243dSDimitry Andric 
152*bdd1243dSDimitry Andric Expected<std::unique_ptr<LinkGraph>>
153*bdd1243dSDimitry Andric createLinkGraphFromELFObject_loongarch(MemoryBufferRef ObjectBuffer) {
154*bdd1243dSDimitry Andric   LLVM_DEBUG({
155*bdd1243dSDimitry Andric     dbgs() << "Building jitlink graph for new input "
156*bdd1243dSDimitry Andric            << ObjectBuffer.getBufferIdentifier() << "...\n";
157*bdd1243dSDimitry Andric   });
158*bdd1243dSDimitry Andric 
159*bdd1243dSDimitry Andric   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
160*bdd1243dSDimitry Andric   if (!ELFObj)
161*bdd1243dSDimitry Andric     return ELFObj.takeError();
162*bdd1243dSDimitry Andric 
163*bdd1243dSDimitry Andric   if ((*ELFObj)->getArch() == Triple::loongarch64) {
164*bdd1243dSDimitry Andric     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
165*bdd1243dSDimitry Andric     return ELFLinkGraphBuilder_loongarch<object::ELF64LE>(
166*bdd1243dSDimitry Andric                (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
167*bdd1243dSDimitry Andric                (*ELFObj)->makeTriple())
168*bdd1243dSDimitry Andric         .buildGraph();
169*bdd1243dSDimitry Andric   }
170*bdd1243dSDimitry Andric 
171*bdd1243dSDimitry Andric   assert((*ELFObj)->getArch() == Triple::loongarch32 &&
172*bdd1243dSDimitry Andric          "Invalid triple for LoongArch ELF object file");
173*bdd1243dSDimitry Andric   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
174*bdd1243dSDimitry Andric   return ELFLinkGraphBuilder_loongarch<object::ELF32LE>(
175*bdd1243dSDimitry Andric              (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
176*bdd1243dSDimitry Andric              (*ELFObj)->makeTriple())
177*bdd1243dSDimitry Andric       .buildGraph();
178*bdd1243dSDimitry Andric }
179*bdd1243dSDimitry Andric 
180*bdd1243dSDimitry Andric void link_ELF_loongarch(std::unique_ptr<LinkGraph> G,
181*bdd1243dSDimitry Andric                         std::unique_ptr<JITLinkContext> Ctx) {
182*bdd1243dSDimitry Andric   PassConfiguration Config;
183*bdd1243dSDimitry Andric   const Triple &TT = G->getTargetTriple();
184*bdd1243dSDimitry Andric   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
185*bdd1243dSDimitry Andric     // Add eh-frame passses.
186*bdd1243dSDimitry Andric     Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
187*bdd1243dSDimitry Andric     Config.PrePrunePasses.push_back(
188*bdd1243dSDimitry Andric         EHFrameEdgeFixer(".eh_frame", G->getPointerSize(), Pointer32, Pointer64,
189*bdd1243dSDimitry Andric                          Delta32, Delta64, NegDelta32));
190*bdd1243dSDimitry Andric     Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
191*bdd1243dSDimitry Andric 
192*bdd1243dSDimitry Andric     // Add a mark-live pass.
193*bdd1243dSDimitry Andric     if (auto MarkLive = Ctx->getMarkLivePass(TT))
194*bdd1243dSDimitry Andric       Config.PrePrunePasses.push_back(std::move(MarkLive));
195*bdd1243dSDimitry Andric     else
196*bdd1243dSDimitry Andric       Config.PrePrunePasses.push_back(markAllSymbolsLive);
197*bdd1243dSDimitry Andric 
198*bdd1243dSDimitry Andric     // Add an in-place GOT/PLTStubs build pass.
199*bdd1243dSDimitry Andric     Config.PostPrunePasses.push_back(buildTables_ELF_loongarch);
200*bdd1243dSDimitry Andric   }
201*bdd1243dSDimitry Andric 
202*bdd1243dSDimitry Andric   if (auto Err = Ctx->modifyPassConfig(*G, Config))
203*bdd1243dSDimitry Andric     return Ctx->notifyFailed(std::move(Err));
204*bdd1243dSDimitry Andric 
205*bdd1243dSDimitry Andric   ELFJITLinker_loongarch::link(std::move(Ctx), std::move(G), std::move(Config));
206*bdd1243dSDimitry Andric }
207*bdd1243dSDimitry Andric 
208*bdd1243dSDimitry Andric } // namespace jitlink
209*bdd1243dSDimitry Andric } // namespace llvm
210