xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
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     using namespace aarch64;
41     using namespace llvm::support;
42 
43     char *BlockWorkingMem = B.getAlreadyMutableContent().data();
44     char *FixupPtr = BlockWorkingMem + E.getOffset();
45     auto FixupAddress = B.getAddress() + E.getOffset();
46     switch (E.getKind()) {
47     case aarch64::R_AARCH64_CALL26: {
48       assert((FixupAddress.getValue() & 0x3) == 0 &&
49              "Call-inst is not 32-bit aligned");
50       int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
51 
52       if (static_cast<uint64_t>(Value) & 0x3)
53         return make_error<JITLinkError>("Call target is not 32-bit aligned");
54 
55       if (!isInt<28>(Value))
56         return makeTargetOutOfRangeError(G, B, E);
57 
58       uint32_t RawInstr = *(little32_t *)FixupPtr;
59       assert((RawInstr & 0x7fffffff) == 0x14000000 &&
60              "RawInstr isn't a B or BR immediate instruction");
61       uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
62       uint32_t FixedInstr = RawInstr | Imm;
63       *(little32_t *)FixupPtr = FixedInstr;
64       break;
65     }
66     }
67     return Error::success();
68   }
69 };
70 
71 template <typename ELFT>
72 class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
73 private:
74   static Expected<aarch64::EdgeKind_aarch64>
75   getRelocationKind(const uint32_t Type) {
76     using namespace aarch64;
77     switch (Type) {
78     case ELF::R_AARCH64_CALL26:
79       return EdgeKind_aarch64::R_AARCH64_CALL26;
80     }
81 
82     return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
83                                     formatv("{0:d}", Type));
84   }
85 
86   Error addRelocations() override {
87     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
88 
89     using Base = ELFLinkGraphBuilder<ELFT>;
90     using Self = ELFLinkGraphBuilder_aarch64<ELFT>;
91     for (const auto &RelSect : Base::Sections)
92       if (Error Err = Base::forEachRelocation(RelSect, this,
93                                               &Self::addSingleRelocation))
94         return Err;
95 
96     return Error::success();
97   }
98 
99   Error addSingleRelocation(const typename ELFT::Rela &Rel,
100                             const typename ELFT::Shdr &FixupSect,
101                             Block &BlockToFix) {
102     using Base = ELFLinkGraphBuilder<ELFT>;
103 
104     uint32_t SymbolIndex = Rel.getSymbol(false);
105     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
106     if (!ObjSymbol)
107       return ObjSymbol.takeError();
108 
109     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
110     if (!GraphSymbol)
111       return make_error<StringError>(
112           formatv("Could not find symbol at given index, did you add it to "
113                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
114                   SymbolIndex, (*ObjSymbol)->st_shndx,
115                   Base::GraphSymbols.size()),
116           inconvertibleErrorCode());
117 
118     uint32_t Type = Rel.getType(false);
119     Expected<aarch64::EdgeKind_aarch64> Kind = getRelocationKind(Type);
120     if (!Kind)
121       return Kind.takeError();
122 
123     int64_t Addend = Rel.r_addend;
124     orc::ExecutorAddr FixupAddress =
125         orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
126     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
127     Edge GE(*Kind, Offset, *GraphSymbol, Addend);
128     LLVM_DEBUG({
129       dbgs() << "    ";
130       printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(*Kind));
131       dbgs() << "\n";
132     });
133 
134     BlockToFix.addEdge(std::move(GE));
135     return Error::success();
136   }
137 
138 public:
139   ELFLinkGraphBuilder_aarch64(StringRef FileName,
140                               const object::ELFFile<ELFT> &Obj, const Triple T)
141       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
142                                   aarch64::getEdgeKindName) {}
143 };
144 
145 Expected<std::unique_ptr<LinkGraph>>
146 createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) {
147   LLVM_DEBUG({
148     dbgs() << "Building jitlink graph for new input "
149            << ObjectBuffer.getBufferIdentifier() << "...\n";
150   });
151 
152   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
153   if (!ELFObj)
154     return ELFObj.takeError();
155 
156   assert((*ELFObj)->getArch() == Triple::aarch64 &&
157          "Only AArch64 (little endian) is supported for now");
158 
159   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
160   return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
161                                                       ELFObjFile.getELFFile(),
162                                                       (*ELFObj)->makeTriple())
163       .buildGraph();
164 }
165 
166 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
167                       std::unique_ptr<JITLinkContext> Ctx) {
168   PassConfiguration Config;
169   const Triple &TT = G->getTargetTriple();
170   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
171     if (auto MarkLive = Ctx->getMarkLivePass(TT))
172       Config.PrePrunePasses.push_back(std::move(MarkLive));
173     else
174       Config.PrePrunePasses.push_back(markAllSymbolsLive);
175   }
176   if (auto Err = Ctx->modifyPassConfig(*G, Config))
177     return Ctx->notifyFailed(std::move(Err));
178 
179   ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config));
180 }
181 
182 } // namespace jitlink
183 } // namespace llvm
184