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