[mlir][py] Enable loading only specified dialects during creation. (#121421)
[llvm-project.git] / lld / ELF / Thunks.cpp
blob4e4e0684a3f596825388d15b1d40010fd3c1051d
1 //===- Thunks.cpp --------------------------------------------------------===//
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 // This file contains Thunk subclasses.
11 // A thunk is a small piece of code written after an input section
12 // which is used to jump between "incompatible" functions
13 // such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions.
15 // If a jump target is too far and its address doesn't fit to a
16 // short jump instruction, we need to create a thunk too, but we
17 // haven't supported it yet.
19 // i386 and x86-64 don't need thunks.
21 //===---------------------------------------------------------------------===//
23 #include "Thunks.h"
24 #include "Config.h"
25 #include "InputFiles.h"
26 #include "InputSection.h"
27 #include "OutputSections.h"
28 #include "Symbols.h"
29 #include "SyntheticSections.h"
30 #include "Target.h"
31 #include "lld/Common/CommonLinkerContext.h"
32 #include "llvm/BinaryFormat/ELF.h"
33 #include "llvm/Support/Casting.h"
34 #include "llvm/Support/ErrorHandling.h"
35 #include "llvm/Support/MathExtras.h"
36 #include <cstdint>
37 #include <cstring>
39 using namespace llvm;
40 using namespace llvm::object;
41 using namespace llvm::ELF;
42 using namespace lld;
43 using namespace lld::elf;
45 namespace {
47 // Base class for AArch64 thunks.
49 // An AArch64 thunk may be either short or long. A short thunk is simply a
50 // branch (B) instruction, and it may be used to call AArch64 functions when the
51 // distance from the thunk to the target is less than 128MB. Long thunks can
52 // branch to any virtual address and they are implemented in the derived
53 // classes. This class tries to create a short thunk if the target is in range,
54 // otherwise it creates a long thunk. When BTI is enabled indirect branches
55 // must land on a BTI instruction. If the destination does not have a BTI
56 // instruction mayNeedLandingPad is set to true and Thunk::landingPad points
57 // to an alternative entry point with a BTI.
58 class AArch64Thunk : public Thunk {
59 public:
60 AArch64Thunk(Ctx &ctx, Symbol &dest, int64_t addend, bool mayNeedLandingPad)
61 : Thunk(ctx, dest, addend), mayNeedLandingPad(mayNeedLandingPad) {}
62 bool getMayUseShortThunk();
63 void writeTo(uint8_t *buf) override;
64 bool needsSyntheticLandingPad() override;
66 protected:
67 bool mayNeedLandingPad;
69 private:
70 bool mayUseShortThunk = true;
71 virtual void writeLong(uint8_t *buf) = 0;
72 // A thunk may be written out as a short or long, and we may not know which
73 // type at thunk creation time. In some thunk implementations the long thunk
74 // has additional mapping symbols. Thus function can be overridden to add
75 // these additional mapping symbols.
76 virtual void addLongMapSyms() {}
79 // AArch64 long range Thunks.
80 class AArch64ABSLongThunk final : public AArch64Thunk {
81 public:
82 AArch64ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,
83 bool mayNeedLandingPad)
84 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
85 uint32_t size() override { return getMayUseShortThunk() ? 4 : 16; }
86 void addSymbols(ThunkSection &isec) override;
88 private:
89 void writeLong(uint8_t *buf) override;
90 void addLongMapSyms() override;
91 ThunkSection *tsec = nullptr;
94 class AArch64ADRPThunk final : public AArch64Thunk {
95 public:
96 AArch64ADRPThunk(Ctx &ctx, Symbol &dest, int64_t addend,
97 bool mayNeedLandingPad)
98 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
99 uint32_t size() override { return getMayUseShortThunk() ? 4 : 12; }
100 void addSymbols(ThunkSection &isec) override;
102 private:
103 void writeLong(uint8_t *buf) override;
106 // AArch64 BTI Landing Pad
107 // When BTI is enabled indirect branches must land on a BTI
108 // compatible instruction. When the destination does not have a
109 // BTI compatible instruction a Thunk doing an indirect branch
110 // targets a Landing Pad Thunk that direct branches to the target.
111 class AArch64BTILandingPadThunk final : public Thunk {
112 public:
113 AArch64BTILandingPadThunk(Ctx &ctx, Symbol &dest, int64_t addend)
114 : Thunk(ctx, dest, addend) {}
116 uint32_t size() override { return getMayUseShortThunk() ? 4 : 8; }
117 void addSymbols(ThunkSection &isec) override;
118 void writeTo(uint8_t *buf) override;
120 private:
121 bool getMayUseShortThunk();
122 void writeLong(uint8_t *buf);
123 bool mayUseShortThunk = true;
126 // Base class for ARM thunks.
128 // An ARM thunk may be either short or long. A short thunk is simply a branch
129 // (B) instruction, and it may be used to call ARM functions when the distance
130 // from the thunk to the target is less than 32MB. Long thunks can branch to any
131 // virtual address and can switch between ARM and Thumb, and they are
132 // implemented in the derived classes. This class tries to create a short thunk
133 // if the target is in range, otherwise it creates a long thunk.
134 class ARMThunk : public Thunk {
135 public:
136 ARMThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}
138 bool getMayUseShortThunk();
139 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
140 void writeTo(uint8_t *buf) override;
141 bool isCompatibleWith(const InputSection &isec,
142 const Relocation &rel) const override;
144 // Returns the size of a long thunk.
145 virtual uint32_t sizeLong() = 0;
147 // Writes a long thunk to Buf.
148 virtual void writeLong(uint8_t *buf) = 0;
150 private:
151 // This field tracks whether all previously considered layouts would allow
152 // this thunk to be short. If we have ever needed a long thunk, we always
153 // create a long thunk, even if the thunk may be short given the current
154 // distance to the target. We do this because transitioning from long to short
155 // can create layout oscillations in certain corner cases which would prevent
156 // the layout from converging.
157 bool mayUseShortThunk = true;
158 // See comment in AArch64Thunk.
159 virtual void addLongMapSyms() {}
162 // Base class for Thumb-2 thunks.
164 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
165 // which has a range of 16MB.
166 class ThumbThunk : public Thunk {
167 public:
168 ThumbThunk(Ctx &ctx, Symbol &dest, int64_t addend)
169 : Thunk(ctx, dest, addend) {
170 alignment = 2;
173 bool getMayUseShortThunk();
174 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
175 void writeTo(uint8_t *buf) override;
176 bool isCompatibleWith(const InputSection &isec,
177 const Relocation &rel) const override;
179 // Returns the size of a long thunk.
180 virtual uint32_t sizeLong() = 0;
182 // Writes a long thunk to Buf.
183 virtual void writeLong(uint8_t *buf) = 0;
185 private:
186 // See comment in ARMThunk above.
187 bool mayUseShortThunk = true;
188 // See comment in AArch64Thunk.
189 virtual void addLongMapSyms() {}
192 // Specific ARM Thunk implementations. The naming convention is:
193 // Source State, TargetState, Target Requirement, ABS or PI, Range
194 class ARMV7ABSLongThunk final : public ARMThunk {
195 public:
196 ARMV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
197 : ARMThunk(ctx, dest, addend) {}
199 uint32_t sizeLong() override { return 12; }
200 void writeLong(uint8_t *buf) override;
201 void addSymbols(ThunkSection &isec) override;
204 class ARMV7PILongThunk final : public ARMThunk {
205 public:
206 ARMV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
207 : ARMThunk(ctx, dest, addend) {}
209 uint32_t sizeLong() override { return 16; }
210 void writeLong(uint8_t *buf) override;
211 void addSymbols(ThunkSection &isec) override;
214 class ThumbV7ABSLongThunk final : public ThumbThunk {
215 public:
216 ThumbV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
217 : ThumbThunk(ctx, dest, addend) {}
219 uint32_t sizeLong() override { return 10; }
220 void writeLong(uint8_t *buf) override;
221 void addSymbols(ThunkSection &isec) override;
224 class ThumbV7PILongThunk final : public ThumbThunk {
225 public:
226 ThumbV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
227 : ThumbThunk(ctx, dest, addend) {}
229 uint32_t sizeLong() override { return 12; }
230 void writeLong(uint8_t *buf) override;
231 void addSymbols(ThunkSection &isec) override;
234 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
235 class ThumbV6MABSLongThunk final : public ThumbThunk {
236 public:
237 ThumbV6MABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
238 : ThumbThunk(ctx, dest, addend) {}
240 uint32_t sizeLong() override { return 12; }
241 void writeLong(uint8_t *buf) override;
242 void addSymbols(ThunkSection &isec) override;
244 private:
245 void addLongMapSyms() override;
246 ThunkSection *tsec = nullptr;
249 class ThumbV6MABSXOLongThunk final : public ThumbThunk {
250 public:
251 ThumbV6MABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
252 : ThumbThunk(ctx, dest, addend) {}
254 uint32_t sizeLong() override { return 20; }
255 void writeLong(uint8_t *buf) override;
256 void addSymbols(ThunkSection &isec) override;
259 class ThumbV6MPILongThunk final : public ThumbThunk {
260 public:
261 ThumbV6MPILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
262 : ThumbThunk(ctx, dest, addend) {}
264 uint32_t sizeLong() override { return 16; }
265 void writeLong(uint8_t *buf) override;
266 void addSymbols(ThunkSection &isec) override;
268 private:
269 void addLongMapSyms() override;
270 ThunkSection *tsec = nullptr;
273 // Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
274 // v6 support BLX to which BL instructions can be rewritten inline. There are no
275 // Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on
276 // these architecture that can result in a thunk.
278 // LDR on v5 and v6 can switch processor state, so for v5 and v6,
279 // ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4
280 // can also use this thunk, but only for Arm->Arm calls.
281 class ARMV5LongLdrPcThunk final : public ARMThunk {
282 public:
283 ARMV5LongLdrPcThunk(Ctx &ctx, Symbol &dest, int64_t addend)
284 : ARMThunk(ctx, dest, addend) {}
286 uint32_t sizeLong() override { return 8; }
287 void writeLong(uint8_t *buf) override;
288 void addSymbols(ThunkSection &isec) override;
290 private:
291 void addLongMapSyms() override;
292 ThunkSection *tsec = nullptr;
295 // Implementations of Thunks for v4. BLX is not supported, and loads
296 // will not invoke Arm/Thumb state changes.
297 class ARMV4PILongBXThunk final : public ARMThunk {
298 public:
299 ARMV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
300 : ARMThunk(ctx, dest, addend) {}
302 uint32_t sizeLong() override { return 16; }
303 void writeLong(uint8_t *buf) override;
304 void addSymbols(ThunkSection &isec) override;
306 private:
307 void addLongMapSyms() override;
308 ThunkSection *tsec = nullptr;
311 class ARMV4PILongThunk final : public ARMThunk {
312 public:
313 ARMV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
314 : ARMThunk(ctx, dest, addend) {}
316 uint32_t sizeLong() override { return 12; }
317 void writeLong(uint8_t *buf) override;
318 void addSymbols(ThunkSection &isec) override;
320 private:
321 void addLongMapSyms() override;
322 ThunkSection *tsec = nullptr;
325 class ThumbV4PILongBXThunk final : public ThumbThunk {
326 public:
327 ThumbV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
328 : ThumbThunk(ctx, dest, addend) {}
330 uint32_t sizeLong() override { return 16; }
331 void writeLong(uint8_t *buf) override;
332 void addSymbols(ThunkSection &isec) override;
334 private:
335 void addLongMapSyms() override;
336 ThunkSection *tsec = nullptr;
339 class ThumbV4PILongThunk final : public ThumbThunk {
340 public:
341 ThumbV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
342 : ThumbThunk(ctx, dest, addend) {}
344 uint32_t sizeLong() override { return 20; }
345 void writeLong(uint8_t *buf) override;
346 void addSymbols(ThunkSection &isec) override;
348 private:
349 void addLongMapSyms() override;
350 ThunkSection *tsec = nullptr;
353 class ARMV4ABSLongBXThunk final : public ARMThunk {
354 public:
355 ARMV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
356 : ARMThunk(ctx, dest, addend) {}
358 uint32_t sizeLong() override { return 12; }
359 void writeLong(uint8_t *buf) override;
360 void addSymbols(ThunkSection &isec) override;
362 private:
363 void addLongMapSyms() override;
364 ThunkSection *tsec = nullptr;
367 class ThumbV4ABSLongBXThunk final : public ThumbThunk {
368 public:
369 ThumbV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
370 : ThumbThunk(ctx, dest, addend) {}
372 uint32_t sizeLong() override { return 12; }
373 void writeLong(uint8_t *buf) override;
374 void addSymbols(ThunkSection &isec) override;
376 private:
377 void addLongMapSyms() override;
378 ThunkSection *tsec = nullptr;
381 class ThumbV4ABSLongThunk final : public ThumbThunk {
382 public:
383 ThumbV4ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
384 : ThumbThunk(ctx, dest, addend) {}
386 uint32_t sizeLong() override { return 16; }
387 void writeLong(uint8_t *buf) override;
388 void addSymbols(ThunkSection &isec) override;
390 private:
391 void addLongMapSyms() override;
392 ThunkSection *tsec = nullptr;
395 // The AVR devices need thunks for R_AVR_LO8_LDI_GS/R_AVR_HI8_LDI_GS
396 // when their destination is out of range [0, 0x1ffff].
397 class AVRThunk : public Thunk {
398 public:
399 AVRThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}
400 uint32_t size() override { return 4; }
401 void writeTo(uint8_t *buf) override;
402 void addSymbols(ThunkSection &isec) override;
405 // MIPS LA25 thunk
406 class MipsThunk final : public Thunk {
407 public:
408 MipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
410 uint32_t size() override { return 16; }
411 void writeTo(uint8_t *buf) override;
412 void addSymbols(ThunkSection &isec) override;
413 InputSection *getTargetInputSection() const override;
416 // microMIPS R2-R5 LA25 thunk
417 class MicroMipsThunk final : public Thunk {
418 public:
419 MicroMipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
421 uint32_t size() override { return 14; }
422 void writeTo(uint8_t *buf) override;
423 void addSymbols(ThunkSection &isec) override;
424 InputSection *getTargetInputSection() const override;
427 // microMIPS R6 LA25 thunk
428 class MicroMipsR6Thunk final : public Thunk {
429 public:
430 MicroMipsR6Thunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
432 uint32_t size() override { return 12; }
433 void writeTo(uint8_t *buf) override;
434 void addSymbols(ThunkSection &isec) override;
435 InputSection *getTargetInputSection() const override;
438 class PPC32PltCallStub final : public Thunk {
439 public:
440 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
441 // decide the offsets in the call stub.
442 PPC32PltCallStub(Ctx &ctx, const InputSection &isec, const Relocation &rel,
443 Symbol &dest)
444 : Thunk(ctx, dest, rel.addend), file(isec.file) {}
445 uint32_t size() override { return 16; }
446 void writeTo(uint8_t *buf) override;
447 void addSymbols(ThunkSection &isec) override;
448 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
450 private:
451 // Records the call site of the call stub.
452 const InputFile *file;
455 class PPC32LongThunk final : public Thunk {
456 public:
457 PPC32LongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
458 : Thunk(ctx, dest, addend) {}
459 uint32_t size() override { return ctx.arg.isPic ? 32 : 16; }
460 void writeTo(uint8_t *buf) override;
461 void addSymbols(ThunkSection &isec) override;
464 // PPC64 Plt call stubs.
465 // Any call site that needs to call through a plt entry needs a call stub in
466 // the .text section. The call stub is responsible for:
467 // 1) Saving the toc-pointer to the stack.
468 // 2) Loading the target functions address from the procedure linkage table into
469 // r12 for use by the target functions global entry point, and into the count
470 // register.
471 // 3) Transferring control to the target function through an indirect branch.
472 class PPC64PltCallStub final : public Thunk {
473 public:
474 PPC64PltCallStub(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
475 uint32_t size() override { return 20; }
476 void writeTo(uint8_t *buf) override;
477 void addSymbols(ThunkSection &isec) override;
478 bool isCompatibleWith(const InputSection &isec,
479 const Relocation &rel) const override;
482 // PPC64 R2 Save Stub
483 // When the caller requires a valid R2 TOC pointer but the callee does not
484 // require a TOC pointer and the callee cannot guarantee that it doesn't
485 // clobber R2 then we need to save R2. This stub:
486 // 1) Saves the TOC pointer to the stack.
487 // 2) Tail calls the callee.
488 class PPC64R2SaveStub final : public Thunk {
489 public:
490 PPC64R2SaveStub(Ctx &ctx, Symbol &dest, int64_t addend)
491 : Thunk(ctx, dest, addend) {
492 alignment = 16;
495 // To prevent oscillations in layout when moving from short to long thunks
496 // we make sure that once a thunk has been set to long it cannot go back.
497 bool getMayUseShortThunk() {
498 if (!mayUseShortThunk)
499 return false;
500 if (!isInt<26>(computeOffset())) {
501 mayUseShortThunk = false;
502 return false;
504 return true;
506 uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
507 void writeTo(uint8_t *buf) override;
508 void addSymbols(ThunkSection &isec) override;
509 bool isCompatibleWith(const InputSection &isec,
510 const Relocation &rel) const override;
512 private:
513 // Transitioning from long to short can create layout oscillations in
514 // certain corner cases which would prevent the layout from converging.
515 // This is similar to the handling for ARMThunk.
516 bool mayUseShortThunk = true;
517 int64_t computeOffset() const {
518 return destination.getVA(ctx) - (getThunkTargetSym()->getVA(ctx) + 4);
522 // PPC64 R12 Setup Stub
523 // When a caller that does not maintain TOC calls a target which may possibly
524 // use TOC (either non-preemptible with localentry>1 or preemptible), we need to
525 // set r12 to satisfy the requirement of the global entry point.
526 class PPC64R12SetupStub final : public Thunk {
527 public:
528 PPC64R12SetupStub(Ctx &ctx, Symbol &dest, bool gotPlt)
529 : Thunk(ctx, dest, 0), gotPlt(gotPlt) {
530 alignment = 16;
532 uint32_t size() override { return 32; }
533 void writeTo(uint8_t *buf) override;
534 void addSymbols(ThunkSection &isec) override;
535 bool isCompatibleWith(const InputSection &isec,
536 const Relocation &rel) const override;
538 private:
539 bool gotPlt;
542 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
543 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
544 // larger than that we need to emit a long-branch thunk. The target address
545 // of the callee is stored in a table to be accessed TOC-relative. Since the
546 // call must be local (a non-local call will have a PltCallStub instead) the
547 // table stores the address of the callee's local entry point. For
548 // position-independent code a corresponding relative dynamic relocation is
549 // used.
550 class PPC64LongBranchThunk : public Thunk {
551 public:
552 uint32_t size() override { return 32; }
553 void writeTo(uint8_t *buf) override;
554 void addSymbols(ThunkSection &isec) override;
555 bool isCompatibleWith(const InputSection &isec,
556 const Relocation &rel) const override;
558 protected:
559 PPC64LongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
560 : Thunk(ctx, dest, addend) {}
563 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
564 public:
565 PPC64PILongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
566 : PPC64LongBranchThunk(ctx, dest, addend) {
567 assert(!dest.isPreemptible);
568 if (std::optional<uint32_t> index =
569 ctx.in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
570 ctx.mainPart->relaDyn->addRelativeReloc(
571 ctx.target->relativeRel, *ctx.in.ppc64LongBranchTarget,
572 *index * UINT64_C(8), dest,
573 addend + getPPC64GlobalEntryToLocalEntryOffset(ctx, dest.stOther),
574 ctx.target->symbolicRel, R_ABS);
579 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
580 public:
581 PPC64PDLongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
582 : PPC64LongBranchThunk(ctx, dest, addend) {
583 ctx.in.ppc64LongBranchTarget->addEntry(&dest, addend);
587 } // end anonymous namespace
589 Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
590 InputSectionBase &section) {
591 Defined *d = addSyntheticLocal(ctx, name, type, value, /*size=*/0, section);
592 syms.push_back(d);
593 return d;
596 void Thunk::setOffset(uint64_t newOffset) {
597 for (Defined *d : syms)
598 d->value = d->value - offset + newOffset;
599 offset = newOffset;
602 // AArch64 Thunk base class.
603 static uint64_t getAArch64ThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
604 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a);
605 return v;
608 bool AArch64Thunk::getMayUseShortThunk() {
609 if (!mayUseShortThunk)
610 return false;
611 uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend);
612 uint64_t p = getThunkTargetSym()->getVA(ctx);
613 mayUseShortThunk = llvm::isInt<28>(s - p);
614 if (!mayUseShortThunk)
615 addLongMapSyms();
616 return mayUseShortThunk;
619 void AArch64Thunk::writeTo(uint8_t *buf) {
620 if (!getMayUseShortThunk()) {
621 writeLong(buf);
622 return;
624 uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend);
625 uint64_t p = getThunkTargetSym()->getVA(ctx);
626 write32(ctx, buf, 0x14000000); // b S
627 ctx.target->relocateNoSym(buf, R_AARCH64_CALL26, s - p);
630 bool AArch64Thunk::needsSyntheticLandingPad() {
631 // Short Thunks use a direct branch, no synthetic landing pad
632 // required.
633 return mayNeedLandingPad && !getMayUseShortThunk();
636 // AArch64 long range Thunks.
637 void AArch64ABSLongThunk::writeLong(uint8_t *buf) {
638 const uint8_t data[] = {
639 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
640 0x00, 0x02, 0x1f, 0xd6, // br x16
641 0x00, 0x00, 0x00, 0x00, // L0: .xword S
642 0x00, 0x00, 0x00, 0x00,
644 // If mayNeedLandingPad is true then destination is an
645 // AArch64BTILandingPadThunk that defines landingPad.
646 assert(!mayNeedLandingPad || landingPad != nullptr);
647 uint64_t s = mayNeedLandingPad
648 ? landingPad->getVA(ctx, 0)
649 : getAArch64ThunkDestVA(ctx, destination, addend);
650 memcpy(buf, data, sizeof(data));
651 ctx.target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
654 void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
655 addSymbol(ctx.saver.save("__AArch64AbsLongThunk_" + destination.getName()),
656 STT_FUNC, 0, isec);
657 addSymbol("$x", STT_NOTYPE, 0, isec);
658 tsec = &isec;
659 (void)getMayUseShortThunk();
662 void AArch64ABSLongThunk::addLongMapSyms() {
663 addSymbol("$d", STT_NOTYPE, 8, *tsec);
666 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
667 // using the small code model, including pc-relative ones. At time of writing
668 // clang and gcc do not support the large code model for position independent
669 // code so it is safe to use this for position independent thunks without
670 // worrying about the destination being more than 4Gb away.
671 void AArch64ADRPThunk::writeLong(uint8_t *buf) {
672 const uint8_t data[] = {
673 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
674 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
675 0x00, 0x02, 0x1f, 0xd6, // br x16
677 // if mayNeedLandingPad is true then destination is an
678 // AArch64BTILandingPadThunk that defines landingPad.
679 assert(!mayNeedLandingPad || landingPad != nullptr);
680 uint64_t s = mayNeedLandingPad
681 ? landingPad->getVA(ctx, 0)
682 : getAArch64ThunkDestVA(ctx, destination, addend);
683 uint64_t p = getThunkTargetSym()->getVA(ctx);
684 memcpy(buf, data, sizeof(data));
685 ctx.target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
686 getAArch64Page(s) - getAArch64Page(p));
687 ctx.target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
690 void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
691 addSymbol(ctx.saver.save("__AArch64ADRPThunk_" + destination.getName()),
692 STT_FUNC, 0, isec);
693 addSymbol("$x", STT_NOTYPE, 0, isec);
696 void AArch64BTILandingPadThunk::addSymbols(ThunkSection &isec) {
697 addSymbol(ctx.saver.save("__AArch64BTIThunk_" + destination.getName()),
698 STT_FUNC, 0, isec);
699 addSymbol("$x", STT_NOTYPE, 0, isec);
702 void AArch64BTILandingPadThunk::writeTo(uint8_t *buf) {
703 if (!getMayUseShortThunk()) {
704 writeLong(buf);
705 return;
707 write32(ctx, buf, 0xd503245f); // BTI c
708 // Control falls through to target in following section.
711 bool AArch64BTILandingPadThunk::getMayUseShortThunk() {
712 if (!mayUseShortThunk)
713 return false;
714 // If the target is the following instruction then we can fall
715 // through without the indirect branch.
716 uint64_t s = destination.getVA(ctx, addend);
717 uint64_t p = getThunkTargetSym()->getVA(ctx);
718 // This function is called before addresses are stable. We need to
719 // work out the range from the thunk to the next section but the
720 // address of the start of the next section depends on the size of
721 // the thunks in the previous pass. s - p + offset == 0 represents
722 // the first pass where the Thunk and following section are assigned
723 // the same offset. s - p <= 4 is the last Thunk in the Thunk
724 // Section.
725 mayUseShortThunk = (s - p + offset == 0 || s - p <= 4);
726 return mayUseShortThunk;
729 void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) {
730 uint64_t s = destination.getVA(ctx, addend);
731 uint64_t p = getThunkTargetSym()->getVA(ctx) + 4;
732 write32(ctx, buf, 0xd503245f); // BTI c
733 write32(ctx, buf + 4, 0x14000000); // B S
734 ctx.target->relocateNoSym(buf + 4, R_AARCH64_CALL26, s - p);
737 // ARM Target Thunks
738 static uint64_t getARMThunkDestVA(Ctx &ctx, const Symbol &s) {
739 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx);
740 return SignExtend64<32>(v);
743 // This function returns true if the target is not Thumb and is within 2^26, and
744 // it has not previously returned false (see comment for mayUseShortThunk).
745 bool ARMThunk::getMayUseShortThunk() {
746 if (!mayUseShortThunk)
747 return false;
748 uint64_t s = getARMThunkDestVA(ctx, destination);
749 if (s & 1) {
750 mayUseShortThunk = false;
751 addLongMapSyms();
752 return false;
754 uint64_t p = getThunkTargetSym()->getVA(ctx);
755 int64_t offset = s - p - 8;
756 mayUseShortThunk = llvm::isInt<26>(offset);
757 if (!mayUseShortThunk)
758 addLongMapSyms();
759 return mayUseShortThunk;
762 void ARMThunk::writeTo(uint8_t *buf) {
763 if (!getMayUseShortThunk()) {
764 writeLong(buf);
765 return;
768 uint64_t s = getARMThunkDestVA(ctx, destination);
769 uint64_t p = getThunkTargetSym()->getVA(ctx);
770 int64_t offset = s - p - 8;
771 write32(ctx, buf, 0xea000000); // b S
772 ctx.target->relocateNoSym(buf, R_ARM_JUMP24, offset);
775 bool ARMThunk::isCompatibleWith(const InputSection &isec,
776 const Relocation &rel) const {
777 // v4T does not have BLX, so also deny R_ARM_THM_CALL
778 if (!ctx.arg.armHasBlx && rel.type == R_ARM_THM_CALL)
779 return false;
781 // Thumb branch relocations can't use BLX
782 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
785 // This function returns true if:
786 // the target is Thumb
787 // && is within branch range
788 // && this function has not previously returned false
789 // (see comment for mayUseShortThunk)
790 // && the arch supports Thumb branch range extension.
791 bool ThumbThunk::getMayUseShortThunk() {
792 if (!mayUseShortThunk)
793 return false;
794 uint64_t s = getARMThunkDestVA(ctx, destination);
795 // To use a short thunk the destination must be Thumb and the target must
796 // have the wide branch instruction B.w. This instruction is included when
797 // Thumb 2 is present, or in v8-M (and above) baseline architectures.
798 // armJ1J2BranchEncoding is available in all architectures with a profile and
799 // the one v6 CPU that implements Thumb 2 (Arm1156t2-s).
800 // Movt and Movw instructions require Thumb 2 or v8-M baseline.
801 if ((s & 1) == 0 || !ctx.arg.armJ1J2BranchEncoding ||
802 !ctx.arg.armHasMovtMovw) {
803 mayUseShortThunk = false;
804 addLongMapSyms();
805 return false;
807 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~1;
808 int64_t offset = s - p - 4;
809 mayUseShortThunk = llvm::isInt<25>(offset);
810 if (!mayUseShortThunk)
811 addLongMapSyms();
812 return mayUseShortThunk;
815 void ThumbThunk::writeTo(uint8_t *buf) {
816 if (!getMayUseShortThunk()) {
817 writeLong(buf);
818 return;
821 uint64_t s = getARMThunkDestVA(ctx, destination);
822 uint64_t p = getThunkTargetSym()->getVA(ctx);
823 int64_t offset = s - p - 4;
824 write16(ctx, buf + 0, 0xf000); // b.w S
825 write16(ctx, buf + 2, 0xb000);
826 ctx.target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
829 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
830 const Relocation &rel) const {
831 // v4T does not have BLX, so also deny R_ARM_CALL
832 if (!ctx.arg.armHasBlx && rel.type == R_ARM_CALL)
833 return false;
835 // ARM branch relocations can't use BLX
836 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
839 void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
840 write32(ctx, buf + 0, 0xe300c000); // movw ip,:lower16:S
841 write32(ctx, buf + 4, 0xe340c000); // movt ip,:upper16:S
842 write32(ctx, buf + 8, 0xe12fff1c); // bx ip
843 uint64_t s = getARMThunkDestVA(ctx, destination);
844 ctx.target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
845 ctx.target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
848 void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
849 addSymbol(ctx.saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
850 STT_FUNC, 0, isec);
851 addSymbol("$a", STT_NOTYPE, 0, isec);
854 void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
855 write16(ctx, buf + 0, 0xf240); // movw ip, :lower16:S
856 write16(ctx, buf + 2, 0x0c00);
857 write16(ctx, buf + 4, 0xf2c0); // movt ip, :upper16:S
858 write16(ctx, buf + 6, 0x0c00);
859 write16(ctx, buf + 8, 0x4760); // bx ip
860 uint64_t s = getARMThunkDestVA(ctx, destination);
861 ctx.target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
862 ctx.target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
865 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
866 addSymbol(ctx.saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
867 STT_FUNC, 1, isec);
868 addSymbol("$t", STT_NOTYPE, 0, isec);
871 void ARMV7PILongThunk::writeLong(uint8_t *buf) {
872 write32(ctx, buf + 0,
873 0xe30fcff0); // P: movw ip,:lower16:S - (P + (L1-P) + 8)
874 write32(ctx, buf + 4,
875 0xe340c000); // movt ip,:upper16:S - (P + (L1-P) + 8)
876 write32(ctx, buf + 8, 0xe08cc00f); // L1: add ip, ip, pc
877 write32(ctx, buf + 12, 0xe12fff1c); // bx ip
878 uint64_t s = getARMThunkDestVA(ctx, destination);
879 uint64_t p = getThunkTargetSym()->getVA(ctx);
880 int64_t offset = s - p - 16;
881 ctx.target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
882 ctx.target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
885 void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
886 addSymbol(ctx.saver.save("__ARMV7PILongThunk_" + destination.getName()),
887 STT_FUNC, 0, isec);
888 addSymbol("$a", STT_NOTYPE, 0, isec);
891 void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
892 write16(ctx, buf + 0, 0xf64f); // P: movw ip,:lower16:S - (P + (L1-P) + 4)
893 write16(ctx, buf + 2, 0x7cf4);
894 write16(ctx, buf + 4, 0xf2c0); // movt ip,:upper16:S - (P + (L1-P) + 4)
895 write16(ctx, buf + 6, 0x0c00);
896 write16(ctx, buf + 8, 0x44fc); // L1: add ip, pc
897 write16(ctx, buf + 10, 0x4760); // bx ip
898 uint64_t s = getARMThunkDestVA(ctx, destination);
899 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
900 int64_t offset = s - p - 12;
901 ctx.target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
902 ctx.target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
905 void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
906 addSymbol(ctx.saver.save("__ThumbV7PILongThunk_" + destination.getName()),
907 STT_FUNC, 1, isec);
908 addSymbol("$t", STT_NOTYPE, 0, isec);
911 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
912 // Most Thumb instructions cannot access the high registers r8 - r15. As the
913 // only register we can corrupt is r12 we must instead spill a low register
914 // to the stack to use as a scratch register. We push r1 even though we
915 // don't need to get some space to use for the return address.
916 write16(ctx, buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers
917 write16(ctx, buf + 2, 0x4801); // ldr r0, [pc, #4] ; L1
918 write16(ctx, buf + 4, 0x9001); // str r0, [sp, #4] ; SP + 4 = S
919 write16(ctx, buf + 6, 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
920 write32(ctx, buf + 8, 0x00000000); // L1: .word S
921 uint64_t s = getARMThunkDestVA(ctx, destination);
922 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
925 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
926 addSymbol(ctx.saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
927 STT_FUNC, 1, isec);
928 addSymbol("$t", STT_NOTYPE, 0, isec);
929 tsec = &isec;
930 (void)getMayUseShortThunk();
933 void ThumbV6MABSLongThunk::addLongMapSyms() {
934 addSymbol("$d", STT_NOTYPE, 8, *tsec);
937 void ThumbV6MABSXOLongThunk::writeLong(uint8_t *buf) {
938 // Most Thumb instructions cannot access the high registers r8 - r15. As the
939 // only register we can corrupt is r12 we must instead spill a low register
940 // to the stack to use as a scratch register. We push r1 even though we
941 // don't need to get some space to use for the return address.
942 write16(ctx, buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers
943 write16(ctx, buf + 2, 0x2000); // movs r0, :upper8_15:S
944 write16(ctx, buf + 4, 0x0200); // lsls r0, r0, #8
945 write16(ctx, buf + 6, 0x3000); // adds r0, :upper0_7:S
946 write16(ctx, buf + 8, 0x0200); // lsls r0, r0, #8
947 write16(ctx, buf + 10, 0x3000); // adds r0, :lower8_15:S
948 write16(ctx, buf + 12, 0x0200); // lsls r0, r0, #8
949 write16(ctx, buf + 14, 0x3000); // adds r0, :lower0_7:S
950 write16(ctx, buf + 16, 0x9001); // str r0, [sp, #4] ; SP + 4 = S
951 write16(ctx, buf + 18,
952 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
953 uint64_t s = getARMThunkDestVA(ctx, destination);
954 ctx.target->relocateNoSym(buf + 2, R_ARM_THM_ALU_ABS_G3, s);
955 ctx.target->relocateNoSym(buf + 6, R_ARM_THM_ALU_ABS_G2_NC, s);
956 ctx.target->relocateNoSym(buf + 10, R_ARM_THM_ALU_ABS_G1_NC, s);
957 ctx.target->relocateNoSym(buf + 14, R_ARM_THM_ALU_ABS_G0_NC, s);
960 void ThumbV6MABSXOLongThunk::addSymbols(ThunkSection &isec) {
961 addSymbol(ctx.saver.save("__Thumbv6MABSXOLongThunk_" + destination.getName()),
962 STT_FUNC, 1, isec);
963 addSymbol("$t", STT_NOTYPE, 0, isec);
966 void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
967 // Most Thumb instructions cannot access the high registers r8 - r15. As the
968 // only register we can corrupt is ip (r12) we must instead spill a low
969 // register to the stack to use as a scratch register.
970 write16(ctx, buf + 0,
971 0xb401); // P: push {r0} ; Obtain scratch register
972 write16(ctx, buf + 2, 0x4802); // ldr r0, [pc, #8] ; L2
973 write16(ctx, buf + 4, 0x4684); // mov ip, r0 ; high to low register
974 write16(ctx, buf + 6,
975 0xbc01); // pop {r0} ; restore scratch register
976 write16(ctx, buf + 8, 0x44e7); // L1: add pc, ip ; transfer control
977 write16(ctx, buf + 10,
978 0x46c0); // nop ; pad to 4-byte boundary
979 write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 4)
980 uint64_t s = getARMThunkDestVA(ctx, destination);
981 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
982 ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
985 void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
986 addSymbol(ctx.saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
987 STT_FUNC, 1, isec);
988 addSymbol("$t", STT_NOTYPE, 0, isec);
989 tsec = &isec;
990 (void)getMayUseShortThunk();
993 void ThumbV6MPILongThunk::addLongMapSyms() {
994 addSymbol("$d", STT_NOTYPE, 12, *tsec);
997 void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
998 write32(ctx, buf + 0, 0xe51ff004); // ldr pc, [pc,#-4] ; L1
999 write32(ctx, buf + 4, 0x00000000); // L1: .word S
1000 ctx.target->relocateNoSym(buf + 4, R_ARM_ABS32,
1001 getARMThunkDestVA(ctx, destination));
1004 void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
1005 addSymbol(ctx.saver.save("__ARMv5LongLdrPcThunk_" + destination.getName()),
1006 STT_FUNC, 0, isec);
1007 addSymbol("$a", STT_NOTYPE, 0, isec);
1008 tsec = &isec;
1009 (void)getMayUseShortThunk();
1012 void ARMV5LongLdrPcThunk::addLongMapSyms() {
1013 addSymbol("$d", STT_NOTYPE, 4, *tsec);
1016 void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
1017 write32(ctx, buf + 0, 0xe59fc000); // ldr r12, [pc] ; L1
1018 write32(ctx, buf + 4, 0xe12fff1c); // bx r12
1019 write32(ctx, buf + 8, 0x00000000); // L1: .word S
1020 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32,
1021 getARMThunkDestVA(ctx, destination));
1024 void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
1025 addSymbol(ctx.saver.save("__ARMv4ABSLongBXThunk_" + destination.getName()),
1026 STT_FUNC, 0, isec);
1027 addSymbol("$a", STT_NOTYPE, 0, isec);
1028 tsec = &isec;
1029 (void)getMayUseShortThunk();
1032 void ARMV4ABSLongBXThunk::addLongMapSyms() {
1033 addSymbol("$d", STT_NOTYPE, 8, *tsec);
1036 void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
1037 write16(ctx, buf + 0, 0x4778); // bx pc
1038 write16(ctx, buf + 2,
1039 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1040 write32(ctx, buf + 4, 0xe51ff004); // ldr pc, [pc, #-4] ; L1
1041 write32(ctx, buf + 8, 0x00000000); // L1: .word S
1042 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32,
1043 getARMThunkDestVA(ctx, destination));
1046 void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
1047 addSymbol(ctx.saver.save("__Thumbv4ABSLongBXThunk_" + destination.getName()),
1048 STT_FUNC, 1, isec);
1049 addSymbol("$t", STT_NOTYPE, 0, isec);
1050 tsec = &isec;
1051 (void)getMayUseShortThunk();
1054 void ThumbV4ABSLongBXThunk::addLongMapSyms() {
1055 addSymbol("$a", STT_NOTYPE, 4, *tsec);
1056 addSymbol("$d", STT_NOTYPE, 8, *tsec);
1059 void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
1060 write16(ctx, buf + 0, 0x4778); // bx pc
1061 write16(ctx, buf + 2,
1062 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1063 write32(ctx, buf + 4, 0xe59fc000); // ldr r12, [pc] ; L1
1064 write32(ctx, buf + 8, 0xe12fff1c); // bx r12
1065 write32(ctx, buf + 12, 0x00000000); // L1: .word S
1066 ctx.target->relocateNoSym(buf + 12, R_ARM_ABS32,
1067 getARMThunkDestVA(ctx, destination));
1070 void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
1071 addSymbol(ctx.saver.save("__Thumbv4ABSLongThunk_" + destination.getName()),
1072 STT_FUNC, 1, isec);
1073 addSymbol("$t", STT_NOTYPE, 0, isec);
1074 tsec = &isec;
1075 (void)getMayUseShortThunk();
1078 void ThumbV4ABSLongThunk::addLongMapSyms() {
1079 addSymbol("$a", STT_NOTYPE, 4, *tsec);
1080 addSymbol("$d", STT_NOTYPE, 12, *tsec);
1083 void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
1084 write32(ctx, buf + 0, 0xe59fc004); // P: ldr ip, [pc,#4] ; L2
1085 write32(ctx, buf + 4, 0xe08fc00c); // L1: add ip, pc, ip
1086 write32(ctx, buf + 8, 0xe12fff1c); // bx ip
1087 write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1088 uint64_t s = getARMThunkDestVA(ctx, destination);
1089 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1090 ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
1093 void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1094 addSymbol(ctx.saver.save("__ARMv4PILongBXThunk_" + destination.getName()),
1095 STT_FUNC, 0, isec);
1096 addSymbol("$a", STT_NOTYPE, 0, isec);
1097 tsec = &isec;
1098 (void)getMayUseShortThunk();
1101 void ARMV4PILongBXThunk::addLongMapSyms() {
1102 addSymbol("$d", STT_NOTYPE, 12, *tsec);
1105 void ARMV4PILongThunk::writeLong(uint8_t *buf) {
1106 write32(ctx, buf + 0, 0xe59fc000); // P: ldr ip, [pc] ; L2
1107 write32(ctx, buf + 4, 0xe08ff00c); // L1: add pc, pc, r12
1108 write32(ctx, buf + 8, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1109 uint64_t s = getARMThunkDestVA(ctx, destination);
1110 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1111 ctx.target->relocateNoSym(buf + 8, R_ARM_REL32, s - p - 12);
1114 void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
1115 addSymbol(ctx.saver.save("__ARMv4PILongThunk_" + destination.getName()),
1116 STT_FUNC, 0, isec);
1117 addSymbol("$a", STT_NOTYPE, 0, isec);
1118 tsec = &isec;
1119 (void)getMayUseShortThunk();
1122 void ARMV4PILongThunk::addLongMapSyms() {
1123 addSymbol("$d", STT_NOTYPE, 8, *tsec);
1126 void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
1127 write16(ctx, buf + 0, 0x4778); // P: bx pc
1128 write16(ctx, buf + 2,
1129 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1130 write32(ctx, buf + 4, 0xe59fc000); // ldr r12, [pc] ; L2
1131 write32(ctx, buf + 8, 0xe08cf00f); // L1: add pc, r12, pc
1132 write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1133 uint64_t s = getARMThunkDestVA(ctx, destination);
1134 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1135 ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 16);
1138 void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1139 addSymbol(ctx.saver.save("__Thumbv4PILongBXThunk_" + destination.getName()),
1140 STT_FUNC, 1, isec);
1141 addSymbol("$t", STT_NOTYPE, 0, isec);
1142 tsec = &isec;
1143 (void)getMayUseShortThunk();
1146 void ThumbV4PILongBXThunk::addLongMapSyms() {
1147 addSymbol("$a", STT_NOTYPE, 4, *tsec);
1148 addSymbol("$d", STT_NOTYPE, 12, *tsec);
1151 void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
1152 write16(ctx, buf + 0, 0x4778); // P: bx pc
1153 write16(ctx, buf + 2,
1154 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1155 write32(ctx, buf + 4, 0xe59fc004); // ldr ip, [pc,#4] ; L2
1156 write32(ctx, buf + 8, 0xe08fc00c); // L1: add ip, pc, ip
1157 write32(ctx, buf + 12, 0xe12fff1c); // bx ip
1158 write32(ctx, buf + 16, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1159 uint64_t s = getARMThunkDestVA(ctx, destination);
1160 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1161 ctx.target->relocateNoSym(buf + 16, R_ARM_REL32, s - p - 16);
1164 void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
1165 addSymbol(ctx.saver.save("__Thumbv4PILongThunk_" + destination.getName()),
1166 STT_FUNC, 1, isec);
1167 addSymbol("$t", STT_NOTYPE, 0, isec);
1168 tsec = &isec;
1169 (void)getMayUseShortThunk();
1172 void ThumbV4PILongThunk::addLongMapSyms() {
1173 addSymbol("$a", STT_NOTYPE, 4, *tsec);
1174 addSymbol("$d", STT_NOTYPE, 16, *tsec);
1177 // Use the long jump which covers a range up to 8MiB.
1178 void AVRThunk::writeTo(uint8_t *buf) {
1179 write32(ctx, buf, 0x940c); // jmp func
1180 ctx.target->relocateNoSym(buf, R_AVR_CALL, destination.getVA(ctx));
1183 void AVRThunk::addSymbols(ThunkSection &isec) {
1184 addSymbol(ctx.saver.save("__AVRThunk_" + destination.getName()), STT_FUNC, 0,
1185 isec);
1188 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
1189 void MipsThunk::writeTo(uint8_t *buf) {
1190 uint64_t s = destination.getVA(ctx);
1191 write32(ctx, buf, 0x3c190000); // lui $25, %hi(func)
1192 write32(ctx, buf + 4, 0x08000000 | (s >> 2)); // j func
1193 write32(ctx, buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
1194 write32(ctx, buf + 12, 0x00000000); // nop
1195 ctx.target->relocateNoSym(buf, R_MIPS_HI16, s);
1196 ctx.target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
1199 void MipsThunk::addSymbols(ThunkSection &isec) {
1200 addSymbol(ctx.saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
1201 isec);
1204 InputSection *MipsThunk::getTargetInputSection() const {
1205 auto &dr = cast<Defined>(destination);
1206 return dyn_cast<InputSection>(dr.section);
1209 // Write microMIPS R2-R5 LA25 thunk code
1210 // to call PIC function from the non-PIC one.
1211 void MicroMipsThunk::writeTo(uint8_t *buf) {
1212 uint64_t s = destination.getVA(ctx);
1213 write16(ctx, buf, 0x41b9); // lui $25, %hi(func)
1214 write16(ctx, buf + 4, 0xd400); // j func
1215 write16(ctx, buf + 8, 0x3339); // addiu $25, $25, %lo(func)
1216 write16(ctx, buf + 12, 0x0c00); // nop
1217 ctx.target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
1218 ctx.target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
1219 ctx.target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
1222 void MicroMipsThunk::addSymbols(ThunkSection &isec) {
1223 Defined *d =
1224 addSymbol(ctx.saver.save("__microLA25Thunk_" + destination.getName()),
1225 STT_FUNC, 0, isec);
1226 d->stOther |= STO_MIPS_MICROMIPS;
1229 InputSection *MicroMipsThunk::getTargetInputSection() const {
1230 auto &dr = cast<Defined>(destination);
1231 return dyn_cast<InputSection>(dr.section);
1234 // Write microMIPS R6 LA25 thunk code
1235 // to call PIC function from the non-PIC one.
1236 void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
1237 uint64_t s = destination.getVA(ctx);
1238 uint64_t p = getThunkTargetSym()->getVA(ctx);
1239 write16(ctx, buf, 0x1320); // lui $25, %hi(func)
1240 write16(ctx, buf + 4, 0x3339); // addiu $25, $25, %lo(func)
1241 write16(ctx, buf + 8, 0x9400); // bc func
1242 ctx.target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
1243 ctx.target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
1244 ctx.target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
1247 void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
1248 Defined *d =
1249 addSymbol(ctx.saver.save("__microLA25Thunk_" + destination.getName()),
1250 STT_FUNC, 0, isec);
1251 d->stOther |= STO_MIPS_MICROMIPS;
1254 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
1255 auto &dr = cast<Defined>(destination);
1256 return dyn_cast<InputSection>(dr.section);
1259 void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t gotPltVA,
1260 const InputFile *file, int64_t addend) {
1261 if (!ctx.arg.isPic) {
1262 write32(ctx, buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
1263 write32(ctx, buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
1264 write32(ctx, buf + 8, 0x7d6903a6); // mtctr r11
1265 write32(ctx, buf + 12, 0x4e800420); // bctr
1266 return;
1268 uint32_t offset;
1269 if (addend >= 0x8000) {
1270 // The stub loads an address relative to r30 (.got2+Addend). Addend is
1271 // almost always 0x8000. The address of .got2 is different in another object
1272 // file, so a stub cannot be shared.
1273 offset = gotPltVA -
1274 (ctx.in.ppc32Got2->getParent()->getVA() +
1275 (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
1276 } else {
1277 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
1278 // currently the address of .got).
1279 offset = gotPltVA - ctx.in.got->getVA();
1281 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
1282 if (ha == 0) {
1283 write32(ctx, buf + 0, 0x817e0000 | l); // lwz r11,l(r30)
1284 write32(ctx, buf + 4, 0x7d6903a6); // mtctr r11
1285 write32(ctx, buf + 8, 0x4e800420); // bctr
1286 write32(ctx, buf + 12, 0x60000000); // nop
1287 } else {
1288 write32(ctx, buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha
1289 write32(ctx, buf + 4, 0x816b0000 | l); // lwz r11,l(r11)
1290 write32(ctx, buf + 8, 0x7d6903a6); // mtctr r11
1291 write32(ctx, buf + 12, 0x4e800420); // bctr
1295 void PPC32PltCallStub::writeTo(uint8_t *buf) {
1296 writePPC32PltCallStub(ctx, buf, destination.getGotPltVA(ctx), file, addend);
1299 void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
1300 std::string buf;
1301 raw_string_ostream os(buf);
1302 os << format_hex_no_prefix(addend, 8);
1303 if (!ctx.arg.isPic)
1304 os << ".plt_call32.";
1305 else if (addend >= 0x8000)
1306 os << ".got2.plt_pic32.";
1307 else
1308 os << ".plt_pic32.";
1309 os << destination.getName();
1310 addSymbol(ctx.saver.save(buf), STT_FUNC, 0, isec);
1313 bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
1314 const Relocation &rel) const {
1315 return !ctx.arg.isPic || (isec.file == file && rel.addend == addend);
1318 void PPC32LongThunk::addSymbols(ThunkSection &isec) {
1319 addSymbol(ctx.saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
1320 isec);
1323 void PPC32LongThunk::writeTo(uint8_t *buf) {
1324 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
1325 auto lo = [](uint32_t v) -> uint16_t { return v; };
1326 uint32_t d = destination.getVA(ctx, addend);
1327 if (ctx.arg.isPic) {
1328 uint32_t off = d - (getThunkTargetSym()->getVA(ctx) + 8);
1329 write32(ctx, buf + 0, 0x7c0802a6); // mflr r12,0
1330 write32(ctx, buf + 4, 0x429f0005); // bcl r20,r31,.+4
1331 write32(ctx, buf + 8, 0x7d8802a6); // mtctr r12
1332 write32(ctx, buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
1333 write32(ctx, buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
1334 write32(ctx, buf + 20, 0x7c0803a6); // mtlr r0
1335 buf += 24;
1336 } else {
1337 write32(ctx, buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
1338 write32(ctx, buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
1339 buf += 8;
1341 write32(ctx, buf + 0, 0x7d8903a6); // mtctr r12
1342 write32(ctx, buf + 4, 0x4e800420); // bctr
1345 void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, int64_t offset) {
1346 uint16_t offHa = (offset + 0x8000) >> 16;
1347 uint16_t offLo = offset & 0xffff;
1349 write32(ctx, buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa
1350 write32(ctx, buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)
1351 write32(ctx, buf + 8, 0x7d8903a6); // mtctr r12
1352 write32(ctx, buf + 12, 0x4e800420); // bctr
1355 void PPC64PltCallStub::writeTo(uint8_t *buf) {
1356 int64_t offset = destination.getGotPltVA(ctx) - getPPC64TocBase(ctx);
1357 // Save the TOC pointer to the save-slot reserved in the call frame.
1358 write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1)
1359 writePPC64LoadAndBranch(ctx, buf + 4, offset);
1362 void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
1363 Defined *s = addSymbol(ctx.saver.save("__plt_" + destination.getName()),
1364 STT_FUNC, 0, isec);
1365 s->setNeedsTocRestore(true);
1366 s->file = destination.file;
1369 bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
1370 const Relocation &rel) const {
1371 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1374 void PPC64R2SaveStub::writeTo(uint8_t *buf) {
1375 const int64_t offset = computeOffset();
1376 write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1)
1377 // The branch offset needs to fit in 26 bits.
1378 if (getMayUseShortThunk()) {
1379 write32(ctx, buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
1380 } else if (isInt<34>(offset)) {
1381 int nextInstOffset;
1382 uint64_t tocOffset = destination.getVA(ctx) - getPPC64TocBase(ctx);
1383 if (tocOffset >> 16 > 0) {
1384 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
1385 const uint64_t addis =
1386 ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
1387 write32(ctx, buf + 4, addis); // addis r12, r2 , top of offset
1388 write32(ctx, buf + 8, addi); // addi r12, r12, bottom of offset
1389 nextInstOffset = 12;
1390 } else {
1391 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
1392 write32(ctx, buf + 4, addi); // addi r12, r2, offset
1393 nextInstOffset = 8;
1395 write32(ctx, buf + nextInstOffset, MTCTR_R12); // mtctr r12
1396 write32(ctx, buf + nextInstOffset + 4, BCTR); // bctr
1397 } else {
1398 ctx.in.ppc64LongBranchTarget->addEntry(&destination, addend);
1399 const int64_t offsetFromTOC =
1400 ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1401 getPPC64TocBase(ctx);
1402 writePPC64LoadAndBranch(ctx, buf + 4, offsetFromTOC);
1406 void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
1407 Defined *s = addSymbol(ctx.saver.save("__toc_save_" + destination.getName()),
1408 STT_FUNC, 0, isec);
1409 s->setNeedsTocRestore(true);
1412 bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
1413 const Relocation &rel) const {
1414 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1417 void PPC64R12SetupStub::writeTo(uint8_t *buf) {
1418 int64_t offset =
1419 (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA(ctx)) -
1420 getThunkTargetSym()->getVA(ctx);
1421 if (!isInt<34>(offset))
1422 reportRangeError(ctx, buf, offset, 34, destination,
1423 "R12 setup stub offset");
1425 int nextInstOffset;
1426 if (ctx.arg.power10Stubs) {
1427 const uint64_t imm = (((offset >> 16) & 0x3ffff) << 32) | (offset & 0xffff);
1428 // pld 12, func@plt@pcrel or paddi r12, 0, func@pcrel
1429 writePrefixedInst(ctx, buf,
1430 (gotPlt ? PLD_R12_NO_DISP : PADDI_R12_NO_DISP) | imm);
1431 nextInstOffset = 8;
1432 } else {
1433 uint32_t off = offset - 8;
1434 write32(ctx, buf + 0, 0x7d8802a6); // mflr 12
1435 write32(ctx, buf + 4, 0x429f0005); // bcl 20,31,.+4
1436 write32(ctx, buf + 8, 0x7d6802a6); // mflr 11
1437 write32(ctx, buf + 12, 0x7d8803a6); // mtlr 12
1438 write32(ctx, buf + 16,
1439 0x3d8b0000 | ((off + 0x8000) >> 16)); // addis 12,11,off@ha
1440 if (gotPlt)
1441 write32(ctx, buf + 20, 0xe98c0000 | (off & 0xffff)); // ld 12, off@l(12)
1442 else
1443 write32(ctx, buf + 20, 0x398c0000 | (off & 0xffff)); // addi 12,12,off@l
1444 nextInstOffset = 24;
1446 write32(ctx, buf + nextInstOffset, MTCTR_R12); // mtctr r12
1447 write32(ctx, buf + nextInstOffset + 4, BCTR); // bctr
1450 void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
1451 addSymbol(ctx.saver.save((gotPlt ? "__plt_pcrel_" : "__gep_setup_") +
1452 destination.getName()),
1453 STT_FUNC, 0, isec);
1456 bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
1457 const Relocation &rel) const {
1458 return rel.type == R_PPC64_REL24_NOTOC;
1461 void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
1462 int64_t offset =
1463 ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1464 getPPC64TocBase(ctx);
1465 writePPC64LoadAndBranch(ctx, buf, offset);
1468 void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
1469 addSymbol(ctx.saver.save("__long_branch_" + destination.getName()), STT_FUNC,
1470 0, isec);
1473 bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
1474 const Relocation &rel) const {
1475 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1478 Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
1479 : ctx(ctx), destination(d), addend(a), offset(0) {
1480 destination.thunkAccessed = true;
1483 Thunk::~Thunk() = default;
1485 static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
1486 int64_t a) {
1487 assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
1488 type));
1489 bool mayNeedLandingPad =
1490 (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
1491 !isAArch64BTILandingPad(ctx, s, a);
1492 if (ctx.arg.picThunk)
1493 return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
1494 return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
1497 // Creates a thunk for long branches or Thumb-ARM interworking.
1498 // Arm Architectures v4t does not support Thumb2 technology, and does not
1499 // support BLX or LDR Arm/Thumb state switching. This means that
1500 // - MOVT and MOVW instructions cannot be used.
1501 // - We can't rewrite BL in place to BLX. We will need thunks.
1503 // TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
1504 // Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
1505 static std::unique_ptr<Thunk> addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s,
1506 int64_t a) {
1507 bool thumb_target = s.getVA(ctx, a) & 1;
1509 switch (reloc) {
1510 case R_ARM_PC24:
1511 case R_ARM_PLT32:
1512 case R_ARM_JUMP24:
1513 case R_ARM_CALL:
1514 if (ctx.arg.picThunk) {
1515 if (thumb_target)
1516 return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);
1517 return std::make_unique<ARMV4PILongThunk>(ctx, s, a);
1519 if (thumb_target)
1520 return std::make_unique<ARMV4ABSLongBXThunk>(ctx, s, a);
1521 return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);
1522 case R_ARM_THM_CALL:
1523 if (ctx.arg.picThunk) {
1524 if (thumb_target)
1525 return std::make_unique<ThumbV4PILongThunk>(ctx, s, a);
1526 return std::make_unique<ThumbV4PILongBXThunk>(ctx, s, a);
1528 if (thumb_target)
1529 return std::make_unique<ThumbV4ABSLongThunk>(ctx, s, a);
1530 return std::make_unique<ThumbV4ABSLongBXThunk>(ctx, s, a);
1532 Fatal(ctx) << "relocation " << reloc << " to " << &s
1533 << " not supported for Armv4 or Armv4T target";
1534 llvm_unreachable("");
1537 // Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
1538 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
1539 // - MOVT and MOVW instructions cannot be used
1540 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
1541 // be transformed into a BLX
1542 static std::unique_ptr<Thunk> addThunkArmv5v6(Ctx &ctx, RelType reloc,
1543 Symbol &s, int64_t a) {
1544 switch (reloc) {
1545 case R_ARM_PC24:
1546 case R_ARM_PLT32:
1547 case R_ARM_JUMP24:
1548 case R_ARM_CALL:
1549 case R_ARM_THM_CALL:
1550 if (ctx.arg.picThunk)
1551 return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);
1552 return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);
1554 Fatal(ctx) << "relocation " << reloc << " to " << &s
1555 << " not supported for Armv5 or Armv6 targets";
1556 llvm_unreachable("");
1559 // Create a thunk for Thumb long branch on V6-M.
1560 // Arm Architecture v6-M only supports Thumb instructions. This means
1561 // - MOVT and MOVW instructions cannot be used.
1562 // - Only a limited number of instructions can access registers r8 and above
1563 // - No interworking support is needed (all Thumb).
1564 static std::unique_ptr<Thunk> addThunkV6M(Ctx &ctx, const InputSection &isec,
1565 RelType reloc, Symbol &s, int64_t a) {
1566 const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE;
1567 switch (reloc) {
1568 case R_ARM_THM_JUMP19:
1569 case R_ARM_THM_JUMP24:
1570 case R_ARM_THM_CALL:
1571 if (ctx.arg.isPic) {
1572 if (!isPureCode)
1573 return std::make_unique<ThumbV6MPILongThunk>(ctx, s, a);
1575 Fatal(ctx)
1576 << "relocation " << reloc << " to " << &s
1577 << " not supported for Armv6-M targets for position independent"
1578 " and execute only code";
1579 llvm_unreachable("");
1581 if (isPureCode)
1582 return std::make_unique<ThumbV6MABSXOLongThunk>(ctx, s, a);
1583 return std::make_unique<ThumbV6MABSLongThunk>(ctx, s, a);
1585 Fatal(ctx) << "relocation " << reloc << " to " << &s
1586 << " not supported for Armv6-M targets";
1587 llvm_unreachable("");
1590 // Creates a thunk for Thumb-ARM interworking or branch range extension.
1591 static std::unique_ptr<Thunk> addThunkArm(Ctx &ctx, const InputSection &isec,
1592 RelType reloc, Symbol &s, int64_t a) {
1593 // Decide which Thunk is needed based on:
1594 // Available instruction set
1595 // - An Arm Thunk can only be used if Arm state is available.
1596 // - A Thumb Thunk can only be used if Thumb state is available.
1597 // - Can only use a Thunk if it uses instructions that the Target supports.
1598 // Relocation is branch or branch and link
1599 // - Branch instructions cannot change state, can only select Thunk that
1600 // starts in the same state as the caller.
1601 // - Branch and link relocations can change state, can select Thunks from
1602 // either Arm or Thumb.
1603 // Position independent Thunks if we require position independent code.
1604 // Execute Only Thunks if the output section is execute only code.
1606 // Handle architectures that have restrictions on the instructions that they
1607 // can use in Thunks. The flags below are set by reading the BuildAttributes
1608 // of the input objects. InputFiles.cpp contains the mapping from ARM
1609 // architecture to flag.
1610 if (!ctx.arg.armHasMovtMovw) {
1611 if (ctx.arg.armJ1J2BranchEncoding)
1612 return addThunkV6M(ctx, isec, reloc, s, a);
1613 if (ctx.arg.armHasBlx)
1614 return addThunkArmv5v6(ctx, reloc, s, a);
1615 return addThunkArmv4(ctx, reloc, s, a);
1618 switch (reloc) {
1619 case R_ARM_PC24:
1620 case R_ARM_PLT32:
1621 case R_ARM_JUMP24:
1622 case R_ARM_CALL:
1623 if (ctx.arg.picThunk)
1624 return std::make_unique<ARMV7PILongThunk>(ctx, s, a);
1625 return std::make_unique<ARMV7ABSLongThunk>(ctx, s, a);
1626 case R_ARM_THM_JUMP19:
1627 case R_ARM_THM_JUMP24:
1628 case R_ARM_THM_CALL:
1629 if (ctx.arg.picThunk)
1630 return std::make_unique<ThumbV7PILongThunk>(ctx, s, a);
1631 return std::make_unique<ThumbV7ABSLongThunk>(ctx, s, a);
1633 llvm_unreachable("");
1636 static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,
1637 int64_t a) {
1638 switch (type) {
1639 case R_AVR_LO8_LDI_GS:
1640 case R_AVR_HI8_LDI_GS:
1641 return std::make_unique<AVRThunk>(ctx, s, a);
1642 default:
1643 llvm_unreachable("");
1647 static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
1648 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
1649 return std::make_unique<MicroMipsR6Thunk>(ctx, s);
1650 if (s.stOther & STO_MIPS_MICROMIPS)
1651 return std::make_unique<MicroMipsThunk>(ctx, s);
1652 return std::make_unique<MipsThunk>(ctx, s);
1655 static std::unique_ptr<Thunk> addThunkPPC32(Ctx &ctx, const InputSection &isec,
1656 const Relocation &rel, Symbol &s) {
1657 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
1658 rel.type == R_PPC_PLTREL24) &&
1659 "unexpected relocation type for thunk");
1660 if (s.isInPlt(ctx))
1661 return std::make_unique<PPC32PltCallStub>(ctx, isec, rel, s);
1662 return std::make_unique<PPC32LongThunk>(ctx, s, rel.addend);
1665 static std::unique_ptr<Thunk> addThunkPPC64(Ctx &ctx, RelType type, Symbol &s,
1666 int64_t a) {
1667 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
1668 type == R_PPC64_REL24_NOTOC) &&
1669 "unexpected relocation type for thunk");
1671 // If we are emitting stubs for NOTOC relocations, we need to tell
1672 // the PLT resolver that there can be multiple TOCs.
1673 if (type == R_PPC64_REL24_NOTOC)
1674 ctx.target->ppc64DynamicSectionOpt = 0x2;
1676 if (s.isInPlt(ctx)) {
1677 if (type == R_PPC64_REL24_NOTOC)
1678 return std::make_unique<PPC64R12SetupStub>(ctx, s,
1679 /*gotPlt=*/true);
1680 return std::make_unique<PPC64PltCallStub>(ctx, s);
1683 // This check looks at the st_other bits of the callee. If the value is 1
1684 // then the callee clobbers the TOC and we need an R2 save stub when RelType
1685 // is R_PPC64_REL14 or R_PPC64_REL24.
1686 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
1687 return std::make_unique<PPC64R2SaveStub>(ctx, s, a);
1689 if (type == R_PPC64_REL24_NOTOC)
1690 return std::make_unique<PPC64R12SetupStub>(ctx, s, /*gotPlt=*/false);
1692 if (ctx.arg.picThunk)
1693 return std::make_unique<PPC64PILongBranchThunk>(ctx, s, a);
1695 return std::make_unique<PPC64PDLongBranchThunk>(ctx, s, a);
1698 std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
1699 Relocation &rel) {
1700 Symbol &s = *rel.sym;
1701 int64_t a = rel.addend;
1703 switch (ctx.arg.emachine) {
1704 case EM_AARCH64:
1705 return addThunkAArch64(ctx, rel.type, s, a);
1706 case EM_ARM:
1707 return addThunkArm(ctx, isec, rel.type, s, a);
1708 case EM_AVR:
1709 return addThunkAVR(ctx, rel.type, s, a);
1710 case EM_MIPS:
1711 return addThunkMips(ctx, rel.type, s);
1712 case EM_PPC:
1713 return addThunkPPC32(ctx, isec, rel, s);
1714 case EM_PPC64:
1715 return addThunkPPC64(ctx, rel.type, s, a);
1716 default:
1717 llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");
1721 std::unique_ptr<Thunk> elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) {
1722 switch (ctx.arg.emachine) {
1723 case EM_AARCH64:
1724 return std::make_unique<AArch64BTILandingPadThunk>(ctx, s, a);
1725 default:
1726 llvm_unreachable("add landing pad only supported for AArch64");