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