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 "llvm/BinaryFormat/ELF.h" |
15 | #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" |
16 | #include "llvm/ExecutionEngine/JITLink/aarch64.h" |
17 | #include "llvm/Object/ELFObjectFile.h" |
18 | #include "llvm/Support/Endian.h" |
19 | |
20 | #include "DefineExternalSectionStartAndEndSymbols.h" |
21 | #include "EHFrameSupportImpl.h" |
22 | #include "ELFLinkGraphBuilder.h" |
23 | #include "JITLinkGeneric.h" |
24 | |
25 | #define DEBUG_TYPE "jitlink" |
26 | |
27 | using namespace llvm; |
28 | using namespace llvm::jitlink; |
29 | |
30 | namespace { |
31 | |
32 | constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_" ; |
33 | |
34 | class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> { |
35 | friend class JITLinker<ELFJITLinker_aarch64>; |
36 | |
37 | public: |
38 | ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx, |
39 | std::unique_ptr<LinkGraph> G, |
40 | PassConfiguration PassConfig) |
41 | : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) { |
42 | if (shouldAddDefaultTargetPasses(TT: getGraph().getTargetTriple())) |
43 | getPassConfig().PostAllocationPasses.push_back( |
44 | x: [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); }); |
45 | } |
46 | |
47 | private: |
48 | Symbol *GOTSymbol = nullptr; |
49 | |
50 | Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { |
51 | return aarch64::applyFixup(G, B, E, GOTSymbol); |
52 | } |
53 | |
54 | Error getOrCreateGOTSymbol(LinkGraph &G) { |
55 | auto InteredGOTSymbolName = |
56 | G.getSymbolStringPool()->intern(S: ELFGOTSymbolName); |
57 | |
58 | auto DefineExternalGOTSymbolIfPresent = |
59 | createDefineExternalSectionStartAndEndSymbolsPass( |
60 | F: [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc { |
61 | if (*Sym.getName() == ELFGOTSymbolName) |
62 | if (auto *GOTSection = G.findSectionByName( |
63 | Name: aarch64::GOTTableManager::getSectionName())) { |
64 | GOTSymbol = &Sym; |
65 | return {*GOTSection, true}; |
66 | } |
67 | return {}; |
68 | }); |
69 | |
70 | // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an |
71 | // external. |
72 | if (auto Err = DefineExternalGOTSymbolIfPresent(G)) |
73 | return Err; |
74 | |
75 | // If we succeeded then we're done. |
76 | if (GOTSymbol) |
77 | return Error::success(); |
78 | |
79 | // Otherwise look for a GOT section: If it already has a start symbol we'll |
80 | // record it, otherwise we'll create our own. |
81 | // If there's a GOT section but we didn't find an external GOT symbol... |
82 | if (auto *GOTSection = |
83 | G.findSectionByName(Name: aarch64::GOTTableManager::getSectionName())) { |
84 | |
85 | // Check for an existing defined symbol. |
86 | for (auto *Sym : GOTSection->symbols()) |
87 | if (Sym->getName() == InteredGOTSymbolName) { |
88 | GOTSymbol = Sym; |
89 | return Error::success(); |
90 | } |
91 | |
92 | // If there's no defined symbol then create one. |
93 | SectionRange SR(*GOTSection); |
94 | if (SR.empty()) |
95 | GOTSymbol = |
96 | // FIXME: we should only do this once |
97 | &G.addAbsoluteSymbol(Name: InteredGOTSymbolName, Address: orc::ExecutorAddr(), Size: 0, |
98 | L: Linkage::Strong, S: Scope::Local, IsLive: true); |
99 | else |
100 | GOTSymbol = |
101 | &G.addDefinedSymbol(Content&: *SR.getFirstBlock(), Offset: 0, Name: InteredGOTSymbolName, Size: 0, |
102 | L: Linkage::Strong, S: Scope::Local, IsCallable: false, IsLive: true); |
103 | } |
104 | |
105 | // If we still haven't found a GOT symbol then double check the externals. |
106 | // We may have a GOT-relative reference but no GOT section, in which case |
107 | // we just need to point the GOT symbol at some address in this graph. |
108 | if (!GOTSymbol) { |
109 | for (auto *Sym : G.external_symbols()) { |
110 | if (*Sym->getName() == ELFGOTSymbolName) { |
111 | auto Blocks = G.blocks(); |
112 | if (!Blocks.empty()) { |
113 | G.makeAbsolute(Sym&: *Sym, Address: (*Blocks.begin())->getAddress()); |
114 | GOTSymbol = Sym; |
115 | break; |
116 | } |
117 | } |
118 | } |
119 | } |
120 | |
121 | return Error::success(); |
122 | } |
123 | }; |
124 | |
125 | template <typename ELFT> |
126 | class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> { |
127 | private: |
128 | enum ELFAArch64RelocationKind : Edge::Kind { |
129 | ELFCall26 = Edge::FirstRelocation, |
130 | ELFLdrLo19, |
131 | ELFAdrLo21, |
132 | ELFAdrPage21, |
133 | ELFAddAbs12, |
134 | ELFLdSt8Abs12, |
135 | ELFLdSt16Abs12, |
136 | ELFLdSt32Abs12, |
137 | ELFLdSt64Abs12, |
138 | ELFLdSt128Abs12, |
139 | ELFMovwAbsG0, |
140 | ELFMovwAbsG1, |
141 | ELFMovwAbsG2, |
142 | ELFMovwAbsG3, |
143 | ELFTstBr14, |
144 | ELFCondBr19, |
145 | ELFAbs32, |
146 | ELFAbs64, |
147 | ELFPrel32, |
148 | ELFPrel64, |
149 | ELFAdrGOTPage21, |
150 | ELFLd64GOTLo12, |
151 | ELFLd64GOTPAGELo15, |
152 | ELFTLSDescAdrPage21, |
153 | ELFTLSDescAddLo12, |
154 | ELFTLSDescLd64Lo12, |
155 | ELFTLSDescCall, |
156 | }; |
157 | |
158 | static Expected<ELFAArch64RelocationKind> |
159 | getRelocationKind(const uint32_t Type) { |
160 | using namespace aarch64; |
161 | switch (Type) { |
162 | case ELF::R_AARCH64_CALL26: |
163 | case ELF::R_AARCH64_JUMP26: |
164 | return ELFCall26; |
165 | case ELF::R_AARCH64_LD_PREL_LO19: |
166 | return ELFLdrLo19; |
167 | case ELF::R_AARCH64_ADR_PREL_LO21: |
168 | return ELFAdrLo21; |
169 | case ELF::R_AARCH64_ADR_PREL_PG_HI21: |
170 | return ELFAdrPage21; |
171 | case ELF::R_AARCH64_ADD_ABS_LO12_NC: |
172 | return ELFAddAbs12; |
173 | case ELF::R_AARCH64_LDST8_ABS_LO12_NC: |
174 | return ELFLdSt8Abs12; |
175 | case ELF::R_AARCH64_LDST16_ABS_LO12_NC: |
176 | return ELFLdSt16Abs12; |
177 | case ELF::R_AARCH64_LDST32_ABS_LO12_NC: |
178 | return ELFLdSt32Abs12; |
179 | case ELF::R_AARCH64_LDST64_ABS_LO12_NC: |
180 | return ELFLdSt64Abs12; |
181 | case ELF::R_AARCH64_LDST128_ABS_LO12_NC: |
182 | return ELFLdSt128Abs12; |
183 | case ELF::R_AARCH64_MOVW_UABS_G0_NC: |
184 | return ELFMovwAbsG0; |
185 | case ELF::R_AARCH64_MOVW_UABS_G1_NC: |
186 | return ELFMovwAbsG1; |
187 | case ELF::R_AARCH64_MOVW_UABS_G2_NC: |
188 | return ELFMovwAbsG2; |
189 | case ELF::R_AARCH64_MOVW_UABS_G3: |
190 | return ELFMovwAbsG3; |
191 | case ELF::R_AARCH64_TSTBR14: |
192 | return ELFTstBr14; |
193 | case ELF::R_AARCH64_CONDBR19: |
194 | return ELFCondBr19; |
195 | case ELF::R_AARCH64_ABS32: |
196 | return ELFAbs32; |
197 | case ELF::R_AARCH64_ABS64: |
198 | return ELFAbs64; |
199 | case ELF::R_AARCH64_PREL32: |
200 | return ELFPrel32; |
201 | case ELF::R_AARCH64_PREL64: |
202 | return ELFPrel64; |
203 | case ELF::R_AARCH64_ADR_GOT_PAGE: |
204 | return ELFAdrGOTPage21; |
205 | case ELF::R_AARCH64_LD64_GOT_LO12_NC: |
206 | return ELFLd64GOTLo12; |
207 | case ELF::R_AARCH64_LD64_GOTPAGE_LO15: |
208 | return ELFLd64GOTPAGELo15; |
209 | case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: |
210 | return ELFTLSDescAdrPage21; |
211 | case ELF::R_AARCH64_TLSDESC_ADD_LO12: |
212 | return ELFTLSDescAddLo12; |
213 | case ELF::R_AARCH64_TLSDESC_LD64_LO12: |
214 | return ELFTLSDescLd64Lo12; |
215 | case ELF::R_AARCH64_TLSDESC_CALL: |
216 | return ELFTLSDescCall; |
217 | } |
218 | |
219 | return make_error<JITLinkError>( |
220 | Args: "Unsupported aarch64 relocation:" + formatv(Fmt: "{0:d}: " , Vals: Type) + |
221 | object::getELFRelocationTypeName(Machine: ELF::EM_AARCH64, Type)); |
222 | } |
223 | |
224 | Error addRelocations() override { |
225 | LLVM_DEBUG(dbgs() << "Processing relocations:\n" ); |
226 | |
227 | using Base = ELFLinkGraphBuilder<ELFT>; |
228 | using Self = ELFLinkGraphBuilder_aarch64<ELFT>; |
229 | for (const auto &RelSect : Base::Sections) |
230 | if (Error Err = Base::forEachRelaRelocation(RelSect, this, |
231 | &Self::addSingleRelocation)) |
232 | return Err; |
233 | |
234 | return Error::success(); |
235 | } |
236 | |
237 | Error addSingleRelocation(const typename ELFT::Rela &Rel, |
238 | const typename ELFT::Shdr &FixupSect, |
239 | Block &BlockToFix) { |
240 | using support::ulittle32_t; |
241 | using Base = ELFLinkGraphBuilder<ELFT>; |
242 | |
243 | uint32_t SymbolIndex = Rel.getSymbol(false); |
244 | auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); |
245 | if (!ObjSymbol) |
246 | return ObjSymbol.takeError(); |
247 | |
248 | Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); |
249 | if (!GraphSymbol) |
250 | return make_error<StringError>( |
251 | formatv("Could not find symbol at given index, did you add it to " |
252 | "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}" , |
253 | SymbolIndex, (*ObjSymbol)->st_shndx, |
254 | Base::GraphSymbols.size()), |
255 | inconvertibleErrorCode()); |
256 | |
257 | uint32_t Type = Rel.getType(false); |
258 | Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type); |
259 | if (!RelocKind) |
260 | return RelocKind.takeError(); |
261 | |
262 | int64_t Addend = Rel.r_addend; |
263 | orc::ExecutorAddr FixupAddress = |
264 | orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; |
265 | Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); |
266 | |
267 | // Get a pointer to the fixup content. |
268 | const void *FixupContent = BlockToFix.getContent().data() + |
269 | (FixupAddress - BlockToFix.getAddress()); |
270 | |
271 | Edge::Kind Kind = Edge::Invalid; |
272 | |
273 | switch (*RelocKind) { |
274 | case ELFCall26: { |
275 | Kind = aarch64::Branch26PCRel; |
276 | break; |
277 | } |
278 | case ELFLdrLo19: { |
279 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
280 | if (!aarch64::isLDRLiteral(Instr)) |
281 | return make_error<JITLinkError>( |
282 | Args: "R_AARCH64_LDR_PREL_LO19 target is not an LDR Literal instruction" ); |
283 | |
284 | Kind = aarch64::LDRLiteral19; |
285 | break; |
286 | } |
287 | case ELFAdrLo21: { |
288 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
289 | if (!aarch64::isADR(Instr)) |
290 | return make_error<JITLinkError>( |
291 | Args: "R_AARCH64_ADR_PREL_LO21 target is not an ADR instruction" ); |
292 | |
293 | Kind = aarch64::ADRLiteral21; |
294 | break; |
295 | } |
296 | case ELFAdrPage21: { |
297 | Kind = aarch64::Page21; |
298 | break; |
299 | } |
300 | case ELFAddAbs12: { |
301 | Kind = aarch64::PageOffset12; |
302 | break; |
303 | } |
304 | case ELFLdSt8Abs12: { |
305 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
306 | if (!aarch64::isLoadStoreImm12(Instr) || |
307 | aarch64::getPageOffset12Shift(Instr) != 0) |
308 | return make_error<JITLinkError>( |
309 | Args: "R_AARCH64_LDST8_ABS_LO12_NC target is not a " |
310 | "LDRB/STRB (imm12) instruction" ); |
311 | |
312 | Kind = aarch64::PageOffset12; |
313 | break; |
314 | } |
315 | case ELFLdSt16Abs12: { |
316 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
317 | if (!aarch64::isLoadStoreImm12(Instr) || |
318 | aarch64::getPageOffset12Shift(Instr) != 1) |
319 | return make_error<JITLinkError>( |
320 | Args: "R_AARCH64_LDST16_ABS_LO12_NC target is not a " |
321 | "LDRH/STRH (imm12) instruction" ); |
322 | |
323 | Kind = aarch64::PageOffset12; |
324 | break; |
325 | } |
326 | case ELFLdSt32Abs12: { |
327 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
328 | if (!aarch64::isLoadStoreImm12(Instr) || |
329 | aarch64::getPageOffset12Shift(Instr) != 2) |
330 | return make_error<JITLinkError>( |
331 | Args: "R_AARCH64_LDST32_ABS_LO12_NC target is not a " |
332 | "LDR/STR (imm12, 32 bit) instruction" ); |
333 | |
334 | Kind = aarch64::PageOffset12; |
335 | break; |
336 | } |
337 | case ELFLdSt64Abs12: { |
338 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
339 | if (!aarch64::isLoadStoreImm12(Instr) || |
340 | aarch64::getPageOffset12Shift(Instr) != 3) |
341 | return make_error<JITLinkError>( |
342 | Args: "R_AARCH64_LDST64_ABS_LO12_NC target is not a " |
343 | "LDR/STR (imm12, 64 bit) instruction" ); |
344 | |
345 | Kind = aarch64::PageOffset12; |
346 | break; |
347 | } |
348 | case ELFLdSt128Abs12: { |
349 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
350 | if (!aarch64::isLoadStoreImm12(Instr) || |
351 | aarch64::getPageOffset12Shift(Instr) != 4) |
352 | return make_error<JITLinkError>( |
353 | Args: "R_AARCH64_LDST128_ABS_LO12_NC target is not a " |
354 | "LDR/STR (imm12, 128 bit) instruction" ); |
355 | |
356 | Kind = aarch64::PageOffset12; |
357 | break; |
358 | } |
359 | case ELFMovwAbsG0: { |
360 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
361 | if (!aarch64::isMoveWideImm16(Instr) || |
362 | aarch64::getMoveWide16Shift(Instr) != 0) |
363 | return make_error<JITLinkError>( |
364 | Args: "R_AARCH64_MOVW_UABS_G0_NC target is not a " |
365 | "MOVK/MOVZ (imm16, LSL #0) instruction" ); |
366 | |
367 | Kind = aarch64::MoveWide16; |
368 | break; |
369 | } |
370 | case ELFMovwAbsG1: { |
371 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
372 | if (!aarch64::isMoveWideImm16(Instr) || |
373 | aarch64::getMoveWide16Shift(Instr) != 16) |
374 | return make_error<JITLinkError>( |
375 | Args: "R_AARCH64_MOVW_UABS_G1_NC target is not a " |
376 | "MOVK/MOVZ (imm16, LSL #16) instruction" ); |
377 | |
378 | Kind = aarch64::MoveWide16; |
379 | break; |
380 | } |
381 | case ELFMovwAbsG2: { |
382 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
383 | if (!aarch64::isMoveWideImm16(Instr) || |
384 | aarch64::getMoveWide16Shift(Instr) != 32) |
385 | return make_error<JITLinkError>( |
386 | Args: "R_AARCH64_MOVW_UABS_G2_NC target is not a " |
387 | "MOVK/MOVZ (imm16, LSL #32) instruction" ); |
388 | |
389 | Kind = aarch64::MoveWide16; |
390 | break; |
391 | } |
392 | case ELFMovwAbsG3: { |
393 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
394 | if (!aarch64::isMoveWideImm16(Instr) || |
395 | aarch64::getMoveWide16Shift(Instr) != 48) |
396 | return make_error<JITLinkError>( |
397 | Args: "R_AARCH64_MOVW_UABS_G3 target is not a " |
398 | "MOVK/MOVZ (imm16, LSL #48) instruction" ); |
399 | |
400 | Kind = aarch64::MoveWide16; |
401 | break; |
402 | } |
403 | case ELFTstBr14: { |
404 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
405 | if (!aarch64::isTestAndBranchImm14(Instr)) |
406 | return make_error<JITLinkError>(Args: "R_AARCH64_TSTBR14 target is not a " |
407 | "test and branch instruction" ); |
408 | |
409 | Kind = aarch64::TestAndBranch14PCRel; |
410 | break; |
411 | } |
412 | case ELFCondBr19: { |
413 | uint32_t Instr = *(const ulittle32_t *)FixupContent; |
414 | if (!aarch64::isCondBranchImm19(Instr) && |
415 | !aarch64::isCompAndBranchImm19(Instr)) |
416 | return make_error<JITLinkError>(Args: "R_AARCH64_CONDBR19 target is not a " |
417 | "conditional branch instruction" ); |
418 | |
419 | Kind = aarch64::CondBranch19PCRel; |
420 | break; |
421 | } |
422 | case ELFAbs32: { |
423 | Kind = aarch64::Pointer32; |
424 | break; |
425 | } |
426 | case ELFAbs64: { |
427 | Kind = aarch64::Pointer64; |
428 | break; |
429 | } |
430 | case ELFPrel32: { |
431 | Kind = aarch64::Delta32; |
432 | break; |
433 | } |
434 | case ELFPrel64: { |
435 | Kind = aarch64::Delta64; |
436 | break; |
437 | } |
438 | case ELFAdrGOTPage21: { |
439 | Kind = aarch64::RequestGOTAndTransformToPage21; |
440 | break; |
441 | } |
442 | case ELFLd64GOTLo12: { |
443 | Kind = aarch64::RequestGOTAndTransformToPageOffset12; |
444 | break; |
445 | } |
446 | case ELFLd64GOTPAGELo15: { |
447 | Kind = aarch64::RequestGOTAndTransformToPageOffset15; |
448 | break; |
449 | } |
450 | case ELFTLSDescAdrPage21: { |
451 | Kind = aarch64::RequestTLSDescEntryAndTransformToPage21; |
452 | break; |
453 | } |
454 | case ELFTLSDescAddLo12: |
455 | case ELFTLSDescLd64Lo12: { |
456 | Kind = aarch64::RequestTLSDescEntryAndTransformToPageOffset12; |
457 | break; |
458 | } |
459 | case ELFTLSDescCall: { |
460 | return Error::success(); |
461 | } |
462 | }; |
463 | |
464 | Edge GE(Kind, Offset, *GraphSymbol, Addend); |
465 | LLVM_DEBUG({ |
466 | dbgs() << " " ; |
467 | printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind)); |
468 | dbgs() << "\n" ; |
469 | }); |
470 | |
471 | BlockToFix.addEdge(E: std::move(GE)); |
472 | |
473 | return Error::success(); |
474 | } |
475 | |
476 | /// Return the string name of the given ELF aarch64 edge kind. |
477 | const char *getELFAArch64RelocationKindName(Edge::Kind R) { |
478 | switch (R) { |
479 | case ELFCall26: |
480 | return "ELFCall26" ; |
481 | case ELFAdrPage21: |
482 | return "ELFAdrPage21" ; |
483 | case ELFAddAbs12: |
484 | return "ELFAddAbs12" ; |
485 | case ELFLdSt8Abs12: |
486 | return "ELFLdSt8Abs12" ; |
487 | case ELFLdSt16Abs12: |
488 | return "ELFLdSt16Abs12" ; |
489 | case ELFLdSt32Abs12: |
490 | return "ELFLdSt32Abs12" ; |
491 | case ELFLdSt64Abs12: |
492 | return "ELFLdSt64Abs12" ; |
493 | case ELFLdSt128Abs12: |
494 | return "ELFLdSt128Abs12" ; |
495 | case ELFMovwAbsG0: |
496 | return "ELFMovwAbsG0" ; |
497 | case ELFMovwAbsG1: |
498 | return "ELFMovwAbsG1" ; |
499 | case ELFMovwAbsG2: |
500 | return "ELFMovwAbsG2" ; |
501 | case ELFMovwAbsG3: |
502 | return "ELFMovwAbsG3" ; |
503 | case ELFAbs32: |
504 | return "ELFAbs32" ; |
505 | case ELFAbs64: |
506 | return "ELFAbs64" ; |
507 | case ELFPrel32: |
508 | return "ELFPrel32" ; |
509 | case ELFPrel64: |
510 | return "ELFPrel64" ; |
511 | case ELFAdrGOTPage21: |
512 | return "ELFAdrGOTPage21" ; |
513 | case ELFLd64GOTLo12: |
514 | return "ELFLd64GOTLo12" ; |
515 | case ELFLd64GOTPAGELo15: |
516 | return "ELFLd64GOTPAGELo15" ; |
517 | case ELFTLSDescAdrPage21: |
518 | return "ELFTLSDescAdrPage21" ; |
519 | case ELFTLSDescAddLo12: |
520 | return "ELFTLSDescAddLo12" ; |
521 | case ELFTLSDescLd64Lo12: |
522 | return "ELFTLSDescLd64Lo12" ; |
523 | case ELFTLSDescCall: |
524 | return "ELFTLSDescCall" ; |
525 | default: |
526 | return getGenericEdgeKindName(K: R); |
527 | } |
528 | } |
529 | |
530 | public: |
531 | ELFLinkGraphBuilder_aarch64(StringRef FileName, |
532 | const object::ELFFile<ELFT> &Obj, |
533 | std::shared_ptr<orc::SymbolStringPool> SSP, |
534 | Triple TT, SubtargetFeatures Features) |
535 | |
536 | : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT), |
537 | std::move(Features), FileName, |
538 | aarch64::getEdgeKindName) {} |
539 | }; |
540 | |
541 | // TLS Info Builder. |
542 | class TLSInfoTableManager_ELF_aarch64 |
543 | : public TableManager<TLSInfoTableManager_ELF_aarch64> { |
544 | public: |
545 | static StringRef getSectionName() { return "$__TLSINFO" ; } |
546 | |
547 | static const uint8_t TLSInfoEntryContent[16]; |
548 | |
549 | bool visitEdge(LinkGraph &G, Block *B, Edge &E) { return false; } |
550 | |
551 | Symbol &createEntry(LinkGraph &G, Symbol &Target) { |
552 | // the TLS Info entry's key value will be written by the fixTLVSectionByName |
553 | // pass, so create mutable content. |
554 | auto &TLSInfoEntry = G.createMutableContentBlock( |
555 | Parent&: getTLSInfoSection(G), MutableContent: G.allocateContent(Source: getTLSInfoEntryContent()), |
556 | Address: orc::ExecutorAddr(), Alignment: 8, AlignmentOffset: 0); |
557 | TLSInfoEntry.addEdge(K: aarch64::Pointer64, Offset: 8, Target, Addend: 0); |
558 | return G.addAnonymousSymbol(Content&: TLSInfoEntry, Offset: 0, Size: 16, IsCallable: false, IsLive: false); |
559 | } |
560 | |
561 | private: |
562 | Section &getTLSInfoSection(LinkGraph &G) { |
563 | if (!TLSInfoTable) |
564 | TLSInfoTable = &G.createSection(Name: getSectionName(), Prot: orc::MemProt::Read); |
565 | return *TLSInfoTable; |
566 | } |
567 | |
568 | ArrayRef<char> getTLSInfoEntryContent() const { |
569 | return {reinterpret_cast<const char *>(TLSInfoEntryContent), |
570 | sizeof(TLSInfoEntryContent)}; |
571 | } |
572 | |
573 | Section *TLSInfoTable = nullptr; |
574 | }; |
575 | |
576 | const uint8_t TLSInfoTableManager_ELF_aarch64::TLSInfoEntryContent[16] = { |
577 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ |
578 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ |
579 | }; |
580 | |
581 | // TLS Descriptor Builder. |
582 | class TLSDescTableManager_ELF_aarch64 |
583 | : public TableManager<TLSDescTableManager_ELF_aarch64> { |
584 | public: |
585 | TLSDescTableManager_ELF_aarch64( |
586 | TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager) |
587 | : TLSInfoTableManager(TLSInfoTableManager) {} |
588 | |
589 | static StringRef getSectionName() { return "$__TLSDESC" ; } |
590 | |
591 | static const uint8_t TLSDescEntryContent[16]; |
592 | |
593 | bool visitEdge(LinkGraph &G, Block *B, Edge &E) { |
594 | Edge::Kind KindToSet = Edge::Invalid; |
595 | switch (E.getKind()) { |
596 | case aarch64::RequestTLSDescEntryAndTransformToPage21: { |
597 | KindToSet = aarch64::Page21; |
598 | break; |
599 | } |
600 | case aarch64::RequestTLSDescEntryAndTransformToPageOffset12: { |
601 | KindToSet = aarch64::PageOffset12; |
602 | break; |
603 | } |
604 | default: |
605 | return false; |
606 | } |
607 | assert(KindToSet != Edge::Invalid && |
608 | "Fell through switch, but no new kind to set" ); |
609 | DEBUG_WITH_TYPE("jitlink" , { |
610 | dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " |
611 | << B->getFixupAddress(E) << " (" << B->getAddress() << " + " |
612 | << formatv("{0:x}" , E.getOffset()) << ")\n" ; |
613 | }); |
614 | E.setKind(KindToSet); |
615 | E.setTarget(getEntryForTarget(G, Target&: E.getTarget())); |
616 | return true; |
617 | } |
618 | |
619 | Symbol &createEntry(LinkGraph &G, Symbol &Target) { |
620 | auto &EntryBlock = |
621 | G.createContentBlock(Parent&: getTLSDescSection(G), Content: getTLSDescBlockContent(), |
622 | Address: orc::ExecutorAddr(), Alignment: 8, AlignmentOffset: 0); |
623 | EntryBlock.addEdge(K: aarch64::Pointer64, Offset: 0, Target&: getTLSDescResolver(G), Addend: 0); |
624 | EntryBlock.addEdge(K: aarch64::Pointer64, Offset: 8, |
625 | Target&: TLSInfoTableManager.getEntryForTarget(G, Target), Addend: 0); |
626 | return G.addAnonymousSymbol(Content&: EntryBlock, Offset: 0, Size: 8, IsCallable: false, IsLive: false); |
627 | } |
628 | |
629 | private: |
630 | Section &getTLSDescSection(LinkGraph &G) { |
631 | if (!GOTSection) |
632 | GOTSection = &G.createSection(Name: getSectionName(), Prot: orc::MemProt::Read); |
633 | return *GOTSection; |
634 | } |
635 | |
636 | Symbol &getTLSDescResolver(LinkGraph &G) { |
637 | if (!TLSDescResolver) |
638 | TLSDescResolver = &G.addExternalSymbol(Name: "__tlsdesc_resolver" , Size: 8, IsWeaklyReferenced: false); |
639 | return *TLSDescResolver; |
640 | } |
641 | |
642 | ArrayRef<char> getTLSDescBlockContent() { |
643 | return {reinterpret_cast<const char *>(TLSDescEntryContent), |
644 | sizeof(TLSDescEntryContent)}; |
645 | } |
646 | |
647 | Section *GOTSection = nullptr; |
648 | Symbol *TLSDescResolver = nullptr; |
649 | TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager; |
650 | }; |
651 | |
652 | const uint8_t TLSDescTableManager_ELF_aarch64::TLSDescEntryContent[16] = { |
653 | 0x00, 0x00, 0x00, 0x00, |
654 | 0x00, 0x00, 0x00, 0x00, /*resolver function pointer*/ |
655 | 0x00, 0x00, 0x00, 0x00, |
656 | 0x00, 0x00, 0x00, 0x00 /*pointer to tls info*/ |
657 | }; |
658 | |
659 | Error buildTables_ELF_aarch64(LinkGraph &G) { |
660 | LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n" ); |
661 | |
662 | aarch64::GOTTableManager GOT(G); |
663 | aarch64::PLTTableManager PLT(G, GOT); |
664 | TLSInfoTableManager_ELF_aarch64 TLSInfo; |
665 | TLSDescTableManager_ELF_aarch64 TLSDesc(TLSInfo); |
666 | visitExistingEdges(G, Vs&: GOT, Vs&: PLT, Vs&: TLSDesc, Vs&: TLSInfo); |
667 | return Error::success(); |
668 | } |
669 | |
670 | } // namespace |
671 | |
672 | namespace llvm { |
673 | namespace jitlink { |
674 | |
675 | Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_aarch64( |
676 | MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { |
677 | LLVM_DEBUG({ |
678 | dbgs() << "Building jitlink graph for new input " |
679 | << ObjectBuffer.getBufferIdentifier() << "...\n" ; |
680 | }); |
681 | |
682 | auto ELFObj = object::ObjectFile::createELFObjectFile(Object: ObjectBuffer); |
683 | if (!ELFObj) |
684 | return ELFObj.takeError(); |
685 | |
686 | auto Features = (*ELFObj)->getFeatures(); |
687 | if (!Features) |
688 | return Features.takeError(); |
689 | |
690 | assert((*ELFObj)->getArch() == Triple::aarch64 && |
691 | "Only AArch64 (little endian) is supported for now" ); |
692 | |
693 | auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(Val&: **ELFObj); |
694 | return ELFLinkGraphBuilder_aarch64<object::ELF64LE>( |
695 | (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP), |
696 | (*ELFObj)->makeTriple(), std::move(*Features)) |
697 | .buildGraph(); |
698 | } |
699 | |
700 | void link_ELF_aarch64(std::unique_ptr<LinkGraph> G, |
701 | std::unique_ptr<JITLinkContext> Ctx) { |
702 | PassConfiguration Config; |
703 | const Triple &TT = G->getTargetTriple(); |
704 | if (Ctx->shouldAddDefaultTargetPasses(TT)) { |
705 | // Add eh-frame passes. |
706 | Config.PrePrunePasses.push_back(x: DWARFRecordSectionSplitter(".eh_frame" )); |
707 | Config.PrePrunePasses.push_back(x: EHFrameEdgeFixer( |
708 | ".eh_frame" , 8, aarch64::Pointer32, aarch64::Pointer64, |
709 | aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32)); |
710 | Config.PrePrunePasses.push_back(x: EHFrameNullTerminator(".eh_frame" )); |
711 | |
712 | // Add a mark-live pass. |
713 | if (auto MarkLive = Ctx->getMarkLivePass(TT)) |
714 | Config.PrePrunePasses.push_back(x: std::move(MarkLive)); |
715 | else |
716 | Config.PrePrunePasses.push_back(x: markAllSymbolsLive); |
717 | |
718 | // Resolve any external section start / end symbols. |
719 | Config.PostAllocationPasses.push_back( |
720 | x: createDefineExternalSectionStartAndEndSymbolsPass( |
721 | F&: identifyELFSectionStartAndEndSymbols)); |
722 | |
723 | // Add an in-place GOT/TLS/Stubs build pass. |
724 | Config.PostPrunePasses.push_back(x: buildTables_ELF_aarch64); |
725 | } |
726 | |
727 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config)) |
728 | return Ctx->notifyFailed(Err: std::move(Err)); |
729 | |
730 | ELFJITLinker_aarch64::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(Config)); |
731 | } |
732 | |
733 | } // namespace jitlink |
734 | } // namespace llvm |
735 | |