workflows/release-tasks: Remove stray backslash
[llvm-project.git] / lld / ELF / Thunks.cpp
blob26f3041021f30a213fbc88efe94b17005f153e5e
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.
55 class AArch64Thunk : public Thunk {
56 public:
57 AArch64Thunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
58 bool getMayUseShortThunk();
59 void writeTo(uint8_t *buf) override;
61 private:
62 bool mayUseShortThunk = true;
63 virtual void writeLong(uint8_t *buf) = 0;
66 // AArch64 long range Thunks.
67 class AArch64ABSLongThunk final : public AArch64Thunk {
68 public:
69 AArch64ABSLongThunk(Symbol &dest, int64_t addend)
70 : AArch64Thunk(dest, addend) {}
71 uint32_t size() override { return getMayUseShortThunk() ? 4 : 16; }
72 void addSymbols(ThunkSection &isec) override;
74 private:
75 void writeLong(uint8_t *buf) override;
78 class AArch64ADRPThunk final : public AArch64Thunk {
79 public:
80 AArch64ADRPThunk(Symbol &dest, int64_t addend) : AArch64Thunk(dest, addend) {}
81 uint32_t size() override { return getMayUseShortThunk() ? 4 : 12; }
82 void addSymbols(ThunkSection &isec) override;
84 private:
85 void writeLong(uint8_t *buf) override;
88 // Base class for ARM thunks.
90 // An ARM thunk may be either short or long. A short thunk is simply a branch
91 // (B) instruction, and it may be used to call ARM functions when the distance
92 // from the thunk to the target is less than 32MB. Long thunks can branch to any
93 // virtual address and can switch between ARM and Thumb, and they are
94 // implemented in the derived classes. This class tries to create a short thunk
95 // if the target is in range, otherwise it creates a long thunk.
96 class ARMThunk : public Thunk {
97 public:
98 ARMThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
100 bool getMayUseShortThunk();
101 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
102 void writeTo(uint8_t *buf) override;
103 bool isCompatibleWith(const InputSection &isec,
104 const Relocation &rel) const override;
106 // Returns the size of a long thunk.
107 virtual uint32_t sizeLong() = 0;
109 // Writes a long thunk to Buf.
110 virtual void writeLong(uint8_t *buf) = 0;
112 private:
113 // This field tracks whether all previously considered layouts would allow
114 // this thunk to be short. If we have ever needed a long thunk, we always
115 // create a long thunk, even if the thunk may be short given the current
116 // distance to the target. We do this because transitioning from long to short
117 // can create layout oscillations in certain corner cases which would prevent
118 // the layout from converging.
119 bool mayUseShortThunk = true;
122 // Base class for Thumb-2 thunks.
124 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
125 // which has a range of 16MB.
126 class ThumbThunk : public Thunk {
127 public:
128 ThumbThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
129 alignment = 2;
132 bool getMayUseShortThunk();
133 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
134 void writeTo(uint8_t *buf) override;
135 bool isCompatibleWith(const InputSection &isec,
136 const Relocation &rel) const override;
138 // Returns the size of a long thunk.
139 virtual uint32_t sizeLong() = 0;
141 // Writes a long thunk to Buf.
142 virtual void writeLong(uint8_t *buf) = 0;
144 private:
145 // See comment in ARMThunk above.
146 bool mayUseShortThunk = true;
149 // Specific ARM Thunk implementations. The naming convention is:
150 // Source State, TargetState, Target Requirement, ABS or PI, Range
151 class ARMV7ABSLongThunk final : public ARMThunk {
152 public:
153 ARMV7ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
155 uint32_t sizeLong() override { return 12; }
156 void writeLong(uint8_t *buf) override;
157 void addSymbols(ThunkSection &isec) override;
160 class ARMV7PILongThunk final : public ARMThunk {
161 public:
162 ARMV7PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
164 uint32_t sizeLong() override { return 16; }
165 void writeLong(uint8_t *buf) override;
166 void addSymbols(ThunkSection &isec) override;
169 class ThumbV7ABSLongThunk final : public ThumbThunk {
170 public:
171 ThumbV7ABSLongThunk(Symbol &dest, int64_t addend)
172 : ThumbThunk(dest, addend) {}
174 uint32_t sizeLong() override { return 10; }
175 void writeLong(uint8_t *buf) override;
176 void addSymbols(ThunkSection &isec) override;
179 class ThumbV7PILongThunk final : public ThumbThunk {
180 public:
181 ThumbV7PILongThunk(Symbol &dest, int64_t addend) : ThumbThunk(dest, addend) {}
183 uint32_t sizeLong() override { return 12; }
184 void writeLong(uint8_t *buf) override;
185 void addSymbols(ThunkSection &isec) override;
188 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
189 class ThumbV6MABSLongThunk final : public ThumbThunk {
190 public:
191 ThumbV6MABSLongThunk(Symbol &dest, int64_t addend)
192 : ThumbThunk(dest, addend) {}
194 uint32_t sizeLong() override { return 12; }
195 void writeLong(uint8_t *buf) override;
196 void addSymbols(ThunkSection &isec) override;
199 class ThumbV6MPILongThunk final : public ThumbThunk {
200 public:
201 ThumbV6MPILongThunk(Symbol &dest, int64_t addend)
202 : ThumbThunk(dest, addend) {}
204 uint32_t sizeLong() override { return 16; }
205 void writeLong(uint8_t *buf) override;
206 void addSymbols(ThunkSection &isec) override;
209 // Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
210 // v6 support BLX to which BL instructions can be rewritten inline. There are no
211 // Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on
212 // these architecture that can result in a thunk.
214 // LDR on v5 and v6 can switch processor state, so for v5 and v6,
215 // ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4
216 // can also use this thunk, but only for Arm->Arm calls.
217 class ARMV5LongLdrPcThunk final : public ARMThunk {
218 public:
219 ARMV5LongLdrPcThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
221 uint32_t sizeLong() override { return 8; }
222 void writeLong(uint8_t *buf) override;
223 void addSymbols(ThunkSection &isec) override;
226 // Implementations of Thunks for v4. BLX is not supported, and loads
227 // will not invoke Arm/Thumb state changes.
228 class ARMV4PILongBXThunk final : public ARMThunk {
229 public:
230 ARMV4PILongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
232 uint32_t sizeLong() override { return 16; }
233 void writeLong(uint8_t *buf) override;
234 void addSymbols(ThunkSection &isec) override;
237 class ARMV4PILongThunk final : public ARMThunk {
238 public:
239 ARMV4PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
241 uint32_t sizeLong() override { return 12; }
242 void writeLong(uint8_t *buf) override;
243 void addSymbols(ThunkSection &isec) override;
246 class ThumbV4PILongBXThunk final : public ThumbThunk {
247 public:
248 ThumbV4PILongBXThunk(Symbol &dest, int64_t addend)
249 : ThumbThunk(dest, addend) {}
251 uint32_t sizeLong() override { return 16; }
252 void writeLong(uint8_t *buf) override;
253 void addSymbols(ThunkSection &isec) override;
256 class ThumbV4PILongThunk final : public ThumbThunk {
257 public:
258 ThumbV4PILongThunk(Symbol &dest, int64_t addend)
259 : ThumbThunk(dest, addend) {}
261 uint32_t sizeLong() override { return 20; }
262 void writeLong(uint8_t *buf) override;
263 void addSymbols(ThunkSection &isec) override;
266 class ARMV4ABSLongBXThunk final : public ARMThunk {
267 public:
268 ARMV4ABSLongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
270 uint32_t sizeLong() override { return 12; }
271 void writeLong(uint8_t *buf) override;
272 void addSymbols(ThunkSection &isec) override;
275 class ThumbV4ABSLongBXThunk final : public ThumbThunk {
276 public:
277 ThumbV4ABSLongBXThunk(Symbol &dest, int64_t addend)
278 : ThumbThunk(dest, addend) {}
280 uint32_t sizeLong() override { return 12; }
281 void writeLong(uint8_t *buf) override;
282 void addSymbols(ThunkSection &isec) override;
285 class ThumbV4ABSLongThunk final : public ThumbThunk {
286 public:
287 ThumbV4ABSLongThunk(Symbol &dest, int64_t addend)
288 : ThumbThunk(dest, addend) {}
290 uint32_t sizeLong() override { return 16; }
291 void writeLong(uint8_t *buf) override;
292 void addSymbols(ThunkSection &isec) override;
295 // The AVR devices need thunks for R_AVR_LO8_LDI_GS/R_AVR_HI8_LDI_GS
296 // when their destination is out of range [0, 0x1ffff].
297 class AVRThunk : public Thunk {
298 public:
299 AVRThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
300 uint32_t size() override { return 4; }
301 void writeTo(uint8_t *buf) override;
302 void addSymbols(ThunkSection &isec) override;
305 // MIPS LA25 thunk
306 class MipsThunk final : public Thunk {
307 public:
308 MipsThunk(Symbol &dest) : Thunk(dest, 0) {}
310 uint32_t size() override { return 16; }
311 void writeTo(uint8_t *buf) override;
312 void addSymbols(ThunkSection &isec) override;
313 InputSection *getTargetInputSection() const override;
316 // microMIPS R2-R5 LA25 thunk
317 class MicroMipsThunk final : public Thunk {
318 public:
319 MicroMipsThunk(Symbol &dest) : Thunk(dest, 0) {}
321 uint32_t size() override { return 14; }
322 void writeTo(uint8_t *buf) override;
323 void addSymbols(ThunkSection &isec) override;
324 InputSection *getTargetInputSection() const override;
327 // microMIPS R6 LA25 thunk
328 class MicroMipsR6Thunk final : public Thunk {
329 public:
330 MicroMipsR6Thunk(Symbol &dest) : Thunk(dest, 0) {}
332 uint32_t size() override { return 12; }
333 void writeTo(uint8_t *buf) override;
334 void addSymbols(ThunkSection &isec) override;
335 InputSection *getTargetInputSection() const override;
338 class PPC32PltCallStub final : public Thunk {
339 public:
340 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
341 // decide the offsets in the call stub.
342 PPC32PltCallStub(const InputSection &isec, const Relocation &rel,
343 Symbol &dest)
344 : Thunk(dest, rel.addend), file(isec.file) {}
345 uint32_t size() override { return 16; }
346 void writeTo(uint8_t *buf) override;
347 void addSymbols(ThunkSection &isec) override;
348 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
350 private:
351 // Records the call site of the call stub.
352 const InputFile *file;
355 class PPC32LongThunk final : public Thunk {
356 public:
357 PPC32LongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
358 uint32_t size() override { return config->isPic ? 32 : 16; }
359 void writeTo(uint8_t *buf) override;
360 void addSymbols(ThunkSection &isec) override;
363 // PPC64 Plt call stubs.
364 // Any call site that needs to call through a plt entry needs a call stub in
365 // the .text section. The call stub is responsible for:
366 // 1) Saving the toc-pointer to the stack.
367 // 2) Loading the target functions address from the procedure linkage table into
368 // r12 for use by the target functions global entry point, and into the count
369 // register.
370 // 3) Transferring control to the target function through an indirect branch.
371 class PPC64PltCallStub final : public Thunk {
372 public:
373 PPC64PltCallStub(Symbol &dest) : Thunk(dest, 0) {}
374 uint32_t size() override { return 20; }
375 void writeTo(uint8_t *buf) override;
376 void addSymbols(ThunkSection &isec) override;
377 bool isCompatibleWith(const InputSection &isec,
378 const Relocation &rel) const override;
381 // PPC64 R2 Save Stub
382 // When the caller requires a valid R2 TOC pointer but the callee does not
383 // require a TOC pointer and the callee cannot guarantee that it doesn't
384 // clobber R2 then we need to save R2. This stub:
385 // 1) Saves the TOC pointer to the stack.
386 // 2) Tail calls the callee.
387 class PPC64R2SaveStub final : public Thunk {
388 public:
389 PPC64R2SaveStub(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
390 alignment = 16;
393 // To prevent oscillations in layout when moving from short to long thunks
394 // we make sure that once a thunk has been set to long it cannot go back.
395 bool getMayUseShortThunk() {
396 if (!mayUseShortThunk)
397 return false;
398 if (!isInt<26>(computeOffset())) {
399 mayUseShortThunk = false;
400 return false;
402 return true;
404 uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
405 void writeTo(uint8_t *buf) override;
406 void addSymbols(ThunkSection &isec) override;
407 bool isCompatibleWith(const InputSection &isec,
408 const Relocation &rel) const override;
410 private:
411 // Transitioning from long to short can create layout oscillations in
412 // certain corner cases which would prevent the layout from converging.
413 // This is similar to the handling for ARMThunk.
414 bool mayUseShortThunk = true;
415 int64_t computeOffset() const {
416 return destination.getVA() - (getThunkTargetSym()->getVA() + 4);
420 // PPC64 R12 Setup Stub
421 // When a caller that does not maintain TOC calls a target which may possibly
422 // use TOC (either non-preemptible with localentry>1 or preemptible), we need to
423 // set r12 to satisfy the requirement of the global entry point.
424 class PPC64R12SetupStub final : public Thunk {
425 public:
426 PPC64R12SetupStub(Symbol &dest, bool gotPlt)
427 : Thunk(dest, 0), gotPlt(gotPlt) {
428 alignment = 16;
430 uint32_t size() override { return 32; }
431 void writeTo(uint8_t *buf) override;
432 void addSymbols(ThunkSection &isec) override;
433 bool isCompatibleWith(const InputSection &isec,
434 const Relocation &rel) const override;
436 private:
437 bool gotPlt;
440 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
441 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
442 // larger than that we need to emit a long-branch thunk. The target address
443 // of the callee is stored in a table to be accessed TOC-relative. Since the
444 // call must be local (a non-local call will have a PltCallStub instead) the
445 // table stores the address of the callee's local entry point. For
446 // position-independent code a corresponding relative dynamic relocation is
447 // used.
448 class PPC64LongBranchThunk : public Thunk {
449 public:
450 uint32_t size() override { return 32; }
451 void writeTo(uint8_t *buf) override;
452 void addSymbols(ThunkSection &isec) override;
453 bool isCompatibleWith(const InputSection &isec,
454 const Relocation &rel) const override;
456 protected:
457 PPC64LongBranchThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
460 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
461 public:
462 PPC64PILongBranchThunk(Symbol &dest, int64_t addend)
463 : PPC64LongBranchThunk(dest, addend) {
464 assert(!dest.isPreemptible);
465 if (std::optional<uint32_t> index =
466 in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
467 mainPart->relaDyn->addRelativeReloc(
468 target->relativeRel, *in.ppc64LongBranchTarget, *index * UINT64_C(8),
469 dest, addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther),
470 target->symbolicRel, R_ABS);
475 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
476 public:
477 PPC64PDLongBranchThunk(Symbol &dest, int64_t addend)
478 : PPC64LongBranchThunk(dest, addend) {
479 in.ppc64LongBranchTarget->addEntry(&dest, addend);
483 } // end anonymous namespace
485 Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
486 InputSectionBase &section) {
487 Defined *d = addSyntheticLocal(name, type, value, /*size=*/0, section);
488 syms.push_back(d);
489 return d;
492 void Thunk::setOffset(uint64_t newOffset) {
493 for (Defined *d : syms)
494 d->value = d->value - offset + newOffset;
495 offset = newOffset;
498 // AArch64 Thunk base class.
499 static uint64_t getAArch64ThunkDestVA(const Symbol &s, int64_t a) {
500 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA(a);
501 return v;
504 bool AArch64Thunk::getMayUseShortThunk() {
505 if (!mayUseShortThunk)
506 return false;
507 uint64_t s = getAArch64ThunkDestVA(destination, addend);
508 uint64_t p = getThunkTargetSym()->getVA();
509 mayUseShortThunk = llvm::isInt<28>(s - p);
510 return mayUseShortThunk;
513 void AArch64Thunk::writeTo(uint8_t *buf) {
514 if (!getMayUseShortThunk()) {
515 writeLong(buf);
516 return;
518 uint64_t s = getAArch64ThunkDestVA(destination, addend);
519 uint64_t p = getThunkTargetSym()->getVA();
520 write32(buf, 0x14000000); // b S
521 target->relocateNoSym(buf, R_AARCH64_CALL26, s - p);
524 // AArch64 long range Thunks.
525 void AArch64ABSLongThunk::writeLong(uint8_t *buf) {
526 const uint8_t data[] = {
527 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
528 0x00, 0x02, 0x1f, 0xd6, // br x16
529 0x00, 0x00, 0x00, 0x00, // L0: .xword S
530 0x00, 0x00, 0x00, 0x00,
532 uint64_t s = getAArch64ThunkDestVA(destination, addend);
533 memcpy(buf, data, sizeof(data));
534 target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
537 void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
538 addSymbol(saver().save("__AArch64AbsLongThunk_" + destination.getName()),
539 STT_FUNC, 0, isec);
540 addSymbol("$x", STT_NOTYPE, 0, isec);
541 if (!getMayUseShortThunk())
542 addSymbol("$d", STT_NOTYPE, 8, isec);
545 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
546 // using the small code model, including pc-relative ones. At time of writing
547 // clang and gcc do not support the large code model for position independent
548 // code so it is safe to use this for position independent thunks without
549 // worrying about the destination being more than 4Gb away.
550 void AArch64ADRPThunk::writeLong(uint8_t *buf) {
551 const uint8_t data[] = {
552 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
553 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
554 0x00, 0x02, 0x1f, 0xd6, // br x16
556 uint64_t s = getAArch64ThunkDestVA(destination, addend);
557 uint64_t p = getThunkTargetSym()->getVA();
558 memcpy(buf, data, sizeof(data));
559 target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
560 getAArch64Page(s) - getAArch64Page(p));
561 target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
564 void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
565 addSymbol(saver().save("__AArch64ADRPThunk_" + destination.getName()),
566 STT_FUNC, 0, isec);
567 addSymbol("$x", STT_NOTYPE, 0, isec);
570 // ARM Target Thunks
571 static uint64_t getARMThunkDestVA(const Symbol &s) {
572 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA();
573 return SignExtend64<32>(v);
576 // This function returns true if the target is not Thumb and is within 2^26, and
577 // it has not previously returned false (see comment for mayUseShortThunk).
578 bool ARMThunk::getMayUseShortThunk() {
579 if (!mayUseShortThunk)
580 return false;
581 uint64_t s = getARMThunkDestVA(destination);
582 if (s & 1) {
583 mayUseShortThunk = false;
584 return false;
586 uint64_t p = getThunkTargetSym()->getVA();
587 int64_t offset = s - p - 8;
588 mayUseShortThunk = llvm::isInt<26>(offset);
589 return mayUseShortThunk;
592 void ARMThunk::writeTo(uint8_t *buf) {
593 if (!getMayUseShortThunk()) {
594 writeLong(buf);
595 return;
598 uint64_t s = getARMThunkDestVA(destination);
599 uint64_t p = getThunkTargetSym()->getVA();
600 int64_t offset = s - p - 8;
601 write32(buf, 0xea000000); // b S
602 target->relocateNoSym(buf, R_ARM_JUMP24, offset);
605 bool ARMThunk::isCompatibleWith(const InputSection &isec,
606 const Relocation &rel) const {
607 // v4T does not have BLX, so also deny R_ARM_THM_CALL
608 if (!config->armHasBlx && rel.type == R_ARM_THM_CALL)
609 return false;
611 // Thumb branch relocations can't use BLX
612 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
615 // This function returns true if:
616 // the target is Thumb
617 // && is within branch range
618 // && this function has not previously returned false
619 // (see comment for mayUseShortThunk)
620 // && the arch supports Thumb branch range extension.
621 bool ThumbThunk::getMayUseShortThunk() {
622 if (!mayUseShortThunk || !config->armJ1J2BranchEncoding)
623 return false;
624 uint64_t s = getARMThunkDestVA(destination);
625 if ((s & 1) == 0) {
626 mayUseShortThunk = false;
627 return false;
629 uint64_t p = getThunkTargetSym()->getVA() & ~1;
630 int64_t offset = s - p - 4;
631 mayUseShortThunk = llvm::isInt<25>(offset);
632 return mayUseShortThunk;
635 void ThumbThunk::writeTo(uint8_t *buf) {
636 if (!getMayUseShortThunk()) {
637 writeLong(buf);
638 return;
641 uint64_t s = getARMThunkDestVA(destination);
642 uint64_t p = getThunkTargetSym()->getVA();
643 int64_t offset = s - p - 4;
644 write16(buf + 0, 0xf000); // b.w S
645 write16(buf + 2, 0xb000);
646 target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
649 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
650 const Relocation &rel) const {
651 // v4T does not have BLX, so also deny R_ARM_CALL
652 if (!config->armHasBlx && rel.type == R_ARM_CALL)
653 return false;
655 // ARM branch relocations can't use BLX
656 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
659 void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
660 write32(buf + 0, 0xe300c000); // movw ip,:lower16:S
661 write32(buf + 4, 0xe340c000); // movt ip,:upper16:S
662 write32(buf + 8, 0xe12fff1c); // bx ip
663 uint64_t s = getARMThunkDestVA(destination);
664 target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
665 target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
668 void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
669 addSymbol(saver().save("__ARMv7ABSLongThunk_" + destination.getName()),
670 STT_FUNC, 0, isec);
671 addSymbol("$a", STT_NOTYPE, 0, isec);
674 void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
675 write16(buf + 0, 0xf240); // movw ip, :lower16:S
676 write16(buf + 2, 0x0c00);
677 write16(buf + 4, 0xf2c0); // movt ip, :upper16:S
678 write16(buf + 6, 0x0c00);
679 write16(buf + 8, 0x4760); // bx ip
680 uint64_t s = getARMThunkDestVA(destination);
681 target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
682 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
685 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
686 addSymbol(saver().save("__Thumbv7ABSLongThunk_" + destination.getName()),
687 STT_FUNC, 1, isec);
688 addSymbol("$t", STT_NOTYPE, 0, isec);
691 void ARMV7PILongThunk::writeLong(uint8_t *buf) {
692 write32(buf + 0, 0xe30fcff0); // P: movw ip,:lower16:S - (P + (L1-P) + 8)
693 write32(buf + 4, 0xe340c000); // movt ip,:upper16:S - (P + (L1-P) + 8)
694 write32(buf + 8, 0xe08cc00f); // L1: add ip, ip, pc
695 write32(buf + 12, 0xe12fff1c); // bx ip
696 uint64_t s = getARMThunkDestVA(destination);
697 uint64_t p = getThunkTargetSym()->getVA();
698 int64_t offset = s - p - 16;
699 target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
700 target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
703 void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
704 addSymbol(saver().save("__ARMV7PILongThunk_" + destination.getName()),
705 STT_FUNC, 0, isec);
706 addSymbol("$a", STT_NOTYPE, 0, isec);
709 void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
710 write16(buf + 0, 0xf64f); // P: movw ip,:lower16:S - (P + (L1-P) + 4)
711 write16(buf + 2, 0x7cf4);
712 write16(buf + 4, 0xf2c0); // movt ip,:upper16:S - (P + (L1-P) + 4)
713 write16(buf + 6, 0x0c00);
714 write16(buf + 8, 0x44fc); // L1: add ip, pc
715 write16(buf + 10, 0x4760); // bx ip
716 uint64_t s = getARMThunkDestVA(destination);
717 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
718 int64_t offset = s - p - 12;
719 target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
720 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
723 void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
724 addSymbol(saver().save("__ThumbV7PILongThunk_" + destination.getName()),
725 STT_FUNC, 1, isec);
726 addSymbol("$t", STT_NOTYPE, 0, isec);
729 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
730 // Most Thumb instructions cannot access the high registers r8 - r15. As the
731 // only register we can corrupt is r12 we must instead spill a low register
732 // to the stack to use as a scratch register. We push r1 even though we
733 // don't need to get some space to use for the return address.
734 write16(buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers
735 write16(buf + 2, 0x4801); // ldr r0, [pc, #4] ; L1
736 write16(buf + 4, 0x9001); // str r0, [sp, #4] ; SP + 4 = S
737 write16(buf + 6, 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
738 write32(buf + 8, 0x00000000); // L1: .word S
739 uint64_t s = getARMThunkDestVA(destination);
740 target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
743 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
744 addSymbol(saver().save("__Thumbv6MABSLongThunk_" + destination.getName()),
745 STT_FUNC, 1, isec);
746 addSymbol("$t", STT_NOTYPE, 0, isec);
747 addSymbol("$d", STT_NOTYPE, 8, isec);
750 void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
751 // Most Thumb instructions cannot access the high registers r8 - r15. As the
752 // only register we can corrupt is ip (r12) we must instead spill a low
753 // register to the stack to use as a scratch register.
754 write16(buf + 0, 0xb401); // P: push {r0} ; Obtain scratch register
755 write16(buf + 2, 0x4802); // ldr r0, [pc, #8] ; L2
756 write16(buf + 4, 0x4684); // mov ip, r0 ; high to low register
757 write16(buf + 6, 0xbc01); // pop {r0} ; restore scratch register
758 write16(buf + 8, 0x44e7); // L1: add pc, ip ; transfer control
759 write16(buf + 10, 0x46c0); // nop ; pad to 4-byte boundary
760 write32(buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 4)
761 uint64_t s = getARMThunkDestVA(destination);
762 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
763 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
766 void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
767 addSymbol(saver().save("__Thumbv6MPILongThunk_" + destination.getName()),
768 STT_FUNC, 1, isec);
769 addSymbol("$t", STT_NOTYPE, 0, isec);
770 addSymbol("$d", STT_NOTYPE, 12, isec);
773 void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
774 write32(buf + 0, 0xe51ff004); // ldr pc, [pc,#-4] ; L1
775 write32(buf + 4, 0x00000000); // L1: .word S
776 target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
779 void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
780 addSymbol(saver().save("__ARMv5LongLdrPcThunk_" + destination.getName()),
781 STT_FUNC, 0, isec);
782 addSymbol("$a", STT_NOTYPE, 0, isec);
783 addSymbol("$d", STT_NOTYPE, 4, isec);
786 void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
787 write32(buf + 0, 0xe59fc000); // ldr r12, [pc] ; L1
788 write32(buf + 4, 0xe12fff1c); // bx r12
789 write32(buf + 8, 0x00000000); // L1: .word S
790 target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
793 void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
794 addSymbol(saver().save("__ARMv4ABSLongBXThunk_" + destination.getName()),
795 STT_FUNC, 0, isec);
796 addSymbol("$a", STT_NOTYPE, 0, isec);
797 addSymbol("$d", STT_NOTYPE, 8, isec);
800 void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
801 write16(buf + 0, 0x4778); // bx pc
802 write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
803 write32(buf + 4, 0xe51ff004); // ldr pc, [pc, #-4] ; L1
804 write32(buf + 8, 0x00000000); // L1: .word S
805 target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
808 void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
809 addSymbol(saver().save("__Thumbv4ABSLongBXThunk_" + destination.getName()),
810 STT_FUNC, 1, isec);
811 addSymbol("$t", STT_NOTYPE, 0, isec);
812 addSymbol("$a", STT_NOTYPE, 4, isec);
813 addSymbol("$d", STT_NOTYPE, 8, isec);
816 void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
817 write16(buf + 0, 0x4778); // bx pc
818 write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
819 write32(buf + 4, 0xe59fc000); // ldr r12, [pc] ; L1
820 write32(buf + 8, 0xe12fff1c); // bx r12
821 write32(buf + 12, 0x00000000); // L1: .word S
822 target->relocateNoSym(buf + 12, R_ARM_ABS32, getARMThunkDestVA(destination));
825 void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
826 addSymbol(saver().save("__Thumbv4ABSLongThunk_" + destination.getName()),
827 STT_FUNC, 1, isec);
828 addSymbol("$t", STT_NOTYPE, 0, isec);
829 addSymbol("$a", STT_NOTYPE, 4, isec);
830 addSymbol("$d", STT_NOTYPE, 12, isec);
833 void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
834 write32(buf + 0, 0xe59fc004); // P: ldr ip, [pc,#4] ; L2
835 write32(buf + 4, 0xe08fc00c); // L1: add ip, pc, ip
836 write32(buf + 8, 0xe12fff1c); // bx ip
837 write32(buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
838 uint64_t s = getARMThunkDestVA(destination);
839 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
840 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
843 void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
844 addSymbol(saver().save("__ARMv4PILongBXThunk_" + destination.getName()),
845 STT_FUNC, 0, isec);
846 addSymbol("$a", STT_NOTYPE, 0, isec);
847 addSymbol("$d", STT_NOTYPE, 12, isec);
850 void ARMV4PILongThunk::writeLong(uint8_t *buf) {
851 write32(buf + 0, 0xe59fc000); // P: ldr ip, [pc] ; L2
852 write32(buf + 4, 0xe08ff00c); // L1: add pc, pc, r12
853 write32(buf + 8, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
854 uint64_t s = getARMThunkDestVA(destination);
855 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
856 target->relocateNoSym(buf + 8, R_ARM_REL32, s - p - 12);
859 void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
860 addSymbol(saver().save("__ARMv4PILongThunk_" + destination.getName()),
861 STT_FUNC, 0, isec);
862 addSymbol("$a", STT_NOTYPE, 0, isec);
863 addSymbol("$d", STT_NOTYPE, 8, isec);
866 void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
867 write16(buf + 0, 0x4778); // P: bx pc
868 write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
869 write32(buf + 4, 0xe59fc000); // ldr r12, [pc] ; L2
870 write32(buf + 8, 0xe08cf00f); // L1: add pc, r12, pc
871 write32(buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
872 uint64_t s = getARMThunkDestVA(destination);
873 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
874 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 16);
877 void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
878 addSymbol(saver().save("__Thumbv4PILongBXThunk_" + destination.getName()),
879 STT_FUNC, 1, isec);
880 addSymbol("$t", STT_NOTYPE, 0, isec);
881 addSymbol("$a", STT_NOTYPE, 4, isec);
882 addSymbol("$d", STT_NOTYPE, 12, isec);
885 void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
886 write16(buf + 0, 0x4778); // P: bx pc
887 write16(buf + 2, 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
888 write32(buf + 4, 0xe59fc004); // ldr ip, [pc,#4] ; L2
889 write32(buf + 8, 0xe08fc00c); // L1: add ip, pc, ip
890 write32(buf + 12, 0xe12fff1c); // bx ip
891 write32(buf + 16, 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
892 uint64_t s = getARMThunkDestVA(destination);
893 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
894 target->relocateNoSym(buf + 16, R_ARM_REL32, s - p - 16);
897 void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
898 addSymbol(saver().save("__Thumbv4PILongThunk_" + destination.getName()),
899 STT_FUNC, 1, isec);
900 addSymbol("$t", STT_NOTYPE, 0, isec);
901 addSymbol("$a", STT_NOTYPE, 4, isec);
902 addSymbol("$d", STT_NOTYPE, 16, isec);
905 // Use the long jump which covers a range up to 8MiB.
906 void AVRThunk::writeTo(uint8_t *buf) {
907 write32(buf, 0x940c); // jmp func
908 target->relocateNoSym(buf, R_AVR_CALL, destination.getVA());
911 void AVRThunk::addSymbols(ThunkSection &isec) {
912 addSymbol(saver().save("__AVRThunk_" + destination.getName()), STT_FUNC, 0,
913 isec);
916 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
917 void MipsThunk::writeTo(uint8_t *buf) {
918 uint64_t s = destination.getVA();
919 write32(buf, 0x3c190000); // lui $25, %hi(func)
920 write32(buf + 4, 0x08000000 | (s >> 2)); // j func
921 write32(buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
922 write32(buf + 12, 0x00000000); // nop
923 target->relocateNoSym(buf, R_MIPS_HI16, s);
924 target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
927 void MipsThunk::addSymbols(ThunkSection &isec) {
928 addSymbol(saver().save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
929 isec);
932 InputSection *MipsThunk::getTargetInputSection() const {
933 auto &dr = cast<Defined>(destination);
934 return dyn_cast<InputSection>(dr.section);
937 // Write microMIPS R2-R5 LA25 thunk code
938 // to call PIC function from the non-PIC one.
939 void MicroMipsThunk::writeTo(uint8_t *buf) {
940 uint64_t s = destination.getVA();
941 write16(buf, 0x41b9); // lui $25, %hi(func)
942 write16(buf + 4, 0xd400); // j func
943 write16(buf + 8, 0x3339); // addiu $25, $25, %lo(func)
944 write16(buf + 12, 0x0c00); // nop
945 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
946 target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
947 target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
950 void MicroMipsThunk::addSymbols(ThunkSection &isec) {
951 Defined *d =
952 addSymbol(saver().save("__microLA25Thunk_" + destination.getName()),
953 STT_FUNC, 0, isec);
954 d->stOther |= STO_MIPS_MICROMIPS;
957 InputSection *MicroMipsThunk::getTargetInputSection() const {
958 auto &dr = cast<Defined>(destination);
959 return dyn_cast<InputSection>(dr.section);
962 // Write microMIPS R6 LA25 thunk code
963 // to call PIC function from the non-PIC one.
964 void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
965 uint64_t s = destination.getVA();
966 uint64_t p = getThunkTargetSym()->getVA();
967 write16(buf, 0x1320); // lui $25, %hi(func)
968 write16(buf + 4, 0x3339); // addiu $25, $25, %lo(func)
969 write16(buf + 8, 0x9400); // bc func
970 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
971 target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
972 target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
975 void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
976 Defined *d =
977 addSymbol(saver().save("__microLA25Thunk_" + destination.getName()),
978 STT_FUNC, 0, isec);
979 d->stOther |= STO_MIPS_MICROMIPS;
982 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
983 auto &dr = cast<Defined>(destination);
984 return dyn_cast<InputSection>(dr.section);
987 void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
988 const InputFile *file, int64_t addend) {
989 if (!config->isPic) {
990 write32(buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
991 write32(buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
992 write32(buf + 8, 0x7d6903a6); // mtctr r11
993 write32(buf + 12, 0x4e800420); // bctr
994 return;
996 uint32_t offset;
997 if (addend >= 0x8000) {
998 // The stub loads an address relative to r30 (.got2+Addend). Addend is
999 // almost always 0x8000. The address of .got2 is different in another object
1000 // file, so a stub cannot be shared.
1001 offset = gotPltVA -
1002 (in.ppc32Got2->getParent()->getVA() +
1003 (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
1004 } else {
1005 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
1006 // currently the address of .got).
1007 offset = gotPltVA - in.got->getVA();
1009 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
1010 if (ha == 0) {
1011 write32(buf + 0, 0x817e0000 | l); // lwz r11,l(r30)
1012 write32(buf + 4, 0x7d6903a6); // mtctr r11
1013 write32(buf + 8, 0x4e800420); // bctr
1014 write32(buf + 12, 0x60000000); // nop
1015 } else {
1016 write32(buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha
1017 write32(buf + 4, 0x816b0000 | l); // lwz r11,l(r11)
1018 write32(buf + 8, 0x7d6903a6); // mtctr r11
1019 write32(buf + 12, 0x4e800420); // bctr
1023 void PPC32PltCallStub::writeTo(uint8_t *buf) {
1024 writePPC32PltCallStub(buf, destination.getGotPltVA(), file, addend);
1027 void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
1028 std::string buf;
1029 raw_string_ostream os(buf);
1030 os << format_hex_no_prefix(addend, 8);
1031 if (!config->isPic)
1032 os << ".plt_call32.";
1033 else if (addend >= 0x8000)
1034 os << ".got2.plt_pic32.";
1035 else
1036 os << ".plt_pic32.";
1037 os << destination.getName();
1038 addSymbol(saver().save(os.str()), STT_FUNC, 0, isec);
1041 bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
1042 const Relocation &rel) const {
1043 return !config->isPic || (isec.file == file && rel.addend == addend);
1046 void PPC32LongThunk::addSymbols(ThunkSection &isec) {
1047 addSymbol(saver().save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
1048 isec);
1051 void PPC32LongThunk::writeTo(uint8_t *buf) {
1052 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
1053 auto lo = [](uint32_t v) -> uint16_t { return v; };
1054 uint32_t d = destination.getVA(addend);
1055 if (config->isPic) {
1056 uint32_t off = d - (getThunkTargetSym()->getVA() + 8);
1057 write32(buf + 0, 0x7c0802a6); // mflr r12,0
1058 write32(buf + 4, 0x429f0005); // bcl r20,r31,.+4
1059 write32(buf + 8, 0x7d8802a6); // mtctr r12
1060 write32(buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
1061 write32(buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
1062 write32(buf + 20, 0x7c0803a6); // mtlr r0
1063 buf += 24;
1064 } else {
1065 write32(buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
1066 write32(buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
1067 buf += 8;
1069 write32(buf + 0, 0x7d8903a6); // mtctr r12
1070 write32(buf + 4, 0x4e800420); // bctr
1073 void elf::writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
1074 uint16_t offHa = (offset + 0x8000) >> 16;
1075 uint16_t offLo = offset & 0xffff;
1077 write32(buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa
1078 write32(buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)
1079 write32(buf + 8, 0x7d8903a6); // mtctr r12
1080 write32(buf + 12, 0x4e800420); // bctr
1083 void PPC64PltCallStub::writeTo(uint8_t *buf) {
1084 int64_t offset = destination.getGotPltVA() - getPPC64TocBase();
1085 // Save the TOC pointer to the save-slot reserved in the call frame.
1086 write32(buf + 0, 0xf8410018); // std r2,24(r1)
1087 writePPC64LoadAndBranch(buf + 4, offset);
1090 void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
1091 Defined *s = addSymbol(saver().save("__plt_" + destination.getName()),
1092 STT_FUNC, 0, isec);
1093 s->needsTocRestore = true;
1094 s->file = destination.file;
1097 bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
1098 const Relocation &rel) const {
1099 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1102 void PPC64R2SaveStub::writeTo(uint8_t *buf) {
1103 const int64_t offset = computeOffset();
1104 write32(buf + 0, 0xf8410018); // std r2,24(r1)
1105 // The branch offset needs to fit in 26 bits.
1106 if (getMayUseShortThunk()) {
1107 write32(buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
1108 } else if (isInt<34>(offset)) {
1109 int nextInstOffset;
1110 uint64_t tocOffset = destination.getVA() - getPPC64TocBase();
1111 if (tocOffset >> 16 > 0) {
1112 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
1113 const uint64_t addis =
1114 ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
1115 write32(buf + 4, addis); // addis r12, r2 , top of offset
1116 write32(buf + 8, addi); // addi r12, r12, bottom of offset
1117 nextInstOffset = 12;
1118 } else {
1119 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
1120 write32(buf + 4, addi); // addi r12, r2, offset
1121 nextInstOffset = 8;
1123 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
1124 write32(buf + nextInstOffset + 4, BCTR); // bctr
1125 } else {
1126 in.ppc64LongBranchTarget->addEntry(&destination, addend);
1127 const int64_t offsetFromTOC =
1128 in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1129 getPPC64TocBase();
1130 writePPC64LoadAndBranch(buf + 4, offsetFromTOC);
1134 void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
1135 Defined *s = addSymbol(saver().save("__toc_save_" + destination.getName()),
1136 STT_FUNC, 0, isec);
1137 s->needsTocRestore = true;
1140 bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
1141 const Relocation &rel) const {
1142 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1145 void PPC64R12SetupStub::writeTo(uint8_t *buf) {
1146 int64_t offset = (gotPlt ? destination.getGotPltVA() : destination.getVA()) -
1147 getThunkTargetSym()->getVA();
1148 if (!isInt<34>(offset))
1149 reportRangeError(buf, offset, 34, destination, "R12 setup stub offset");
1151 int nextInstOffset;
1152 if (config->power10Stubs) {
1153 const uint64_t imm = (((offset >> 16) & 0x3ffff) << 32) | (offset & 0xffff);
1154 // pld 12, func@plt@pcrel or paddi r12, 0, func@pcrel
1155 writePrefixedInstruction(
1156 buf, (gotPlt ? PLD_R12_NO_DISP : PADDI_R12_NO_DISP) | imm);
1157 nextInstOffset = 8;
1158 } else {
1159 uint32_t off = offset - 8;
1160 write32(buf + 0, 0x7d8802a6); // mflr 12
1161 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
1162 write32(buf + 8, 0x7d6802a6); // mflr 11
1163 write32(buf + 12, 0x7d8803a6); // mtlr 12
1164 write32(buf + 16,
1165 0x3d8b0000 | ((off + 0x8000) >> 16)); // addis 12,11,off@ha
1166 if (gotPlt)
1167 write32(buf + 20, 0xe98c0000 | (off & 0xffff)); // ld 12, off@l(12)
1168 else
1169 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi 12,12,off@l
1170 nextInstOffset = 24;
1172 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
1173 write32(buf + nextInstOffset + 4, BCTR); // bctr
1176 void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
1177 addSymbol(saver().save((gotPlt ? "__plt_pcrel_" : "__gep_setup_") +
1178 destination.getName()),
1179 STT_FUNC, 0, isec);
1182 bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
1183 const Relocation &rel) const {
1184 return rel.type == R_PPC64_REL24_NOTOC;
1187 void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
1188 int64_t offset = in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1189 getPPC64TocBase();
1190 writePPC64LoadAndBranch(buf, offset);
1193 void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
1194 addSymbol(saver().save("__long_branch_" + destination.getName()), STT_FUNC, 0,
1195 isec);
1198 bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
1199 const Relocation &rel) const {
1200 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1203 Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {
1204 destination.thunkAccessed = true;
1207 Thunk::~Thunk() = default;
1209 static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
1210 if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
1211 type != R_AARCH64_PLT32)
1212 fatal("unrecognized relocation type");
1213 if (config->picThunk)
1214 return make<AArch64ADRPThunk>(s, a);
1215 return make<AArch64ABSLongThunk>(s, a);
1218 // Creates a thunk for long branches or Thumb-ARM interworking.
1219 // Arm Architectures v4t does not support Thumb2 technology, and does not
1220 // support BLX or LDR Arm/Thumb state switching. This means that
1221 // - MOVT and MOVW instructions cannot be used.
1222 // - We can't rewrite BL in place to BLX. We will need thunks.
1224 // TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
1225 // Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
1226 static Thunk *addThunkArmv4(RelType reloc, Symbol &s, int64_t a) {
1227 bool thumb_target = s.getVA(a) & 1;
1229 switch (reloc) {
1230 case R_ARM_PC24:
1231 case R_ARM_PLT32:
1232 case R_ARM_JUMP24:
1233 case R_ARM_CALL:
1234 if (config->picThunk) {
1235 if (thumb_target)
1236 return make<ARMV4PILongBXThunk>(s, a);
1237 return make<ARMV4PILongThunk>(s, a);
1239 if (thumb_target)
1240 return make<ARMV4ABSLongBXThunk>(s, a);
1241 return make<ARMV5LongLdrPcThunk>(s, a);
1242 case R_ARM_THM_CALL:
1243 if (config->picThunk) {
1244 if (thumb_target)
1245 return make<ThumbV4PILongThunk>(s, a);
1246 return make<ThumbV4PILongBXThunk>(s, a);
1248 if (thumb_target)
1249 return make<ThumbV4ABSLongThunk>(s, a);
1250 return make<ThumbV4ABSLongBXThunk>(s, a);
1252 fatal("relocation " + toString(reloc) + " to " + toString(s) +
1253 " not supported for Armv4 or Armv4T target");
1256 // Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
1257 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
1258 // - MOVT and MOVW instructions cannot be used
1259 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
1260 // be transformed into a BLX
1261 static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) {
1262 switch (reloc) {
1263 case R_ARM_PC24:
1264 case R_ARM_PLT32:
1265 case R_ARM_JUMP24:
1266 case R_ARM_CALL:
1267 case R_ARM_THM_CALL:
1268 if (config->picThunk)
1269 return make<ARMV4PILongBXThunk>(s, a);
1270 return make<ARMV5LongLdrPcThunk>(s, a);
1272 fatal("relocation " + toString(reloc) + " to " + toString(s) +
1273 " not supported for Armv5 or Armv6 targets");
1276 // Create a thunk for Thumb long branch on V6-M.
1277 // Arm Architecture v6-M only supports Thumb instructions. This means
1278 // - MOVT and MOVW instructions cannot be used.
1279 // - Only a limited number of instructions can access registers r8 and above
1280 // - No interworking support is needed (all Thumb).
1281 static Thunk *addThunkV6M(RelType reloc, Symbol &s, int64_t a) {
1282 switch (reloc) {
1283 case R_ARM_THM_JUMP19:
1284 case R_ARM_THM_JUMP24:
1285 case R_ARM_THM_CALL:
1286 if (config->isPic)
1287 return make<ThumbV6MPILongThunk>(s, a);
1288 return make<ThumbV6MABSLongThunk>(s, a);
1290 fatal("relocation " + toString(reloc) + " to " + toString(s) +
1291 " not supported for Armv6-M targets");
1294 // Creates a thunk for Thumb-ARM interworking or branch range extension.
1295 static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
1296 // Decide which Thunk is needed based on:
1297 // Available instruction set
1298 // - An Arm Thunk can only be used if Arm state is available.
1299 // - A Thumb Thunk can only be used if Thumb state is available.
1300 // - Can only use a Thunk if it uses instructions that the Target supports.
1301 // Relocation is branch or branch and link
1302 // - Branch instructions cannot change state, can only select Thunk that
1303 // starts in the same state as the caller.
1304 // - Branch and link relocations can change state, can select Thunks from
1305 // either Arm or Thumb.
1306 // Position independent Thunks if we require position independent code.
1308 // Handle architectures that have restrictions on the instructions that they
1309 // can use in Thunks. The flags below are set by reading the BuildAttributes
1310 // of the input objects. InputFiles.cpp contains the mapping from ARM
1311 // architecture to flag.
1312 if (!config->armHasMovtMovw) {
1313 if (config->armJ1J2BranchEncoding)
1314 return addThunkV6M(reloc, s, a);
1315 if (config->armHasBlx)
1316 return addThunkArmv5v6(reloc, s, a);
1317 return addThunkArmv4(reloc, s, a);
1320 switch (reloc) {
1321 case R_ARM_PC24:
1322 case R_ARM_PLT32:
1323 case R_ARM_JUMP24:
1324 case R_ARM_CALL:
1325 if (config->picThunk)
1326 return make<ARMV7PILongThunk>(s, a);
1327 return make<ARMV7ABSLongThunk>(s, a);
1328 case R_ARM_THM_JUMP19:
1329 case R_ARM_THM_JUMP24:
1330 case R_ARM_THM_CALL:
1331 if (config->picThunk)
1332 return make<ThumbV7PILongThunk>(s, a);
1333 return make<ThumbV7ABSLongThunk>(s, a);
1335 fatal("unrecognized relocation type");
1338 static Thunk *addThunkAVR(RelType type, Symbol &s, int64_t a) {
1339 switch (type) {
1340 case R_AVR_LO8_LDI_GS:
1341 case R_AVR_HI8_LDI_GS:
1342 return make<AVRThunk>(s, a);
1343 default:
1344 fatal("unrecognized relocation type " + toString(type));
1348 static Thunk *addThunkMips(RelType type, Symbol &s) {
1349 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6())
1350 return make<MicroMipsR6Thunk>(s);
1351 if (s.stOther & STO_MIPS_MICROMIPS)
1352 return make<MicroMipsThunk>(s);
1353 return make<MipsThunk>(s);
1356 static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
1357 Symbol &s) {
1358 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
1359 rel.type == R_PPC_PLTREL24) &&
1360 "unexpected relocation type for thunk");
1361 if (s.isInPlt())
1362 return make<PPC32PltCallStub>(isec, rel, s);
1363 return make<PPC32LongThunk>(s, rel.addend);
1366 static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
1367 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
1368 type == R_PPC64_REL24_NOTOC) &&
1369 "unexpected relocation type for thunk");
1370 if (s.isInPlt())
1371 return type == R_PPC64_REL24_NOTOC
1372 ? (Thunk *)make<PPC64R12SetupStub>(s, /*gotPlt=*/true)
1373 : (Thunk *)make<PPC64PltCallStub>(s);
1375 // This check looks at the st_other bits of the callee. If the value is 1
1376 // then the callee clobbers the TOC and we need an R2 save stub when RelType
1377 // is R_PPC64_REL14 or R_PPC64_REL24.
1378 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
1379 return make<PPC64R2SaveStub>(s, a);
1381 if (type == R_PPC64_REL24_NOTOC)
1382 return make<PPC64R12SetupStub>(s, /*gotPlt=*/false);
1384 if (config->picThunk)
1385 return make<PPC64PILongBranchThunk>(s, a);
1387 return make<PPC64PDLongBranchThunk>(s, a);
1390 Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
1391 Symbol &s = *rel.sym;
1392 int64_t a = rel.addend;
1394 switch (config->emachine) {
1395 case EM_AARCH64:
1396 return addThunkAArch64(rel.type, s, a);
1397 case EM_ARM:
1398 return addThunkArm(rel.type, s, a);
1399 case EM_AVR:
1400 return addThunkAVR(rel.type, s, a);
1401 case EM_MIPS:
1402 return addThunkMips(rel.type, s);
1403 case EM_PPC:
1404 return addThunkPPC32(isec, rel, s);
1405 case EM_PPC64:
1406 return addThunkPPC64(rel.type, s, a);
1407 default:
1408 llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");