1 //===----- ELF_aarch64.cpp - JIT linker implementation for ELF/aarch64 ----===//
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/aarch64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
14 #include "ELFLinkGraphBuilder.h"
15 #include "JITLinkGeneric.h"
16 #include "llvm/BinaryFormat/ELF.h"
17 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
18 #include "llvm/Object/ELFObjectFile.h"
19 #include "llvm/Support/Endian.h"
20 #include "llvm/Support/MathExtras.h"
21 
22 #include "PerGraphGOTAndPLTStubsBuilder.h"
23 
24 #define DEBUG_TYPE "jitlink"
25 
26 using namespace llvm;
27 using namespace llvm::jitlink;
28 
29 namespace llvm {
30 namespace jitlink {
31 
32 class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
33   friend class JITLinker<ELFJITLinker_aarch64>;
34 
35 public:
36   ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
37                        std::unique_ptr<LinkGraph> G,
38                        PassConfiguration PassConfig)
39       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
40 
41 private:
42   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
43     return aarch64::applyFixup(G, B, E);
44   }
45 };
46 
47 template <typename ELFT>
48 class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
49 private:
50   enum ELFAArch64RelocationKind : Edge::Kind {
51     ELFCall26 = Edge::FirstRelocation,
52     ELFAdrPage21,
53     ELFAddAbs12,
54     ELFLdSt8Abs12,
55     ELFLdSt16Abs12,
56     ELFLdSt32Abs12,
57     ELFLdSt64Abs12,
58     ELFLdSt128Abs12,
59     ELFAbs64,
60     ELFPrel32,
61     ELFPrel64,
62     ELFAdrGOTPage21,
63     ELFLd64GOTLo12,
64   };
65 
66   static Expected<ELFAArch64RelocationKind>
67   getRelocationKind(const uint32_t Type) {
68     using namespace aarch64;
69     switch (Type) {
70     case ELF::R_AARCH64_CALL26:
71       return ELFCall26;
72     case ELF::R_AARCH64_ADR_PREL_PG_HI21:
73       return ELFAdrPage21;
74     case ELF::R_AARCH64_ADD_ABS_LO12_NC:
75       return ELFAddAbs12;
76     case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
77       return ELFLdSt8Abs12;
78     case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
79       return ELFLdSt16Abs12;
80     case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
81       return ELFLdSt32Abs12;
82     case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
83       return ELFLdSt64Abs12;
84     case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
85       return ELFLdSt128Abs12;
86     case ELF::R_AARCH64_ABS64:
87       return ELFAbs64;
88     case ELF::R_AARCH64_PREL32:
89       return ELFPrel32;
90     case ELF::R_AARCH64_PREL64:
91       return ELFPrel64;
92     case ELF::R_AARCH64_ADR_GOT_PAGE:
93       return ELFAdrGOTPage21;
94     case ELF::R_AARCH64_LD64_GOT_LO12_NC:
95       return ELFLd64GOTLo12;
96     }
97 
98     return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
99                                     formatv("{0:d}", Type));
100   }
101 
102   Error addRelocations() override {
103     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
104 
105     using Base = ELFLinkGraphBuilder<ELFT>;
106     using Self = ELFLinkGraphBuilder_aarch64<ELFT>;
107     for (const auto &RelSect : Base::Sections)
108       if (Error Err = Base::forEachRelocation(RelSect, this,
109                                               &Self::addSingleRelocation))
110         return Err;
111 
112     return Error::success();
113   }
114 
115   Error addSingleRelocation(const typename ELFT::Rela &Rel,
116                             const typename ELFT::Shdr &FixupSect,
117                             Block &BlockToFix) {
118     using support::ulittle32_t;
119     using Base = ELFLinkGraphBuilder<ELFT>;
120 
121     uint32_t SymbolIndex = Rel.getSymbol(false);
122     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
123     if (!ObjSymbol)
124       return ObjSymbol.takeError();
125 
126     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
127     if (!GraphSymbol)
128       return make_error<StringError>(
129           formatv("Could not find symbol at given index, did you add it to "
130                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
131                   SymbolIndex, (*ObjSymbol)->st_shndx,
132                   Base::GraphSymbols.size()),
133           inconvertibleErrorCode());
134 
135     uint32_t Type = Rel.getType(false);
136     Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type);
137     if (!RelocKind)
138       return RelocKind.takeError();
139 
140     int64_t Addend = Rel.r_addend;
141     orc::ExecutorAddr FixupAddress =
142         orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
143     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
144 
145     // Get a pointer to the fixup content.
146     const void *FixupContent = BlockToFix.getContent().data() +
147                                (FixupAddress - BlockToFix.getAddress());
148 
149     Edge::Kind Kind = Edge::Invalid;
150 
151     switch (*RelocKind) {
152     case ELFCall26: {
153       Kind = aarch64::Branch26;
154       break;
155     }
156     case ELFAdrPage21: {
157       Kind = aarch64::Page21;
158       break;
159     }
160     case ELFAddAbs12: {
161       Kind = aarch64::PageOffset12;
162       break;
163     }
164     case ELFLdSt8Abs12: {
165       uint32_t Instr = *(const ulittle32_t *)FixupContent;
166       if (!aarch64::isLoadStoreImm12(Instr) ||
167           aarch64::getPageOffset12Shift(Instr) != 0)
168         return make_error<JITLinkError>(
169             "R_AARCH64_LDST8_ABS_LO12_NC target is not a "
170             "LDRB/STRB (imm12) instruction");
171 
172       Kind = aarch64::PageOffset12;
173       break;
174     }
175     case ELFLdSt16Abs12: {
176       uint32_t Instr = *(const ulittle32_t *)FixupContent;
177       if (!aarch64::isLoadStoreImm12(Instr) ||
178           aarch64::getPageOffset12Shift(Instr) != 1)
179         return make_error<JITLinkError>(
180             "R_AARCH64_LDST16_ABS_LO12_NC target is not a "
181             "LDRH/STRH (imm12) instruction");
182 
183       Kind = aarch64::PageOffset12;
184       break;
185     }
186     case ELFLdSt32Abs12: {
187       uint32_t Instr = *(const ulittle32_t *)FixupContent;
188       if (!aarch64::isLoadStoreImm12(Instr) ||
189           aarch64::getPageOffset12Shift(Instr) != 2)
190         return make_error<JITLinkError>(
191             "R_AARCH64_LDST32_ABS_LO12_NC target is not a "
192             "LDR/STR (imm12, 32 bit) instruction");
193 
194       Kind = aarch64::PageOffset12;
195       break;
196     }
197     case ELFLdSt64Abs12: {
198       uint32_t Instr = *(const ulittle32_t *)FixupContent;
199       if (!aarch64::isLoadStoreImm12(Instr) ||
200           aarch64::getPageOffset12Shift(Instr) != 3)
201         return make_error<JITLinkError>(
202             "R_AARCH64_LDST64_ABS_LO12_NC target is not a "
203             "LDR/STR (imm12, 64 bit) instruction");
204 
205       Kind = aarch64::PageOffset12;
206       break;
207     }
208     case ELFLdSt128Abs12: {
209       uint32_t Instr = *(const ulittle32_t *)FixupContent;
210       if (!aarch64::isLoadStoreImm12(Instr) ||
211           aarch64::getPageOffset12Shift(Instr) != 4)
212         return make_error<JITLinkError>(
213             "R_AARCH64_LDST128_ABS_LO12_NC target is not a "
214             "LDR/STR (imm12, 128 bit) instruction");
215 
216       Kind = aarch64::PageOffset12;
217       break;
218     }
219     case ELFAbs64: {
220       Kind = aarch64::Pointer64;
221       break;
222     }
223     case ELFPrel32: {
224       Kind = aarch64::Delta32;
225       break;
226     }
227     case ELFPrel64: {
228       Kind = aarch64::Delta64;
229       break;
230     }
231     case ELFAdrGOTPage21: {
232       Kind = aarch64::GOTPage21;
233       break;
234     }
235     case ELFLd64GOTLo12: {
236       Kind = aarch64::GOTPageOffset12;
237       break;
238     }
239     };
240 
241     Edge GE(Kind, Offset, *GraphSymbol, Addend);
242     LLVM_DEBUG({
243       dbgs() << "    ";
244       printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind));
245       dbgs() << "\n";
246     });
247 
248     BlockToFix.addEdge(std::move(GE));
249     return Error::success();
250   }
251 
252   /// Return the string name of the given ELF aarch64 edge kind.
253   const char *getELFAArch64RelocationKindName(Edge::Kind R) {
254     switch (R) {
255     case ELFCall26:
256       return "ELFCall26";
257     case ELFAdrPage21:
258       return "ELFAdrPage21";
259     case ELFAddAbs12:
260       return "ELFAddAbs12";
261     case ELFLdSt8Abs12:
262       return "ELFLdSt8Abs12";
263     case ELFLdSt16Abs12:
264       return "ELFLdSt16Abs12";
265     case ELFLdSt32Abs12:
266       return "ELFLdSt32Abs12";
267     case ELFLdSt64Abs12:
268       return "ELFLdSt64Abs12";
269     case ELFLdSt128Abs12:
270       return "ELFLdSt128Abs12";
271     case ELFAbs64:
272       return "ELFAbs64";
273     case ELFPrel32:
274       return "ELFPrel32";
275     case ELFPrel64:
276       return "ELFPrel64";
277     case ELFAdrGOTPage21:
278       return "ELFAdrGOTPage21";
279     case ELFLd64GOTLo12:
280       return "ELFLd64GOTLo12";
281     default:
282       return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
283     }
284   }
285 
286 public:
287   ELFLinkGraphBuilder_aarch64(StringRef FileName,
288                               const object::ELFFile<ELFT> &Obj, const Triple T)
289       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
290                                   aarch64::getEdgeKindName) {}
291 };
292 
293 class PerGraphGOTAndPLTStubsBuilder_ELF_arm64
294     : public PerGraphGOTAndPLTStubsBuilder<
295           PerGraphGOTAndPLTStubsBuilder_ELF_arm64> {
296 public:
297   using PerGraphGOTAndPLTStubsBuilder<
298       PerGraphGOTAndPLTStubsBuilder_ELF_arm64>::PerGraphGOTAndPLTStubsBuilder;
299 
300   bool isGOTEdgeToFix(Edge &E) const {
301     return E.getKind() == aarch64::GOTPage21 ||
302            E.getKind() == aarch64::GOTPageOffset12;
303   }
304 
305   Symbol &createGOTEntry(Symbol &Target) {
306     auto &GOTEntryBlock = G.createContentBlock(
307         getGOTSection(), getGOTEntryBlockContent(), orc::ExecutorAddr(), 8, 0);
308     GOTEntryBlock.addEdge(aarch64::Pointer64, 0, Target, 0);
309     return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
310   }
311 
312   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
313     if (E.getKind() == aarch64::GOTPage21) {
314       E.setKind(aarch64::Page21);
315       E.setTarget(GOTEntry);
316     } else if (E.getKind() == aarch64::GOTPageOffset12) {
317       E.setKind(aarch64::PageOffset12);
318       E.setTarget(GOTEntry);
319     } else
320       llvm_unreachable("Not a GOT edge?");
321   }
322 
323   bool isExternalBranchEdge(Edge &E) { return false; }
324 
325   Symbol &createPLTStub(Symbol &Target) {
326     assert(false && "unimplemetned");
327     return Target;
328   }
329 
330   void fixPLTEdge(Edge &E, Symbol &Stub) { assert(false && "unimplemetned"); }
331 
332 private:
333   Section &getGOTSection() {
334     if (!GOTSection)
335       GOTSection = &G.createSection("$__GOT", MemProt::Read | MemProt::Exec);
336     return *GOTSection;
337   }
338 
339   ArrayRef<char> getGOTEntryBlockContent() {
340     return {reinterpret_cast<const char *>(NullGOTEntryContent),
341             sizeof(NullGOTEntryContent)};
342   }
343 
344   static const uint8_t NullGOTEntryContent[8];
345   Section *GOTSection = nullptr;
346 };
347 
348 const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_arm64::NullGOTEntryContent[8] =
349     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
350 
351 Expected<std::unique_ptr<LinkGraph>>
352 createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) {
353   LLVM_DEBUG({
354     dbgs() << "Building jitlink graph for new input "
355            << ObjectBuffer.getBufferIdentifier() << "...\n";
356   });
357 
358   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
359   if (!ELFObj)
360     return ELFObj.takeError();
361 
362   assert((*ELFObj)->getArch() == Triple::aarch64 &&
363          "Only AArch64 (little endian) is supported for now");
364 
365   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
366   return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
367                                                       ELFObjFile.getELFFile(),
368                                                       (*ELFObj)->makeTriple())
369       .buildGraph();
370 }
371 
372 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
373                       std::unique_ptr<JITLinkContext> Ctx) {
374   PassConfiguration Config;
375   const Triple &TT = G->getTargetTriple();
376   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
377     if (auto MarkLive = Ctx->getMarkLivePass(TT))
378       Config.PrePrunePasses.push_back(std::move(MarkLive));
379     else
380       Config.PrePrunePasses.push_back(markAllSymbolsLive);
381   }
382 
383   Config.PostPrunePasses.push_back(
384       PerGraphGOTAndPLTStubsBuilder_ELF_arm64::asPass);
385 
386   if (auto Err = Ctx->modifyPassConfig(*G, Config))
387     return Ctx->notifyFailed(std::move(Err));
388 
389   ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config));
390 }
391 
392 } // namespace jitlink
393 } // namespace llvm
394