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