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:
ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)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:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const43 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>
getRelocationKind(const uint32_t Type)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
addRelocations()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
addSingleRelocation(const typename ELFT::Rela & Rel,const typename ELFT::Shdr & FixupSect,Block & BlockToFix)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:
ELFLinkGraphBuilder_loongarch(StringRef FileName,const object::ELFFile<ELFT> & Obj,const Triple T)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
buildTables_ELF_loongarch(LinkGraph & G)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>>
createLinkGraphFromELFObject_loongarch(MemoryBufferRef ObjectBuffer)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
link_ELF_loongarch(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)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