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/MathExtras.h"
20 
21 #define DEBUG_TYPE "jitlink"
22 
23 using namespace llvm;
24 using namespace llvm::jitlink;
25 
26 namespace llvm {
27 namespace jitlink {
28 
29 class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
30   friend class JITLinker<ELFJITLinker_aarch64>;
31 
32 public:
33   ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
34                        std::unique_ptr<LinkGraph> G,
35                        PassConfiguration PassConfig)
36       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
37 
38 private:
39   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
40     return aarch64::applyFixup(G, B, E);
41   }
42 };
43 
44 template <typename ELFT>
45 class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
46 private:
47   enum ELFAArch64RelocationKind : Edge::Kind {
48     ELFBranch26 = Edge::FirstRelocation,
49   };
50 
51   static Expected<ELFAArch64RelocationKind>
52   getRelocationKind(const uint32_t Type) {
53     using namespace aarch64;
54     switch (Type) {
55     case ELF::R_AARCH64_CALL26:
56       return ELFBranch26;
57     }
58 
59     return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
60                                     formatv("{0:d}", Type));
61   }
62 
63   Error addRelocations() override {
64     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
65 
66     using Base = ELFLinkGraphBuilder<ELFT>;
67     using Self = ELFLinkGraphBuilder_aarch64<ELFT>;
68     for (const auto &RelSect : Base::Sections)
69       if (Error Err = Base::forEachRelocation(RelSect, this,
70                                               &Self::addSingleRelocation))
71         return Err;
72 
73     return Error::success();
74   }
75 
76   Error addSingleRelocation(const typename ELFT::Rela &Rel,
77                             const typename ELFT::Shdr &FixupSect,
78                             Block &BlockToFix) {
79     using Base = ELFLinkGraphBuilder<ELFT>;
80 
81     uint32_t SymbolIndex = Rel.getSymbol(false);
82     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
83     if (!ObjSymbol)
84       return ObjSymbol.takeError();
85 
86     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
87     if (!GraphSymbol)
88       return make_error<StringError>(
89           formatv("Could not find symbol at given index, did you add it to "
90                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
91                   SymbolIndex, (*ObjSymbol)->st_shndx,
92                   Base::GraphSymbols.size()),
93           inconvertibleErrorCode());
94 
95     uint32_t Type = Rel.getType(false);
96     Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type);
97     if (!RelocKind)
98       return RelocKind.takeError();
99 
100     int64_t Addend = Rel.r_addend;
101     orc::ExecutorAddr FixupAddress =
102         orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
103     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
104 
105     Edge::Kind Kind = Edge::Invalid;
106 
107     switch (*RelocKind) {
108     case ELFBranch26: {
109       Kind = aarch64::Branch26;
110       break;
111     }
112     };
113 
114     Edge GE(Kind, Offset, *GraphSymbol, Addend);
115     LLVM_DEBUG({
116       dbgs() << "    ";
117       printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind));
118       dbgs() << "\n";
119     });
120 
121     BlockToFix.addEdge(std::move(GE));
122     return Error::success();
123   }
124 
125   /// Return the string name of the given ELF aarch64 edge kind.
126   const char *getELFAArch64RelocationKindName(Edge::Kind R) {
127     switch (R) {
128     case ELFBranch26:
129       return "ELFBranch26";
130     default:
131       return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
132     }
133   }
134 
135 public:
136   ELFLinkGraphBuilder_aarch64(StringRef FileName,
137                               const object::ELFFile<ELFT> &Obj, const Triple T)
138       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
139                                   aarch64::getEdgeKindName) {}
140 };
141 
142 Expected<std::unique_ptr<LinkGraph>>
143 createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) {
144   LLVM_DEBUG({
145     dbgs() << "Building jitlink graph for new input "
146            << ObjectBuffer.getBufferIdentifier() << "...\n";
147   });
148 
149   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
150   if (!ELFObj)
151     return ELFObj.takeError();
152 
153   assert((*ELFObj)->getArch() == Triple::aarch64 &&
154          "Only AArch64 (little endian) is supported for now");
155 
156   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
157   return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
158                                                       ELFObjFile.getELFFile(),
159                                                       (*ELFObj)->makeTriple())
160       .buildGraph();
161 }
162 
163 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
164                       std::unique_ptr<JITLinkContext> Ctx) {
165   PassConfiguration Config;
166   const Triple &TT = G->getTargetTriple();
167   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
168     if (auto MarkLive = Ctx->getMarkLivePass(TT))
169       Config.PrePrunePasses.push_back(std::move(MarkLive));
170     else
171       Config.PrePrunePasses.push_back(markAllSymbolsLive);
172   }
173   if (auto Err = Ctx->modifyPassConfig(*G, Config))
174     return Ctx->notifyFailed(std::move(Err));
175 
176   ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config));
177 }
178 
179 } // namespace jitlink
180 } // namespace llvm
181