[memprof] Use a new constructor of IndexedAllocationInfo (NFC) (#116920)
[llvm-project.git] / lld / ELF / Thunks.cpp
blob4f04c33f0e5c5a6a735d83ea682f011139fab98a
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;
74 // AArch64 long range Thunks.
75 class AArch64ABSLongThunk final : public AArch64Thunk {
76 public:
77 AArch64ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,
78 bool mayNeedLandingPad)
79 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
80 uint32_t size() override { return getMayUseShortThunk() ? 4 : 16; }
81 void addSymbols(ThunkSection &isec) override;
83 private:
84 void writeLong(uint8_t *buf) override;
87 class AArch64ADRPThunk final : public AArch64Thunk {
88 public:
89 AArch64ADRPThunk(Ctx &ctx, Symbol &dest, int64_t addend,
90 bool mayNeedLandingPad)
91 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
92 uint32_t size() override { return getMayUseShortThunk() ? 4 : 12; }
93 void addSymbols(ThunkSection &isec) override;
95 private:
96 void writeLong(uint8_t *buf) override;
99 // AArch64 BTI Landing Pad
100 // When BTI is enabled indirect branches must land on a BTI
101 // compatible instruction. When the destination does not have a
102 // BTI compatible instruction a Thunk doing an indirect branch
103 // targets a Landing Pad Thunk that direct branches to the target.
104 class AArch64BTILandingPadThunk final : public Thunk {
105 public:
106 AArch64BTILandingPadThunk(Ctx &ctx, Symbol &dest, int64_t addend)
107 : Thunk(ctx, dest, addend) {}
109 uint32_t size() override { return getMayUseShortThunk() ? 4 : 8; }
110 void addSymbols(ThunkSection &isec) override;
111 void writeTo(uint8_t *buf) override;
113 private:
114 bool getMayUseShortThunk();
115 void writeLong(uint8_t *buf);
116 bool mayUseShortThunk = true;
119 // Base class for ARM thunks.
121 // An ARM thunk may be either short or long. A short thunk is simply a branch
122 // (B) instruction, and it may be used to call ARM functions when the distance
123 // from the thunk to the target is less than 32MB. Long thunks can branch to any
124 // virtual address and can switch between ARM and Thumb, and they are
125 // implemented in the derived classes. This class tries to create a short thunk
126 // if the target is in range, otherwise it creates a long thunk.
127 class ARMThunk : public Thunk {
128 public:
129 ARMThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}
131 bool getMayUseShortThunk();
132 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
133 void writeTo(uint8_t *buf) override;
134 bool isCompatibleWith(const InputSection &isec,
135 const Relocation &rel) const override;
137 // Returns the size of a long thunk.
138 virtual uint32_t sizeLong() = 0;
140 // Writes a long thunk to Buf.
141 virtual void writeLong(uint8_t *buf) = 0;
143 private:
144 // This field tracks whether all previously considered layouts would allow
145 // this thunk to be short. If we have ever needed a long thunk, we always
146 // create a long thunk, even if the thunk may be short given the current
147 // distance to the target. We do this because transitioning from long to short
148 // can create layout oscillations in certain corner cases which would prevent
149 // the layout from converging.
150 bool mayUseShortThunk = true;
153 // Base class for Thumb-2 thunks.
155 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
156 // which has a range of 16MB.
157 class ThumbThunk : public Thunk {
158 public:
159 ThumbThunk(Ctx &ctx, Symbol &dest, int64_t addend)
160 : Thunk(ctx, dest, addend) {
161 alignment = 2;
164 bool getMayUseShortThunk();
165 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
166 void writeTo(uint8_t *buf) override;
167 bool isCompatibleWith(const InputSection &isec,
168 const Relocation &rel) const override;
170 // Returns the size of a long thunk.
171 virtual uint32_t sizeLong() = 0;
173 // Writes a long thunk to Buf.
174 virtual void writeLong(uint8_t *buf) = 0;
176 private:
177 // See comment in ARMThunk above.
178 bool mayUseShortThunk = true;
181 // Specific ARM Thunk implementations. The naming convention is:
182 // Source State, TargetState, Target Requirement, ABS or PI, Range
183 class ARMV7ABSLongThunk final : public ARMThunk {
184 public:
185 ARMV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
186 : ARMThunk(ctx, dest, addend) {}
188 uint32_t sizeLong() override { return 12; }
189 void writeLong(uint8_t *buf) override;
190 void addSymbols(ThunkSection &isec) override;
193 class ARMV7PILongThunk final : public ARMThunk {
194 public:
195 ARMV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
196 : ARMThunk(ctx, dest, addend) {}
198 uint32_t sizeLong() override { return 16; }
199 void writeLong(uint8_t *buf) override;
200 void addSymbols(ThunkSection &isec) override;
203 class ThumbV7ABSLongThunk final : public ThumbThunk {
204 public:
205 ThumbV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
206 : ThumbThunk(ctx, dest, addend) {}
208 uint32_t sizeLong() override { return 10; }
209 void writeLong(uint8_t *buf) override;
210 void addSymbols(ThunkSection &isec) override;
213 class ThumbV7PILongThunk final : public ThumbThunk {
214 public:
215 ThumbV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
216 : ThumbThunk(ctx, dest, addend) {}
218 uint32_t sizeLong() override { return 12; }
219 void writeLong(uint8_t *buf) override;
220 void addSymbols(ThunkSection &isec) override;
223 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
224 class ThumbV6MABSLongThunk final : public ThumbThunk {
225 public:
226 ThumbV6MABSLongThunk(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 class ThumbV6MABSXOLongThunk final : public ThumbThunk {
235 public:
236 ThumbV6MABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
237 : ThumbThunk(ctx, dest, addend) {}
239 uint32_t sizeLong() override { return 20; }
240 void writeLong(uint8_t *buf) override;
241 void addSymbols(ThunkSection &isec) override;
244 class ThumbV6MPILongThunk final : public ThumbThunk {
245 public:
246 ThumbV6MPILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
247 : ThumbThunk(ctx, dest, addend) {}
249 uint32_t sizeLong() override { return 16; }
250 void writeLong(uint8_t *buf) override;
251 void addSymbols(ThunkSection &isec) override;
254 // Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
255 // v6 support BLX to which BL instructions can be rewritten inline. There are no
256 // Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on
257 // these architecture that can result in a thunk.
259 // LDR on v5 and v6 can switch processor state, so for v5 and v6,
260 // ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4
261 // can also use this thunk, but only for Arm->Arm calls.
262 class ARMV5LongLdrPcThunk final : public ARMThunk {
263 public:
264 ARMV5LongLdrPcThunk(Ctx &ctx, Symbol &dest, int64_t addend)
265 : ARMThunk(ctx, dest, addend) {}
267 uint32_t sizeLong() override { return 8; }
268 void writeLong(uint8_t *buf) override;
269 void addSymbols(ThunkSection &isec) override;
272 // Implementations of Thunks for v4. BLX is not supported, and loads
273 // will not invoke Arm/Thumb state changes.
274 class ARMV4PILongBXThunk final : public ARMThunk {
275 public:
276 ARMV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
277 : ARMThunk(ctx, dest, addend) {}
279 uint32_t sizeLong() override { return 16; }
280 void writeLong(uint8_t *buf) override;
281 void addSymbols(ThunkSection &isec) override;
284 class ARMV4PILongThunk final : public ARMThunk {
285 public:
286 ARMV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
287 : ARMThunk(ctx, dest, addend) {}
289 uint32_t sizeLong() override { return 12; }
290 void writeLong(uint8_t *buf) override;
291 void addSymbols(ThunkSection &isec) override;
294 class ThumbV4PILongBXThunk final : public ThumbThunk {
295 public:
296 ThumbV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
297 : ThumbThunk(ctx, dest, addend) {}
299 uint32_t sizeLong() override { return 16; }
300 void writeLong(uint8_t *buf) override;
301 void addSymbols(ThunkSection &isec) override;
304 class ThumbV4PILongThunk final : public ThumbThunk {
305 public:
306 ThumbV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
307 : ThumbThunk(ctx, dest, addend) {}
309 uint32_t sizeLong() override { return 20; }
310 void writeLong(uint8_t *buf) override;
311 void addSymbols(ThunkSection &isec) override;
314 class ARMV4ABSLongBXThunk final : public ARMThunk {
315 public:
316 ARMV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
317 : ARMThunk(ctx, dest, addend) {}
319 uint32_t sizeLong() override { return 12; }
320 void writeLong(uint8_t *buf) override;
321 void addSymbols(ThunkSection &isec) override;
324 class ThumbV4ABSLongBXThunk final : public ThumbThunk {
325 public:
326 ThumbV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
327 : ThumbThunk(ctx, dest, addend) {}
329 uint32_t sizeLong() override { return 12; }
330 void writeLong(uint8_t *buf) override;
331 void addSymbols(ThunkSection &isec) override;
334 class ThumbV4ABSLongThunk final : public ThumbThunk {
335 public:
336 ThumbV4ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
337 : ThumbThunk(ctx, dest, addend) {}
339 uint32_t sizeLong() override { return 16; }
340 void writeLong(uint8_t *buf) override;
341 void addSymbols(ThunkSection &isec) override;
344 // The AVR devices need thunks for R_AVR_LO8_LDI_GS/R_AVR_HI8_LDI_GS
345 // when their destination is out of range [0, 0x1ffff].
346 class AVRThunk : public Thunk {
347 public:
348 AVRThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}
349 uint32_t size() override { return 4; }
350 void writeTo(uint8_t *buf) override;
351 void addSymbols(ThunkSection &isec) override;
354 // MIPS LA25 thunk
355 class MipsThunk final : public Thunk {
356 public:
357 MipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
359 uint32_t size() override { return 16; }
360 void writeTo(uint8_t *buf) override;
361 void addSymbols(ThunkSection &isec) override;
362 InputSection *getTargetInputSection() const override;
365 // microMIPS R2-R5 LA25 thunk
366 class MicroMipsThunk final : public Thunk {
367 public:
368 MicroMipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
370 uint32_t size() override { return 14; }
371 void writeTo(uint8_t *buf) override;
372 void addSymbols(ThunkSection &isec) override;
373 InputSection *getTargetInputSection() const override;
376 // microMIPS R6 LA25 thunk
377 class MicroMipsR6Thunk final : public Thunk {
378 public:
379 MicroMipsR6Thunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
381 uint32_t size() override { return 12; }
382 void writeTo(uint8_t *buf) override;
383 void addSymbols(ThunkSection &isec) override;
384 InputSection *getTargetInputSection() const override;
387 class PPC32PltCallStub final : public Thunk {
388 public:
389 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
390 // decide the offsets in the call stub.
391 PPC32PltCallStub(Ctx &ctx, const InputSection &isec, const Relocation &rel,
392 Symbol &dest)
393 : Thunk(ctx, dest, rel.addend), file(isec.file) {}
394 uint32_t size() override { return 16; }
395 void writeTo(uint8_t *buf) override;
396 void addSymbols(ThunkSection &isec) override;
397 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
399 private:
400 // Records the call site of the call stub.
401 const InputFile *file;
404 class PPC32LongThunk final : public Thunk {
405 public:
406 PPC32LongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
407 : Thunk(ctx, dest, addend) {}
408 uint32_t size() override { return ctx.arg.isPic ? 32 : 16; }
409 void writeTo(uint8_t *buf) override;
410 void addSymbols(ThunkSection &isec) override;
413 // PPC64 Plt call stubs.
414 // Any call site that needs to call through a plt entry needs a call stub in
415 // the .text section. The call stub is responsible for:
416 // 1) Saving the toc-pointer to the stack.
417 // 2) Loading the target functions address from the procedure linkage table into
418 // r12 for use by the target functions global entry point, and into the count
419 // register.
420 // 3) Transferring control to the target function through an indirect branch.
421 class PPC64PltCallStub final : public Thunk {
422 public:
423 PPC64PltCallStub(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
424 uint32_t size() override { return 20; }
425 void writeTo(uint8_t *buf) override;
426 void addSymbols(ThunkSection &isec) override;
427 bool isCompatibleWith(const InputSection &isec,
428 const Relocation &rel) const override;
431 // PPC64 R2 Save Stub
432 // When the caller requires a valid R2 TOC pointer but the callee does not
433 // require a TOC pointer and the callee cannot guarantee that it doesn't
434 // clobber R2 then we need to save R2. This stub:
435 // 1) Saves the TOC pointer to the stack.
436 // 2) Tail calls the callee.
437 class PPC64R2SaveStub final : public Thunk {
438 public:
439 PPC64R2SaveStub(Ctx &ctx, Symbol &dest, int64_t addend)
440 : Thunk(ctx, dest, addend) {
441 alignment = 16;
444 // To prevent oscillations in layout when moving from short to long thunks
445 // we make sure that once a thunk has been set to long it cannot go back.
446 bool getMayUseShortThunk() {
447 if (!mayUseShortThunk)
448 return false;
449 if (!isInt<26>(computeOffset())) {
450 mayUseShortThunk = false;
451 return false;
453 return true;
455 uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
456 void writeTo(uint8_t *buf) override;
457 void addSymbols(ThunkSection &isec) override;
458 bool isCompatibleWith(const InputSection &isec,
459 const Relocation &rel) const override;
461 private:
462 // Transitioning from long to short can create layout oscillations in
463 // certain corner cases which would prevent the layout from converging.
464 // This is similar to the handling for ARMThunk.
465 bool mayUseShortThunk = true;
466 int64_t computeOffset() const {
467 return destination.getVA(ctx) - (getThunkTargetSym()->getVA(ctx) + 4);
471 // PPC64 R12 Setup Stub
472 // When a caller that does not maintain TOC calls a target which may possibly
473 // use TOC (either non-preemptible with localentry>1 or preemptible), we need to
474 // set r12 to satisfy the requirement of the global entry point.
475 class PPC64R12SetupStub final : public Thunk {
476 public:
477 PPC64R12SetupStub(Ctx &ctx, Symbol &dest, bool gotPlt)
478 : Thunk(ctx, dest, 0), gotPlt(gotPlt) {
479 alignment = 16;
481 uint32_t size() override { return 32; }
482 void writeTo(uint8_t *buf) override;
483 void addSymbols(ThunkSection &isec) override;
484 bool isCompatibleWith(const InputSection &isec,
485 const Relocation &rel) const override;
487 private:
488 bool gotPlt;
491 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
492 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
493 // larger than that we need to emit a long-branch thunk. The target address
494 // of the callee is stored in a table to be accessed TOC-relative. Since the
495 // call must be local (a non-local call will have a PltCallStub instead) the
496 // table stores the address of the callee's local entry point. For
497 // position-independent code a corresponding relative dynamic relocation is
498 // used.
499 class PPC64LongBranchThunk : public Thunk {
500 public:
501 uint32_t size() override { return 32; }
502 void writeTo(uint8_t *buf) override;
503 void addSymbols(ThunkSection &isec) override;
504 bool isCompatibleWith(const InputSection &isec,
505 const Relocation &rel) const override;
507 protected:
508 PPC64LongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
509 : Thunk(ctx, dest, addend) {}
512 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
513 public:
514 PPC64PILongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
515 : PPC64LongBranchThunk(ctx, dest, addend) {
516 assert(!dest.isPreemptible);
517 if (std::optional<uint32_t> index =
518 ctx.in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
519 ctx.mainPart->relaDyn->addRelativeReloc(
520 ctx.target->relativeRel, *ctx.in.ppc64LongBranchTarget,
521 *index * UINT64_C(8), dest,
522 addend + getPPC64GlobalEntryToLocalEntryOffset(ctx, dest.stOther),
523 ctx.target->symbolicRel, R_ABS);
528 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
529 public:
530 PPC64PDLongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
531 : PPC64LongBranchThunk(ctx, dest, addend) {
532 ctx.in.ppc64LongBranchTarget->addEntry(&dest, addend);
536 } // end anonymous namespace
538 Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
539 InputSectionBase &section) {
540 Defined *d = addSyntheticLocal(ctx, name, type, value, /*size=*/0, section);
541 syms.push_back(d);
542 return d;
545 void Thunk::setOffset(uint64_t newOffset) {
546 for (Defined *d : syms)
547 d->value = d->value - offset + newOffset;
548 offset = newOffset;
551 // AArch64 Thunk base class.
552 static uint64_t getAArch64ThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
553 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a);
554 return v;
557 bool AArch64Thunk::getMayUseShortThunk() {
558 if (!mayUseShortThunk)
559 return false;
560 uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend);
561 uint64_t p = getThunkTargetSym()->getVA(ctx);
562 mayUseShortThunk = llvm::isInt<28>(s - p);
563 return mayUseShortThunk;
566 void AArch64Thunk::writeTo(uint8_t *buf) {
567 if (!getMayUseShortThunk()) {
568 writeLong(buf);
569 return;
571 uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend);
572 uint64_t p = getThunkTargetSym()->getVA(ctx);
573 write32(ctx, buf, 0x14000000); // b S
574 ctx.target->relocateNoSym(buf, R_AARCH64_CALL26, s - p);
577 bool AArch64Thunk::needsSyntheticLandingPad() {
578 // Short Thunks use a direct branch, no synthetic landing pad
579 // required.
580 return mayNeedLandingPad && !getMayUseShortThunk();
583 // AArch64 long range Thunks.
584 void AArch64ABSLongThunk::writeLong(uint8_t *buf) {
585 const uint8_t data[] = {
586 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
587 0x00, 0x02, 0x1f, 0xd6, // br x16
588 0x00, 0x00, 0x00, 0x00, // L0: .xword S
589 0x00, 0x00, 0x00, 0x00,
591 // If mayNeedLandingPad is true then destination is an
592 // AArch64BTILandingPadThunk that defines landingPad.
593 assert(!mayNeedLandingPad || landingPad != nullptr);
594 uint64_t s = mayNeedLandingPad
595 ? landingPad->getVA(ctx, 0)
596 : getAArch64ThunkDestVA(ctx, destination, addend);
597 memcpy(buf, data, sizeof(data));
598 ctx.target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
601 void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
602 addSymbol(ctx.saver.save("__AArch64AbsLongThunk_" + destination.getName()),
603 STT_FUNC, 0, isec);
604 addSymbol("$x", STT_NOTYPE, 0, isec);
605 if (!getMayUseShortThunk())
606 addSymbol("$d", STT_NOTYPE, 8, isec);
609 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
610 // using the small code model, including pc-relative ones. At time of writing
611 // clang and gcc do not support the large code model for position independent
612 // code so it is safe to use this for position independent thunks without
613 // worrying about the destination being more than 4Gb away.
614 void AArch64ADRPThunk::writeLong(uint8_t *buf) {
615 const uint8_t data[] = {
616 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
617 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
618 0x00, 0x02, 0x1f, 0xd6, // br x16
620 // if mayNeedLandingPad is true then destination is an
621 // AArch64BTILandingPadThunk that defines landingPad.
622 assert(!mayNeedLandingPad || landingPad != nullptr);
623 uint64_t s = mayNeedLandingPad
624 ? landingPad->getVA(ctx, 0)
625 : getAArch64ThunkDestVA(ctx, destination, addend);
626 uint64_t p = getThunkTargetSym()->getVA(ctx);
627 memcpy(buf, data, sizeof(data));
628 ctx.target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
629 getAArch64Page(s) - getAArch64Page(p));
630 ctx.target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
633 void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
634 addSymbol(ctx.saver.save("__AArch64ADRPThunk_" + destination.getName()),
635 STT_FUNC, 0, isec);
636 addSymbol("$x", STT_NOTYPE, 0, isec);
639 void AArch64BTILandingPadThunk::addSymbols(ThunkSection &isec) {
640 addSymbol(ctx.saver.save("__AArch64BTIThunk_" + destination.getName()),
641 STT_FUNC, 0, isec);
642 addSymbol("$x", STT_NOTYPE, 0, isec);
645 void AArch64BTILandingPadThunk::writeTo(uint8_t *buf) {
646 if (!getMayUseShortThunk()) {
647 writeLong(buf);
648 return;
650 write32(ctx, buf, 0xd503245f); // BTI c
651 // Control falls through to target in following section.
654 bool AArch64BTILandingPadThunk::getMayUseShortThunk() {
655 if (!mayUseShortThunk)
656 return false;
657 // If the target is the following instruction then we can fall
658 // through without the indirect branch.
659 uint64_t s = destination.getVA(ctx, addend);
660 uint64_t p = getThunkTargetSym()->getVA(ctx);
661 // This function is called before addresses are stable. We need to
662 // work out the range from the thunk to the next section but the
663 // address of the start of the next section depends on the size of
664 // the thunks in the previous pass. s - p + offset == 0 represents
665 // the first pass where the Thunk and following section are assigned
666 // the same offset. s - p <= 4 is the last Thunk in the Thunk
667 // Section.
668 mayUseShortThunk = (s - p + offset == 0 || s - p <= 4);
669 return mayUseShortThunk;
672 void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) {
673 uint64_t s = destination.getVA(ctx, addend);
674 uint64_t p = getThunkTargetSym()->getVA(ctx) + 4;
675 write32(ctx, buf, 0xd503245f); // BTI c
676 write32(ctx, buf + 4, 0x14000000); // B S
677 ctx.target->relocateNoSym(buf + 4, R_AARCH64_CALL26, s - p);
680 // ARM Target Thunks
681 static uint64_t getARMThunkDestVA(Ctx &ctx, const Symbol &s) {
682 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx);
683 return SignExtend64<32>(v);
686 // This function returns true if the target is not Thumb and is within 2^26, and
687 // it has not previously returned false (see comment for mayUseShortThunk).
688 bool ARMThunk::getMayUseShortThunk() {
689 if (!mayUseShortThunk)
690 return false;
691 uint64_t s = getARMThunkDestVA(ctx, destination);
692 if (s & 1) {
693 mayUseShortThunk = false;
694 return false;
696 uint64_t p = getThunkTargetSym()->getVA(ctx);
697 int64_t offset = s - p - 8;
698 mayUseShortThunk = llvm::isInt<26>(offset);
699 return mayUseShortThunk;
702 void ARMThunk::writeTo(uint8_t *buf) {
703 if (!getMayUseShortThunk()) {
704 writeLong(buf);
705 return;
708 uint64_t s = getARMThunkDestVA(ctx, destination);
709 uint64_t p = getThunkTargetSym()->getVA(ctx);
710 int64_t offset = s - p - 8;
711 write32(ctx, buf, 0xea000000); // b S
712 ctx.target->relocateNoSym(buf, R_ARM_JUMP24, offset);
715 bool ARMThunk::isCompatibleWith(const InputSection &isec,
716 const Relocation &rel) const {
717 // v4T does not have BLX, so also deny R_ARM_THM_CALL
718 if (!ctx.arg.armHasBlx && rel.type == R_ARM_THM_CALL)
719 return false;
721 // Thumb branch relocations can't use BLX
722 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
725 // This function returns true if:
726 // the target is Thumb
727 // && is within branch range
728 // && this function has not previously returned false
729 // (see comment for mayUseShortThunk)
730 // && the arch supports Thumb branch range extension.
731 bool ThumbThunk::getMayUseShortThunk() {
732 if (!mayUseShortThunk || !ctx.arg.armJ1J2BranchEncoding)
733 return false;
734 uint64_t s = getARMThunkDestVA(ctx, destination);
735 if ((s & 1) == 0) {
736 mayUseShortThunk = false;
737 return false;
739 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~1;
740 int64_t offset = s - p - 4;
741 mayUseShortThunk = llvm::isInt<25>(offset);
742 return mayUseShortThunk;
745 void ThumbThunk::writeTo(uint8_t *buf) {
746 if (!getMayUseShortThunk()) {
747 writeLong(buf);
748 return;
751 uint64_t s = getARMThunkDestVA(ctx, destination);
752 uint64_t p = getThunkTargetSym()->getVA(ctx);
753 int64_t offset = s - p - 4;
754 write16(ctx, buf + 0, 0xf000); // b.w S
755 write16(ctx, buf + 2, 0xb000);
756 ctx.target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
759 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
760 const Relocation &rel) const {
761 // v4T does not have BLX, so also deny R_ARM_CALL
762 if (!ctx.arg.armHasBlx && rel.type == R_ARM_CALL)
763 return false;
765 // ARM branch relocations can't use BLX
766 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
769 void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
770 write32(ctx, buf + 0, 0xe300c000); // movw ip,:lower16:S
771 write32(ctx, buf + 4, 0xe340c000); // movt ip,:upper16:S
772 write32(ctx, buf + 8, 0xe12fff1c); // bx ip
773 uint64_t s = getARMThunkDestVA(ctx, destination);
774 ctx.target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
775 ctx.target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
778 void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
779 addSymbol(ctx.saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
780 STT_FUNC, 0, isec);
781 addSymbol("$a", STT_NOTYPE, 0, isec);
784 void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
785 write16(ctx, buf + 0, 0xf240); // movw ip, :lower16:S
786 write16(ctx, buf + 2, 0x0c00);
787 write16(ctx, buf + 4, 0xf2c0); // movt ip, :upper16:S
788 write16(ctx, buf + 6, 0x0c00);
789 write16(ctx, buf + 8, 0x4760); // bx ip
790 uint64_t s = getARMThunkDestVA(ctx, destination);
791 ctx.target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
792 ctx.target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
795 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
796 addSymbol(ctx.saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
797 STT_FUNC, 1, isec);
798 addSymbol("$t", STT_NOTYPE, 0, isec);
801 void ARMV7PILongThunk::writeLong(uint8_t *buf) {
802 write32(ctx, buf + 0,
803 0xe30fcff0); // P: movw ip,:lower16:S - (P + (L1-P) + 8)
804 write32(ctx, buf + 4,
805 0xe340c000); // movt ip,:upper16:S - (P + (L1-P) + 8)
806 write32(ctx, buf + 8, 0xe08cc00f); // L1: add ip, ip, pc
807 write32(ctx, buf + 12, 0xe12fff1c); // bx ip
808 uint64_t s = getARMThunkDestVA(ctx, destination);
809 uint64_t p = getThunkTargetSym()->getVA(ctx);
810 int64_t offset = s - p - 16;
811 ctx.target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
812 ctx.target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
815 void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
816 addSymbol(ctx.saver.save("__ARMV7PILongThunk_" + destination.getName()),
817 STT_FUNC, 0, isec);
818 addSymbol("$a", STT_NOTYPE, 0, isec);
821 void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
822 write16(ctx, buf + 0, 0xf64f); // P: movw ip,:lower16:S - (P + (L1-P) + 4)
823 write16(ctx, buf + 2, 0x7cf4);
824 write16(ctx, buf + 4, 0xf2c0); // movt ip,:upper16:S - (P + (L1-P) + 4)
825 write16(ctx, buf + 6, 0x0c00);
826 write16(ctx, buf + 8, 0x44fc); // L1: add ip, pc
827 write16(ctx, buf + 10, 0x4760); // bx ip
828 uint64_t s = getARMThunkDestVA(ctx, destination);
829 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
830 int64_t offset = s - p - 12;
831 ctx.target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
832 ctx.target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
835 void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
836 addSymbol(ctx.saver.save("__ThumbV7PILongThunk_" + destination.getName()),
837 STT_FUNC, 1, isec);
838 addSymbol("$t", STT_NOTYPE, 0, isec);
841 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
842 // Most Thumb instructions cannot access the high registers r8 - r15. As the
843 // only register we can corrupt is r12 we must instead spill a low register
844 // to the stack to use as a scratch register. We push r1 even though we
845 // don't need to get some space to use for the return address.
846 write16(ctx, buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers
847 write16(ctx, buf + 2, 0x4801); // ldr r0, [pc, #4] ; L1
848 write16(ctx, buf + 4, 0x9001); // str r0, [sp, #4] ; SP + 4 = S
849 write16(ctx, buf + 6, 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
850 write32(ctx, buf + 8, 0x00000000); // L1: .word S
851 uint64_t s = getARMThunkDestVA(ctx, destination);
852 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
855 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
856 addSymbol(ctx.saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
857 STT_FUNC, 1, isec);
858 addSymbol("$t", STT_NOTYPE, 0, isec);
859 if (!getMayUseShortThunk())
860 addSymbol("$d", STT_NOTYPE, 8, isec);
863 void ThumbV6MABSXOLongThunk::writeLong(uint8_t *buf) {
864 // Most Thumb instructions cannot access the high registers r8 - r15. As the
865 // only register we can corrupt is r12 we must instead spill a low register
866 // to the stack to use as a scratch register. We push r1 even though we
867 // don't need to get some space to use for the return address.
868 write16(ctx, buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers
869 write16(ctx, buf + 2, 0x2000); // movs r0, :upper8_15:S
870 write16(ctx, buf + 4, 0x0200); // lsls r0, r0, #8
871 write16(ctx, buf + 6, 0x3000); // adds r0, :upper0_7:S
872 write16(ctx, buf + 8, 0x0200); // lsls r0, r0, #8
873 write16(ctx, buf + 10, 0x3000); // adds r0, :lower8_15:S
874 write16(ctx, buf + 12, 0x0200); // lsls r0, r0, #8
875 write16(ctx, buf + 14, 0x3000); // adds r0, :lower0_7:S
876 write16(ctx, buf + 16, 0x9001); // str r0, [sp, #4] ; SP + 4 = S
877 write16(ctx, buf + 18,
878 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
879 uint64_t s = getARMThunkDestVA(ctx, destination);
880 ctx.target->relocateNoSym(buf + 2, R_ARM_THM_ALU_ABS_G3, s);
881 ctx.target->relocateNoSym(buf + 6, R_ARM_THM_ALU_ABS_G2_NC, s);
882 ctx.target->relocateNoSym(buf + 10, R_ARM_THM_ALU_ABS_G1_NC, s);
883 ctx.target->relocateNoSym(buf + 14, R_ARM_THM_ALU_ABS_G0_NC, s);
886 void ThumbV6MABSXOLongThunk::addSymbols(ThunkSection &isec) {
887 addSymbol(ctx.saver.save("__Thumbv6MABSXOLongThunk_" + destination.getName()),
888 STT_FUNC, 1, isec);
889 addSymbol("$t", STT_NOTYPE, 0, isec);
892 void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
893 // Most Thumb instructions cannot access the high registers r8 - r15. As the
894 // only register we can corrupt is ip (r12) we must instead spill a low
895 // register to the stack to use as a scratch register.
896 write16(ctx, buf + 0,
897 0xb401); // P: push {r0} ; Obtain scratch register
898 write16(ctx, buf + 2, 0x4802); // ldr r0, [pc, #8] ; L2
899 write16(ctx, buf + 4, 0x4684); // mov ip, r0 ; high to low register
900 write16(ctx, buf + 6,
901 0xbc01); // pop {r0} ; restore scratch register
902 write16(ctx, buf + 8, 0x44e7); // L1: add pc, ip ; transfer control
903 write16(ctx, buf + 10,
904 0x46c0); // nop ; pad to 4-byte boundary
905 write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 4)
906 uint64_t s = getARMThunkDestVA(ctx, destination);
907 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
908 ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
911 void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
912 addSymbol(ctx.saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
913 STT_FUNC, 1, isec);
914 addSymbol("$t", STT_NOTYPE, 0, isec);
915 if (!getMayUseShortThunk())
916 addSymbol("$d", STT_NOTYPE, 12, isec);
919 void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
920 write32(ctx, buf + 0, 0xe51ff004); // ldr pc, [pc,#-4] ; L1
921 write32(ctx, buf + 4, 0x00000000); // L1: .word S
922 ctx.target->relocateNoSym(buf + 4, R_ARM_ABS32,
923 getARMThunkDestVA(ctx, destination));
926 void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
927 addSymbol(ctx.saver.save("__ARMv5LongLdrPcThunk_" + destination.getName()),
928 STT_FUNC, 0, isec);
929 addSymbol("$a", STT_NOTYPE, 0, isec);
930 if (!getMayUseShortThunk())
931 addSymbol("$d", STT_NOTYPE, 4, isec);
934 void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
935 write32(ctx, buf + 0, 0xe59fc000); // ldr r12, [pc] ; L1
936 write32(ctx, buf + 4, 0xe12fff1c); // bx r12
937 write32(ctx, buf + 8, 0x00000000); // L1: .word S
938 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32,
939 getARMThunkDestVA(ctx, destination));
942 void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
943 addSymbol(ctx.saver.save("__ARMv4ABSLongBXThunk_" + destination.getName()),
944 STT_FUNC, 0, isec);
945 addSymbol("$a", STT_NOTYPE, 0, isec);
946 if (!getMayUseShortThunk())
947 addSymbol("$d", STT_NOTYPE, 8, isec);
950 void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
951 write16(ctx, buf + 0, 0x4778); // bx pc
952 write16(ctx, buf + 2,
953 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
954 write32(ctx, buf + 4, 0xe51ff004); // ldr pc, [pc, #-4] ; L1
955 write32(ctx, buf + 8, 0x00000000); // L1: .word S
956 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32,
957 getARMThunkDestVA(ctx, destination));
960 void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
961 addSymbol(ctx.saver.save("__Thumbv4ABSLongBXThunk_" + destination.getName()),
962 STT_FUNC, 1, isec);
963 addSymbol("$t", STT_NOTYPE, 0, isec);
964 addSymbol("$a", STT_NOTYPE, 4, isec);
965 if (!getMayUseShortThunk())
966 addSymbol("$d", STT_NOTYPE, 8, isec);
969 void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
970 write16(ctx, buf + 0, 0x4778); // bx pc
971 write16(ctx, buf + 2,
972 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
973 write32(ctx, buf + 4, 0xe59fc000); // ldr r12, [pc] ; L1
974 write32(ctx, buf + 8, 0xe12fff1c); // bx r12
975 write32(ctx, buf + 12, 0x00000000); // L1: .word S
976 ctx.target->relocateNoSym(buf + 12, R_ARM_ABS32,
977 getARMThunkDestVA(ctx, destination));
980 void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
981 addSymbol(ctx.saver.save("__Thumbv4ABSLongThunk_" + destination.getName()),
982 STT_FUNC, 1, isec);
983 addSymbol("$t", STT_NOTYPE, 0, isec);
984 addSymbol("$a", STT_NOTYPE, 4, isec);
985 if (!getMayUseShortThunk())
986 addSymbol("$d", STT_NOTYPE, 12, isec);
989 void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
990 write32(ctx, buf + 0, 0xe59fc004); // P: ldr ip, [pc,#4] ; L2
991 write32(ctx, buf + 4, 0xe08fc00c); // L1: add ip, pc, ip
992 write32(ctx, buf + 8, 0xe12fff1c); // bx ip
993 write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
994 uint64_t s = getARMThunkDestVA(ctx, destination);
995 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
996 ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
999 void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1000 addSymbol(ctx.saver.save("__ARMv4PILongBXThunk_" + destination.getName()),
1001 STT_FUNC, 0, isec);
1002 addSymbol("$a", STT_NOTYPE, 0, isec);
1003 if (!getMayUseShortThunk())
1004 addSymbol("$d", STT_NOTYPE, 12, isec);
1007 void ARMV4PILongThunk::writeLong(uint8_t *buf) {
1008 write32(ctx, buf + 0, 0xe59fc000); // P: ldr ip, [pc] ; L2
1009 write32(ctx, buf + 4, 0xe08ff00c); // L1: add pc, pc, r12
1010 write32(ctx, buf + 8, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1011 uint64_t s = getARMThunkDestVA(ctx, destination);
1012 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1013 ctx.target->relocateNoSym(buf + 8, R_ARM_REL32, s - p - 12);
1016 void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
1017 addSymbol(ctx.saver.save("__ARMv4PILongThunk_" + destination.getName()),
1018 STT_FUNC, 0, isec);
1019 addSymbol("$a", STT_NOTYPE, 0, isec);
1020 if (!getMayUseShortThunk())
1021 addSymbol("$d", STT_NOTYPE, 8, isec);
1024 void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
1025 write16(ctx, buf + 0, 0x4778); // P: bx pc
1026 write16(ctx, buf + 2,
1027 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1028 write32(ctx, buf + 4, 0xe59fc000); // ldr r12, [pc] ; L2
1029 write32(ctx, buf + 8, 0xe08cf00f); // L1: add pc, r12, pc
1030 write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1031 uint64_t s = getARMThunkDestVA(ctx, destination);
1032 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1033 ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 16);
1036 void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1037 addSymbol(ctx.saver.save("__Thumbv4PILongBXThunk_" + destination.getName()),
1038 STT_FUNC, 1, isec);
1039 addSymbol("$t", STT_NOTYPE, 0, isec);
1040 addSymbol("$a", STT_NOTYPE, 4, isec);
1041 if (!getMayUseShortThunk())
1042 addSymbol("$d", STT_NOTYPE, 12, isec);
1045 void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
1046 write16(ctx, buf + 0, 0x4778); // P: bx pc
1047 write16(ctx, buf + 2,
1048 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1049 write32(ctx, buf + 4, 0xe59fc004); // ldr ip, [pc,#4] ; L2
1050 write32(ctx, buf + 8, 0xe08fc00c); // L1: add ip, pc, ip
1051 write32(ctx, buf + 12, 0xe12fff1c); // bx ip
1052 write32(ctx, buf + 16, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1053 uint64_t s = getARMThunkDestVA(ctx, destination);
1054 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1055 ctx.target->relocateNoSym(buf + 16, R_ARM_REL32, s - p - 16);
1058 void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
1059 addSymbol(ctx.saver.save("__Thumbv4PILongThunk_" + destination.getName()),
1060 STT_FUNC, 1, isec);
1061 addSymbol("$t", STT_NOTYPE, 0, isec);
1062 addSymbol("$a", STT_NOTYPE, 4, isec);
1063 if (!getMayUseShortThunk())
1064 addSymbol("$d", STT_NOTYPE, 16, isec);
1067 // Use the long jump which covers a range up to 8MiB.
1068 void AVRThunk::writeTo(uint8_t *buf) {
1069 write32(ctx, buf, 0x940c); // jmp func
1070 ctx.target->relocateNoSym(buf, R_AVR_CALL, destination.getVA(ctx));
1073 void AVRThunk::addSymbols(ThunkSection &isec) {
1074 addSymbol(ctx.saver.save("__AVRThunk_" + destination.getName()), STT_FUNC, 0,
1075 isec);
1078 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
1079 void MipsThunk::writeTo(uint8_t *buf) {
1080 uint64_t s = destination.getVA(ctx);
1081 write32(ctx, buf, 0x3c190000); // lui $25, %hi(func)
1082 write32(ctx, buf + 4, 0x08000000 | (s >> 2)); // j func
1083 write32(ctx, buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
1084 write32(ctx, buf + 12, 0x00000000); // nop
1085 ctx.target->relocateNoSym(buf, R_MIPS_HI16, s);
1086 ctx.target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
1089 void MipsThunk::addSymbols(ThunkSection &isec) {
1090 addSymbol(ctx.saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
1091 isec);
1094 InputSection *MipsThunk::getTargetInputSection() const {
1095 auto &dr = cast<Defined>(destination);
1096 return dyn_cast<InputSection>(dr.section);
1099 // Write microMIPS R2-R5 LA25 thunk code
1100 // to call PIC function from the non-PIC one.
1101 void MicroMipsThunk::writeTo(uint8_t *buf) {
1102 uint64_t s = destination.getVA(ctx);
1103 write16(ctx, buf, 0x41b9); // lui $25, %hi(func)
1104 write16(ctx, buf + 4, 0xd400); // j func
1105 write16(ctx, buf + 8, 0x3339); // addiu $25, $25, %lo(func)
1106 write16(ctx, buf + 12, 0x0c00); // nop
1107 ctx.target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
1108 ctx.target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
1109 ctx.target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
1112 void MicroMipsThunk::addSymbols(ThunkSection &isec) {
1113 Defined *d =
1114 addSymbol(ctx.saver.save("__microLA25Thunk_" + destination.getName()),
1115 STT_FUNC, 0, isec);
1116 d->stOther |= STO_MIPS_MICROMIPS;
1119 InputSection *MicroMipsThunk::getTargetInputSection() const {
1120 auto &dr = cast<Defined>(destination);
1121 return dyn_cast<InputSection>(dr.section);
1124 // Write microMIPS R6 LA25 thunk code
1125 // to call PIC function from the non-PIC one.
1126 void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
1127 uint64_t s = destination.getVA(ctx);
1128 uint64_t p = getThunkTargetSym()->getVA(ctx);
1129 write16(ctx, buf, 0x1320); // lui $25, %hi(func)
1130 write16(ctx, buf + 4, 0x3339); // addiu $25, $25, %lo(func)
1131 write16(ctx, buf + 8, 0x9400); // bc func
1132 ctx.target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
1133 ctx.target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
1134 ctx.target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
1137 void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
1138 Defined *d =
1139 addSymbol(ctx.saver.save("__microLA25Thunk_" + destination.getName()),
1140 STT_FUNC, 0, isec);
1141 d->stOther |= STO_MIPS_MICROMIPS;
1144 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
1145 auto &dr = cast<Defined>(destination);
1146 return dyn_cast<InputSection>(dr.section);
1149 void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t gotPltVA,
1150 const InputFile *file, int64_t addend) {
1151 if (!ctx.arg.isPic) {
1152 write32(ctx, buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
1153 write32(ctx, buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
1154 write32(ctx, buf + 8, 0x7d6903a6); // mtctr r11
1155 write32(ctx, buf + 12, 0x4e800420); // bctr
1156 return;
1158 uint32_t offset;
1159 if (addend >= 0x8000) {
1160 // The stub loads an address relative to r30 (.got2+Addend). Addend is
1161 // almost always 0x8000. The address of .got2 is different in another object
1162 // file, so a stub cannot be shared.
1163 offset = gotPltVA -
1164 (ctx.in.ppc32Got2->getParent()->getVA() +
1165 (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
1166 } else {
1167 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
1168 // currently the address of .got).
1169 offset = gotPltVA - ctx.in.got->getVA();
1171 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
1172 if (ha == 0) {
1173 write32(ctx, buf + 0, 0x817e0000 | l); // lwz r11,l(r30)
1174 write32(ctx, buf + 4, 0x7d6903a6); // mtctr r11
1175 write32(ctx, buf + 8, 0x4e800420); // bctr
1176 write32(ctx, buf + 12, 0x60000000); // nop
1177 } else {
1178 write32(ctx, buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha
1179 write32(ctx, buf + 4, 0x816b0000 | l); // lwz r11,l(r11)
1180 write32(ctx, buf + 8, 0x7d6903a6); // mtctr r11
1181 write32(ctx, buf + 12, 0x4e800420); // bctr
1185 void PPC32PltCallStub::writeTo(uint8_t *buf) {
1186 writePPC32PltCallStub(ctx, buf, destination.getGotPltVA(ctx), file, addend);
1189 void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
1190 std::string buf;
1191 raw_string_ostream os(buf);
1192 os << format_hex_no_prefix(addend, 8);
1193 if (!ctx.arg.isPic)
1194 os << ".plt_call32.";
1195 else if (addend >= 0x8000)
1196 os << ".got2.plt_pic32.";
1197 else
1198 os << ".plt_pic32.";
1199 os << destination.getName();
1200 addSymbol(ctx.saver.save(buf), STT_FUNC, 0, isec);
1203 bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
1204 const Relocation &rel) const {
1205 return !ctx.arg.isPic || (isec.file == file && rel.addend == addend);
1208 void PPC32LongThunk::addSymbols(ThunkSection &isec) {
1209 addSymbol(ctx.saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
1210 isec);
1213 void PPC32LongThunk::writeTo(uint8_t *buf) {
1214 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
1215 auto lo = [](uint32_t v) -> uint16_t { return v; };
1216 uint32_t d = destination.getVA(ctx, addend);
1217 if (ctx.arg.isPic) {
1218 uint32_t off = d - (getThunkTargetSym()->getVA(ctx) + 8);
1219 write32(ctx, buf + 0, 0x7c0802a6); // mflr r12,0
1220 write32(ctx, buf + 4, 0x429f0005); // bcl r20,r31,.+4
1221 write32(ctx, buf + 8, 0x7d8802a6); // mtctr r12
1222 write32(ctx, buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
1223 write32(ctx, buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
1224 write32(ctx, buf + 20, 0x7c0803a6); // mtlr r0
1225 buf += 24;
1226 } else {
1227 write32(ctx, buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
1228 write32(ctx, buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
1229 buf += 8;
1231 write32(ctx, buf + 0, 0x7d8903a6); // mtctr r12
1232 write32(ctx, buf + 4, 0x4e800420); // bctr
1235 void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, int64_t offset) {
1236 uint16_t offHa = (offset + 0x8000) >> 16;
1237 uint16_t offLo = offset & 0xffff;
1239 write32(ctx, buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa
1240 write32(ctx, buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)
1241 write32(ctx, buf + 8, 0x7d8903a6); // mtctr r12
1242 write32(ctx, buf + 12, 0x4e800420); // bctr
1245 void PPC64PltCallStub::writeTo(uint8_t *buf) {
1246 int64_t offset = destination.getGotPltVA(ctx) - getPPC64TocBase(ctx);
1247 // Save the TOC pointer to the save-slot reserved in the call frame.
1248 write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1)
1249 writePPC64LoadAndBranch(ctx, buf + 4, offset);
1252 void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
1253 Defined *s = addSymbol(ctx.saver.save("__plt_" + destination.getName()),
1254 STT_FUNC, 0, isec);
1255 s->setNeedsTocRestore(true);
1256 s->file = destination.file;
1259 bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
1260 const Relocation &rel) const {
1261 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1264 void PPC64R2SaveStub::writeTo(uint8_t *buf) {
1265 const int64_t offset = computeOffset();
1266 write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1)
1267 // The branch offset needs to fit in 26 bits.
1268 if (getMayUseShortThunk()) {
1269 write32(ctx, buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
1270 } else if (isInt<34>(offset)) {
1271 int nextInstOffset;
1272 uint64_t tocOffset = destination.getVA(ctx) - getPPC64TocBase(ctx);
1273 if (tocOffset >> 16 > 0) {
1274 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
1275 const uint64_t addis =
1276 ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
1277 write32(ctx, buf + 4, addis); // addis r12, r2 , top of offset
1278 write32(ctx, buf + 8, addi); // addi r12, r12, bottom of offset
1279 nextInstOffset = 12;
1280 } else {
1281 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
1282 write32(ctx, buf + 4, addi); // addi r12, r2, offset
1283 nextInstOffset = 8;
1285 write32(ctx, buf + nextInstOffset, MTCTR_R12); // mtctr r12
1286 write32(ctx, buf + nextInstOffset + 4, BCTR); // bctr
1287 } else {
1288 ctx.in.ppc64LongBranchTarget->addEntry(&destination, addend);
1289 const int64_t offsetFromTOC =
1290 ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1291 getPPC64TocBase(ctx);
1292 writePPC64LoadAndBranch(ctx, buf + 4, offsetFromTOC);
1296 void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
1297 Defined *s = addSymbol(ctx.saver.save("__toc_save_" + destination.getName()),
1298 STT_FUNC, 0, isec);
1299 s->setNeedsTocRestore(true);
1302 bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
1303 const Relocation &rel) const {
1304 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1307 void PPC64R12SetupStub::writeTo(uint8_t *buf) {
1308 int64_t offset =
1309 (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA(ctx)) -
1310 getThunkTargetSym()->getVA(ctx);
1311 if (!isInt<34>(offset))
1312 reportRangeError(ctx, buf, offset, 34, destination,
1313 "R12 setup stub offset");
1315 int nextInstOffset;
1316 if (ctx.arg.power10Stubs) {
1317 const uint64_t imm = (((offset >> 16) & 0x3ffff) << 32) | (offset & 0xffff);
1318 // pld 12, func@plt@pcrel or paddi r12, 0, func@pcrel
1319 writePrefixedInst(ctx, buf,
1320 (gotPlt ? PLD_R12_NO_DISP : PADDI_R12_NO_DISP) | imm);
1321 nextInstOffset = 8;
1322 } else {
1323 uint32_t off = offset - 8;
1324 write32(ctx, buf + 0, 0x7d8802a6); // mflr 12
1325 write32(ctx, buf + 4, 0x429f0005); // bcl 20,31,.+4
1326 write32(ctx, buf + 8, 0x7d6802a6); // mflr 11
1327 write32(ctx, buf + 12, 0x7d8803a6); // mtlr 12
1328 write32(ctx, buf + 16,
1329 0x3d8b0000 | ((off + 0x8000) >> 16)); // addis 12,11,off@ha
1330 if (gotPlt)
1331 write32(ctx, buf + 20, 0xe98c0000 | (off & 0xffff)); // ld 12, off@l(12)
1332 else
1333 write32(ctx, buf + 20, 0x398c0000 | (off & 0xffff)); // addi 12,12,off@l
1334 nextInstOffset = 24;
1336 write32(ctx, buf + nextInstOffset, MTCTR_R12); // mtctr r12
1337 write32(ctx, buf + nextInstOffset + 4, BCTR); // bctr
1340 void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
1341 addSymbol(ctx.saver.save((gotPlt ? "__plt_pcrel_" : "__gep_setup_") +
1342 destination.getName()),
1343 STT_FUNC, 0, isec);
1346 bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
1347 const Relocation &rel) const {
1348 return rel.type == R_PPC64_REL24_NOTOC;
1351 void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
1352 int64_t offset =
1353 ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1354 getPPC64TocBase(ctx);
1355 writePPC64LoadAndBranch(ctx, buf, offset);
1358 void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
1359 addSymbol(ctx.saver.save("__long_branch_" + destination.getName()), STT_FUNC,
1360 0, isec);
1363 bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
1364 const Relocation &rel) const {
1365 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1368 Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
1369 : ctx(ctx), destination(d), addend(a), offset(0) {
1370 destination.thunkAccessed = true;
1373 Thunk::~Thunk() = default;
1375 static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
1376 int64_t a) {
1377 assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
1378 type));
1379 bool mayNeedLandingPad =
1380 (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
1381 !isAArch64BTILandingPad(ctx, s, a);
1382 if (ctx.arg.picThunk)
1383 return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
1384 return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
1387 // Creates a thunk for long branches or Thumb-ARM interworking.
1388 // Arm Architectures v4t does not support Thumb2 technology, and does not
1389 // support BLX or LDR Arm/Thumb state switching. This means that
1390 // - MOVT and MOVW instructions cannot be used.
1391 // - We can't rewrite BL in place to BLX. We will need thunks.
1393 // TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
1394 // Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
1395 static std::unique_ptr<Thunk> addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s,
1396 int64_t a) {
1397 bool thumb_target = s.getVA(ctx, a) & 1;
1399 switch (reloc) {
1400 case R_ARM_PC24:
1401 case R_ARM_PLT32:
1402 case R_ARM_JUMP24:
1403 case R_ARM_CALL:
1404 if (ctx.arg.picThunk) {
1405 if (thumb_target)
1406 return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);
1407 return std::make_unique<ARMV4PILongThunk>(ctx, s, a);
1409 if (thumb_target)
1410 return std::make_unique<ARMV4ABSLongBXThunk>(ctx, s, a);
1411 return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);
1412 case R_ARM_THM_CALL:
1413 if (ctx.arg.picThunk) {
1414 if (thumb_target)
1415 return std::make_unique<ThumbV4PILongThunk>(ctx, s, a);
1416 return std::make_unique<ThumbV4PILongBXThunk>(ctx, s, a);
1418 if (thumb_target)
1419 return std::make_unique<ThumbV4ABSLongThunk>(ctx, s, a);
1420 return std::make_unique<ThumbV4ABSLongBXThunk>(ctx, s, a);
1422 Fatal(ctx) << "relocation " << reloc << " to " << &s
1423 << " not supported for Armv4 or Armv4T target";
1424 llvm_unreachable("");
1427 // Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
1428 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
1429 // - MOVT and MOVW instructions cannot be used
1430 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
1431 // be transformed into a BLX
1432 static std::unique_ptr<Thunk> addThunkArmv5v6(Ctx &ctx, RelType reloc,
1433 Symbol &s, int64_t a) {
1434 switch (reloc) {
1435 case R_ARM_PC24:
1436 case R_ARM_PLT32:
1437 case R_ARM_JUMP24:
1438 case R_ARM_CALL:
1439 case R_ARM_THM_CALL:
1440 if (ctx.arg.picThunk)
1441 return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);
1442 return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);
1444 Fatal(ctx) << "relocation " << reloc << " to " << &s
1445 << " not supported for Armv5 or Armv6 targets";
1446 llvm_unreachable("");
1449 // Create a thunk for Thumb long branch on V6-M.
1450 // Arm Architecture v6-M only supports Thumb instructions. This means
1451 // - MOVT and MOVW instructions cannot be used.
1452 // - Only a limited number of instructions can access registers r8 and above
1453 // - No interworking support is needed (all Thumb).
1454 static std::unique_ptr<Thunk> addThunkV6M(Ctx &ctx, const InputSection &isec,
1455 RelType reloc, Symbol &s, int64_t a) {
1456 const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE;
1457 switch (reloc) {
1458 case R_ARM_THM_JUMP19:
1459 case R_ARM_THM_JUMP24:
1460 case R_ARM_THM_CALL:
1461 if (ctx.arg.isPic) {
1462 if (!isPureCode)
1463 return std::make_unique<ThumbV6MPILongThunk>(ctx, s, a);
1465 Fatal(ctx)
1466 << "relocation " << reloc << " to " << &s
1467 << " not supported for Armv6-M targets for position independent"
1468 " and execute only code";
1469 llvm_unreachable("");
1471 if (isPureCode)
1472 return std::make_unique<ThumbV6MABSXOLongThunk>(ctx, s, a);
1473 return std::make_unique<ThumbV6MABSLongThunk>(ctx, s, a);
1475 Fatal(ctx) << "relocation " << reloc << " to " << &s
1476 << " not supported for Armv6-M targets";
1477 llvm_unreachable("");
1480 // Creates a thunk for Thumb-ARM interworking or branch range extension.
1481 static std::unique_ptr<Thunk> addThunkArm(Ctx &ctx, const InputSection &isec,
1482 RelType reloc, Symbol &s, int64_t a) {
1483 // Decide which Thunk is needed based on:
1484 // Available instruction set
1485 // - An Arm Thunk can only be used if Arm state is available.
1486 // - A Thumb Thunk can only be used if Thumb state is available.
1487 // - Can only use a Thunk if it uses instructions that the Target supports.
1488 // Relocation is branch or branch and link
1489 // - Branch instructions cannot change state, can only select Thunk that
1490 // starts in the same state as the caller.
1491 // - Branch and link relocations can change state, can select Thunks from
1492 // either Arm or Thumb.
1493 // Position independent Thunks if we require position independent code.
1494 // Execute Only Thunks if the output section is execute only code.
1496 // Handle architectures that have restrictions on the instructions that they
1497 // can use in Thunks. The flags below are set by reading the BuildAttributes
1498 // of the input objects. InputFiles.cpp contains the mapping from ARM
1499 // architecture to flag.
1500 if (!ctx.arg.armHasMovtMovw) {
1501 if (ctx.arg.armJ1J2BranchEncoding)
1502 return addThunkV6M(ctx, isec, reloc, s, a);
1503 if (ctx.arg.armHasBlx)
1504 return addThunkArmv5v6(ctx, reloc, s, a);
1505 return addThunkArmv4(ctx, reloc, s, a);
1508 switch (reloc) {
1509 case R_ARM_PC24:
1510 case R_ARM_PLT32:
1511 case R_ARM_JUMP24:
1512 case R_ARM_CALL:
1513 if (ctx.arg.picThunk)
1514 return std::make_unique<ARMV7PILongThunk>(ctx, s, a);
1515 return std::make_unique<ARMV7ABSLongThunk>(ctx, s, a);
1516 case R_ARM_THM_JUMP19:
1517 case R_ARM_THM_JUMP24:
1518 case R_ARM_THM_CALL:
1519 if (ctx.arg.picThunk)
1520 return std::make_unique<ThumbV7PILongThunk>(ctx, s, a);
1521 return std::make_unique<ThumbV7ABSLongThunk>(ctx, s, a);
1523 llvm_unreachable("");
1526 static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,
1527 int64_t a) {
1528 switch (type) {
1529 case R_AVR_LO8_LDI_GS:
1530 case R_AVR_HI8_LDI_GS:
1531 return std::make_unique<AVRThunk>(ctx, s, a);
1532 default:
1533 llvm_unreachable("");
1537 static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
1538 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
1539 return std::make_unique<MicroMipsR6Thunk>(ctx, s);
1540 if (s.stOther & STO_MIPS_MICROMIPS)
1541 return std::make_unique<MicroMipsThunk>(ctx, s);
1542 return std::make_unique<MipsThunk>(ctx, s);
1545 static std::unique_ptr<Thunk> addThunkPPC32(Ctx &ctx, const InputSection &isec,
1546 const Relocation &rel, Symbol &s) {
1547 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
1548 rel.type == R_PPC_PLTREL24) &&
1549 "unexpected relocation type for thunk");
1550 if (s.isInPlt(ctx))
1551 return std::make_unique<PPC32PltCallStub>(ctx, isec, rel, s);
1552 return std::make_unique<PPC32LongThunk>(ctx, s, rel.addend);
1555 static std::unique_ptr<Thunk> addThunkPPC64(Ctx &ctx, RelType type, Symbol &s,
1556 int64_t a) {
1557 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
1558 type == R_PPC64_REL24_NOTOC) &&
1559 "unexpected relocation type for thunk");
1561 // If we are emitting stubs for NOTOC relocations, we need to tell
1562 // the PLT resolver that there can be multiple TOCs.
1563 if (type == R_PPC64_REL24_NOTOC)
1564 ctx.target->ppc64DynamicSectionOpt = 0x2;
1566 if (s.isInPlt(ctx)) {
1567 if (type == R_PPC64_REL24_NOTOC)
1568 return std::make_unique<PPC64R12SetupStub>(ctx, s,
1569 /*gotPlt=*/true);
1570 return std::make_unique<PPC64PltCallStub>(ctx, s);
1573 // This check looks at the st_other bits of the callee. If the value is 1
1574 // then the callee clobbers the TOC and we need an R2 save stub when RelType
1575 // is R_PPC64_REL14 or R_PPC64_REL24.
1576 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
1577 return std::make_unique<PPC64R2SaveStub>(ctx, s, a);
1579 if (type == R_PPC64_REL24_NOTOC)
1580 return std::make_unique<PPC64R12SetupStub>(ctx, s, /*gotPlt=*/false);
1582 if (ctx.arg.picThunk)
1583 return std::make_unique<PPC64PILongBranchThunk>(ctx, s, a);
1585 return std::make_unique<PPC64PDLongBranchThunk>(ctx, s, a);
1588 std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
1589 Relocation &rel) {
1590 Symbol &s = *rel.sym;
1591 int64_t a = rel.addend;
1593 switch (ctx.arg.emachine) {
1594 case EM_AARCH64:
1595 return addThunkAArch64(ctx, rel.type, s, a);
1596 case EM_ARM:
1597 return addThunkArm(ctx, isec, rel.type, s, a);
1598 case EM_AVR:
1599 return addThunkAVR(ctx, rel.type, s, a);
1600 case EM_MIPS:
1601 return addThunkMips(ctx, rel.type, s);
1602 case EM_PPC:
1603 return addThunkPPC32(ctx, isec, rel, s);
1604 case EM_PPC64:
1605 return addThunkPPC64(ctx, rel.type, s, a);
1606 default:
1607 llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");
1611 std::unique_ptr<Thunk> elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) {
1612 switch (ctx.arg.emachine) {
1613 case EM_AARCH64:
1614 return std::make_unique<AArch64BTILandingPadThunk>(ctx, s, a);
1615 default:
1616 llvm_unreachable("add landing pad only supported for AArch64");