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 | Args: "Unsupported aarch32 relocation " + formatv(Fmt: "{0:d}: " , Vals&: ELFType) + |
74 | object::getELFRelocationTypeName(Machine: ELF::EM_ARM, Type: 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>(Args: formatv(Fmt: "Invalid aarch32 edge {0:d}: " , |
113 | Vals&: 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(K: 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(ELFType: 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(G&: *Base::G, B&: BlockToFix, Offset, Kind: *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(E: 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 | // Only emit target flag for callable symbols |
204 | if (Sym.getType() != ELF::STT_FUNC) |
205 | return TargetFlagsType{}; |
206 | if (Sym.getValue() & 0x01) |
207 | return aarch32::ThumbSymbol; |
208 | return TargetFlagsType{}; |
209 | } |
210 | |
211 | orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym, |
212 | TargetFlagsType Flags) override { |
213 | assert((makeTargetFlags(Sym) & Flags) == Flags); |
214 | static constexpr uint64_t ThumbBit = 0x01; |
215 | if (Sym.getType() == ELF::STT_FUNC) |
216 | return Sym.getValue() & ~ThumbBit; |
217 | return Sym.getValue(); |
218 | } |
219 | |
220 | public: |
221 | ELFLinkGraphBuilder_aarch32(StringRef FileName, |
222 | const llvm::object::ELFFile<ELFT> &Obj, Triple TT, |
223 | SubtargetFeatures Features, |
224 | aarch32::ArmConfig ArmCfg) |
225 | : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features), |
226 | FileName, getELFAArch32EdgeKindName), |
227 | ArmCfg(std::move(ArmCfg)) {} |
228 | }; |
229 | |
230 | template <typename StubsManagerType> |
231 | Error buildTables_ELF_aarch32(LinkGraph &G) { |
232 | LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n" ); |
233 | |
234 | StubsManagerType StubsManager; |
235 | visitExistingEdges(G, StubsManager); |
236 | aarch32::GOTBuilder GOT; |
237 | visitExistingEdges(G, Vs&: GOT); |
238 | |
239 | return Error::success(); |
240 | } |
241 | |
242 | Expected<std::unique_ptr<LinkGraph>> |
243 | createLinkGraphFromELFObject_aarch32(MemoryBufferRef ObjectBuffer) { |
244 | LLVM_DEBUG({ |
245 | dbgs() << "Building jitlink graph for new input " |
246 | << ObjectBuffer.getBufferIdentifier() << "...\n" ; |
247 | }); |
248 | |
249 | auto ELFObj = ObjectFile::createELFObjectFile(Object: ObjectBuffer); |
250 | if (!ELFObj) |
251 | return ELFObj.takeError(); |
252 | |
253 | auto Features = (*ELFObj)->getFeatures(); |
254 | if (!Features) |
255 | return Features.takeError(); |
256 | |
257 | // Find out what exact AArch32 instruction set and features we target. |
258 | auto TT = (*ELFObj)->makeTriple(); |
259 | ARM::ArchKind AK = ARM::parseArch(Arch: TT.getArchName()); |
260 | if (AK == ARM::ArchKind::INVALID) |
261 | return make_error<JITLinkError>( |
262 | Args: "Failed to build ELF link graph: Invalid ARM ArchKind" ); |
263 | |
264 | // Resolve our internal configuration for the target. If at some point the |
265 | // CPUArch alone becomes too unprecise, we can find more details in the |
266 | // Tag_CPU_arch_profile. |
267 | auto Arch = static_cast<ARMBuildAttrs::CPUArch>(ARM::getArchAttr(AK)); |
268 | aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPUArch: Arch); |
269 | |
270 | // Populate the link-graph. |
271 | switch (TT.getArch()) { |
272 | case Triple::arm: |
273 | case Triple::thumb: { |
274 | auto &ELFFile = cast<ELFObjectFile<ELF32LE>>(Val&: **ELFObj).getELFFile(); |
275 | return ELFLinkGraphBuilder_aarch32<llvm::endianness::little>( |
276 | (*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features), |
277 | ArmCfg) |
278 | .buildGraph(); |
279 | } |
280 | case Triple::armeb: |
281 | case Triple::thumbeb: { |
282 | auto &ELFFile = cast<ELFObjectFile<ELF32BE>>(Val&: **ELFObj).getELFFile(); |
283 | return ELFLinkGraphBuilder_aarch32<llvm::endianness::big>( |
284 | (*ELFObj)->getFileName(), ELFFile, TT, std::move(*Features), |
285 | ArmCfg) |
286 | .buildGraph(); |
287 | } |
288 | default: |
289 | return make_error<JITLinkError>( |
290 | Args: "Failed to build ELF/aarch32 link graph: Invalid target triple " + |
291 | TT.getTriple()); |
292 | } |
293 | } |
294 | |
295 | void link_ELF_aarch32(std::unique_ptr<LinkGraph> G, |
296 | std::unique_ptr<JITLinkContext> Ctx) { |
297 | const Triple &TT = G->getTargetTriple(); |
298 | |
299 | using namespace ARMBuildAttrs; |
300 | ARM::ArchKind AK = ARM::parseArch(Arch: TT.getArchName()); |
301 | auto CPU = static_cast<CPUArch>(ARM::getArchAttr(AK)); |
302 | aarch32::ArmConfig ArmCfg = aarch32::getArmConfigForCPUArch(CPUArch: CPU); |
303 | |
304 | PassConfiguration PassCfg; |
305 | if (Ctx->shouldAddDefaultTargetPasses(TT)) { |
306 | // Add a mark-live pass. |
307 | if (auto MarkLive = Ctx->getMarkLivePass(TT)) |
308 | PassCfg.PrePrunePasses.push_back(x: std::move(MarkLive)); |
309 | else |
310 | PassCfg.PrePrunePasses.push_back(x: markAllSymbolsLive); |
311 | |
312 | switch (ArmCfg.Stubs) { |
313 | case aarch32::StubsFlavor::pre_v7: |
314 | PassCfg.PostPrunePasses.push_back( |
315 | x: buildTables_ELF_aarch32<aarch32::StubsManager_prev7>); |
316 | break; |
317 | case aarch32::StubsFlavor::v7: |
318 | PassCfg.PostPrunePasses.push_back( |
319 | x: buildTables_ELF_aarch32<aarch32::StubsManager_v7>); |
320 | break; |
321 | case aarch32::StubsFlavor::Undefined: |
322 | llvm_unreachable("Check before building graph" ); |
323 | } |
324 | } |
325 | |
326 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config&: PassCfg)) |
327 | return Ctx->notifyFailed(Err: std::move(Err)); |
328 | |
329 | ELFJITLinker_aarch32::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(PassCfg), |
330 | Args: std::move(ArmCfg)); |
331 | } |
332 | |
333 | } // namespace jitlink |
334 | } // namespace llvm |
335 | |