xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_aarch32.cpp (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
1 //===----- ELF_aarch32.cpp - JIT linker implementation for arm/thumb ------===//
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/aarch32 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/ELF_aarch32.h"
14 
15 #include "llvm/BinaryFormat/ELF.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITLink/aarch32.h"
18 #include "llvm/Object/ELF.h"
19 #include "llvm/Object/ELFObjectFile.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/TargetParser/ARMTargetParser.h"
22 
23 #include "ELFLinkGraphBuilder.h"
24 #include "JITLinkGeneric.h"
25 
26 #define DEBUG_TYPE "jitlink"
27 
28 using namespace llvm::object;
29 
30 namespace llvm {
31 namespace jitlink {
32 
33 /// Translate from ELF relocation type to JITLink-internal edge kind.
34 Expected<aarch32::EdgeKind_aarch32>
35 getJITLinkEdgeKind(uint32_t ELFType, const aarch32::ArmConfig &ArmCfg) {
36   switch (ELFType) {
37   case ELF::R_ARM_ABS32:
38     return aarch32::Data_Pointer32;
39   case ELF::R_ARM_GOT_PREL:
40     return aarch32::Data_RequestGOTAndTransformToDelta32;
41   case ELF::R_ARM_REL32:
42     return aarch32::Data_Delta32;
43   case ELF::R_ARM_CALL:
44     return aarch32::Arm_Call;
45   case ELF::R_ARM_JUMP24:
46     return aarch32::Arm_Jump24;
47   case ELF::R_ARM_MOVW_ABS_NC:
48     return aarch32::Arm_MovwAbsNC;
49   case ELF::R_ARM_MOVT_ABS:
50     return aarch32::Arm_MovtAbs;
51   case ELF::R_ARM_NONE:
52     return aarch32::None;
53   case ELF::R_ARM_PREL31:
54     return aarch32::Data_PRel31;
55   case ELF::R_ARM_TARGET1:
56     return (ArmCfg.Target1Rel) ? aarch32::Data_Delta32
57                                : aarch32::Data_Pointer32;
58   case ELF::R_ARM_THM_CALL:
59     return aarch32::Thumb_Call;
60   case ELF::R_ARM_THM_JUMP24:
61     return aarch32::Thumb_Jump24;
62   case ELF::R_ARM_THM_MOVW_ABS_NC:
63     return aarch32::Thumb_MovwAbsNC;
64   case ELF::R_ARM_THM_MOVT_ABS:
65     return aarch32::Thumb_MovtAbs;
66   case ELF::R_ARM_THM_MOVW_PREL_NC:
67     return aarch32::Thumb_MovwPrelNC;
68   case ELF::R_ARM_THM_MOVT_PREL:
69     return aarch32::Thumb_MovtPrel;
70   }
71 
72   return make_error<JITLinkError>(
73       "Unsupported aarch32 relocation " + formatv("{0:d}: ", ELFType) +
74       object::getELFRelocationTypeName(ELF::EM_ARM, ELFType));
75 }
76 
77 /// Translate from JITLink-internal edge kind back to ELF relocation type.
78 Expected<uint32_t> getELFRelocationType(Edge::Kind Kind) {
79   switch (static_cast<aarch32::EdgeKind_aarch32>(Kind)) {
80   case aarch32::Data_Delta32:
81     return ELF::R_ARM_REL32;
82   case aarch32::Data_Pointer32:
83     return ELF::R_ARM_ABS32;
84   case aarch32::Data_PRel31:
85     return ELF::R_ARM_PREL31;
86   case aarch32::Data_RequestGOTAndTransformToDelta32:
87     return ELF::R_ARM_GOT_PREL;
88   case aarch32::Arm_Call:
89     return ELF::R_ARM_CALL;
90   case aarch32::Arm_Jump24:
91     return ELF::R_ARM_JUMP24;
92   case aarch32::Arm_MovwAbsNC:
93     return ELF::R_ARM_MOVW_ABS_NC;
94   case aarch32::Arm_MovtAbs:
95     return ELF::R_ARM_MOVT_ABS;
96   case aarch32::Thumb_Call:
97     return ELF::R_ARM_THM_CALL;
98   case aarch32::Thumb_Jump24:
99     return ELF::R_ARM_THM_JUMP24;
100   case aarch32::Thumb_MovwAbsNC:
101     return ELF::R_ARM_THM_MOVW_ABS_NC;
102   case aarch32::Thumb_MovtAbs:
103     return ELF::R_ARM_THM_MOVT_ABS;
104   case aarch32::Thumb_MovwPrelNC:
105     return ELF::R_ARM_THM_MOVW_PREL_NC;
106   case aarch32::Thumb_MovtPrel:
107     return ELF::R_ARM_THM_MOVT_PREL;
108   case aarch32::None:
109     return ELF::R_ARM_NONE;
110   }
111 
112   return make_error<JITLinkError>(formatv("Invalid aarch32 edge {0:d}: ",
113                                           Kind));
114 }
115 
116 /// Get a human-readable name for the given ELF AArch32 edge kind.
117 const char *getELFAArch32EdgeKindName(Edge::Kind R) {
118   // No ELF-specific edge kinds yet
119   return aarch32::getEdgeKindName(R);
120 }
121 
122 class ELFJITLinker_aarch32 : public JITLinker<ELFJITLinker_aarch32> {
123   friend class JITLinker<ELFJITLinker_aarch32>;
124 
125 public:
126   ELFJITLinker_aarch32(std::unique_ptr<JITLinkContext> Ctx,
127                        std::unique_ptr<LinkGraph> G, PassConfiguration PassCfg,
128                        aarch32::ArmConfig ArmCfg)
129       : JITLinker(std::move(Ctx), std::move(G), std::move(PassCfg)),
130         ArmCfg(std::move(ArmCfg)) {}
131 
132 private:
133   aarch32::ArmConfig ArmCfg;
134 
135   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
136     return aarch32::applyFixup(G, B, E, ArmCfg);
137   }
138 };
139 
140 template <llvm::endianness DataEndianness>
141 class ELFLinkGraphBuilder_aarch32
142     : public ELFLinkGraphBuilder<ELFType<DataEndianness, false>> {
143 private:
144   using ELFT = ELFType<DataEndianness, false>;
145   using Base = ELFLinkGraphBuilder<ELFT>;
146 
147   Error addRelocations() override {
148     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
149     using Self = ELFLinkGraphBuilder_aarch32<DataEndianness>;
150     for (const auto &RelSect : Base::Sections) {
151       if (Error Err = Base::forEachRelRelocation(RelSect, this,
152                                                  &Self::addSingleRelRelocation))
153         return Err;
154     }
155     return Error::success();
156   }
157 
158   Error addSingleRelRelocation(const typename ELFT::Rel &Rel,
159                                const typename ELFT::Shdr &FixupSect,
160                                Block &BlockToFix) {
161     uint32_t SymbolIndex = Rel.getSymbol(false);
162     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
163     if (!ObjSymbol)
164       return ObjSymbol.takeError();
165 
166     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
167     if (!GraphSymbol)
168       return make_error<StringError>(
169           formatv("Could not find symbol at given index, did you add it to "
170                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
171                   SymbolIndex, (*ObjSymbol)->st_shndx,
172                   Base::GraphSymbols.size()),
173           inconvertibleErrorCode());
174 
175     uint32_t Type = Rel.getType(false);
176     Expected<aarch32::EdgeKind_aarch32> Kind = getJITLinkEdgeKind(Type, ArmCfg);
177     if (!Kind)
178       return Kind.takeError();
179 
180     auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
181     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
182 
183     Expected<int64_t> Addend =
184         aarch32::readAddend(*Base::G, BlockToFix, Offset, *Kind, ArmCfg);
185     if (!Addend)
186       return Addend.takeError();
187 
188     Edge E(*Kind, Offset, *GraphSymbol, *Addend);
189     LLVM_DEBUG({
190       dbgs() << "    ";
191       printEdge(dbgs(), BlockToFix, E, getELFAArch32EdgeKindName(*Kind));
192       dbgs() << "\n";
193     });
194 
195     BlockToFix.addEdge(std::move(E));
196     return Error::success();
197   }
198 
199   aarch32::ArmConfig ArmCfg;
200 
201 protected:
202   TargetFlagsType makeTargetFlags(const typename ELFT::Sym &Sym) override {
203     if (Sym.getValue() & 0x01)
204       return aarch32::ThumbSymbol;
205     return TargetFlagsType{};
206   }
207 
208   orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym,
209                                      TargetFlagsType Flags) override {
210     assert((makeTargetFlags(Sym) & Flags) == Flags);
211     static constexpr uint64_t ThumbBit = 0x01;
212     return Sym.getValue() & ~ThumbBit;
213   }
214 
215 public:
216   ELFLinkGraphBuilder_aarch32(StringRef FileName,
217                               const llvm::object::ELFFile<ELFT> &Obj, Triple TT,
218                               SubtargetFeatures Features,
219                               aarch32::ArmConfig ArmCfg)
220       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),
221                                   FileName, getELFAArch32EdgeKindName),
222         ArmCfg(std::move(ArmCfg)) {}
223 };
224 
225 template <typename StubsManagerType>
226 Error buildTables_ELF_aarch32(LinkGraph &G) {
227   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
228 
229   StubsManagerType StubsManager;
230   visitExistingEdges(G, StubsManager);
231   aarch32::GOTBuilder GOT;
232   visitExistingEdges(G, GOT);
233 
234   return Error::success();
235 }
236 
237 Expected<std::unique_ptr<LinkGraph>>
238 createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) {
239   LLVM_DEBUG({
240     dbgs() << "Building jitlink graph for new input "
241            << ObjectBuffer.getBufferIdentifier() << "...\n";
242   });
243 
244   auto ELFObj = ObjectFile::createELFObjectFile(ObjectBuffer);
245   if (!ELFObj)
246     return ELFObj.takeError();
247 
248   auto Features = (*ELFObj)->getFeatures();
249   if (!Features)
250     return Features.takeError();
251 
252   // Find out what exact AArch32 instruction set and features we target.
253   auto TT = (*ELFObj)->makeTriple();
254   ARM::ArchKind AK = ARM::parseArch(TT.getArchName());
255   if (AK == ARM::ArchKind::INVALID)
256     return make_error<JITLinkError>(
257         "Failed to build ELF link graph: Invalid ARM ArchKind");
258 
259   // Resolve our internal configuration for the target. If at some point the
260   // CPUArch alone becomes too unprecise, we can find more details in the
261   // Tag_CPU_arch_profile.
262   auto Arch = static_cast<ARMBuildAttrs::CPUArch>(ARM::getArchAttr(AK));
263   aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(Arch);
264 
265   // Populate the link-graph.
266   switch (TT.getArch()) {
267   case Triple::arm:
268   case Triple::thumb: {
269     auto &ELFFile = cast<ELFObjectFile<ELF32LE>>(**ELFObj).getELFFile();
270     return ELFLinkGraphBuilder_aarch32<llvm::endianness::little>(
271                (*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features),
272                ArmCfg)
273         .buildGraph();
274   }
275   case Triple::armeb:
276   case Triple::thumbeb: {
277     auto &ELFFile = cast<ELFObjectFile<ELF32BE>>(**ELFObj).getELFFile();
278     return ELFLinkGraphBuilder_aarch32<llvm::endianness::big>(
279                (*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features),
280                ArmCfg)
281         .buildGraph();
282   }
283   default:
284     return make_error<JITLinkError>(
285         "Failed to build ELF/aarch32 link graph: Invalid target triple " +
286         TT.getTriple());
287   }
288 }
289 
290 void link_ELF_aarch32(std::unique_ptr<LinkGraph> G,
291                       std::unique_ptr<JITLinkContext> Ctx) {
292   const Triple &TT = G->getTargetTriple();
293 
294   using namespace ARMBuildAttrs;
295   ARM::ArchKind AK = ARM::parseArch(TT.getArchName());
296   auto CPU = static_cast<CPUArch>(ARM::getArchAttr(AK));
297   aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPU);
298 
299   PassConfiguration PassCfg;
300   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
301     // Add a mark-live pass.
302     if (auto MarkLive = Ctx->getMarkLivePass(TT))
303       PassCfg.PrePrunePasses.push_back(std::move(MarkLive));
304     else
305       PassCfg.PrePrunePasses.push_back(markAllSymbolsLive);
306 
307     switch (ArmCfg.Stubs) {
308     case aarch32::StubsFlavor::pre_v7:
309       PassCfg.PostPrunePasses.push_back(
310           buildTables_ELF_aarch32<aarch32::StubsManager_prev7>);
311       break;
312     case aarch32::StubsFlavor::v7:
313       PassCfg.PostPrunePasses.push_back(
314           buildTables_ELF_aarch32<aarch32::StubsManager_v7>);
315       break;
316     case aarch32::StubsFlavor::Undefined:
317       llvm_unreachable("Check before building graph");
318     }
319   }
320 
321   if (auto Err = Ctx->modifyPassConfig(*G, PassCfg))
322     return Ctx->notifyFailed(std::move(Err));
323 
324   ELFJITLinker_aarch32::link(std::move(Ctx), std::move(G), std::move(PassCfg),
325                              std::move(ArmCfg));
326 }
327 
328 } // namespace jitlink
329 } // namespace llvm
330