1 //===- Thunks.cpp --------------------------------------------------------===//
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
7 //===---------------------------------------------------------------------===//
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 //===---------------------------------------------------------------------===//
25 #include "InputSection.h"
26 #include "OutputSections.h"
28 #include "SyntheticSections.h"
30 #include "lld/Common/ErrorHandler.h"
31 #include "lld/Common/Memory.h"
32 #include "llvm/BinaryFormat/ELF.h"
33 #include "llvm/Support/Casting.h"
34 #include "llvm/Support/Endian.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/MathExtras.h"
41 using namespace llvm::object;
42 using namespace llvm::ELF;
44 using namespace lld::elf;
48 // AArch64 long range Thunks
49 class AArch64ABSLongThunk final : public Thunk {
51 AArch64ABSLongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
52 uint32_t size() override { return 16; }
53 void writeTo(uint8_t *buf) override;
54 void addSymbols(ThunkSection &isec) override;
57 class AArch64ADRPThunk final : public Thunk {
59 AArch64ADRPThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
60 uint32_t size() override { return 12; }
61 void writeTo(uint8_t *buf) override;
62 void addSymbols(ThunkSection &isec) override;
65 // Base class for ARM thunks.
67 // An ARM thunk may be either short or long. A short thunk is simply a branch
68 // (B) instruction, and it may be used to call ARM functions when the distance
69 // from the thunk to the target is less than 32MB. Long thunks can branch to any
70 // virtual address and can switch between ARM and Thumb, and they are
71 // implemented in the derived classes. This class tries to create a short thunk
72 // if the target is in range, otherwise it creates a long thunk.
73 class ARMThunk : public Thunk {
75 ARMThunk(Symbol &dest) : Thunk(dest, 0) {}
77 bool getMayUseShortThunk();
78 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
79 void writeTo(uint8_t *buf) override;
80 bool isCompatibleWith(const InputSection &isec,
81 const Relocation &rel) const override;
83 // Returns the size of a long thunk.
84 virtual uint32_t sizeLong() = 0;
86 // Writes a long thunk to Buf.
87 virtual void writeLong(uint8_t *buf) = 0;
90 // This field tracks whether all previously considered layouts would allow
91 // this thunk to be short. If we have ever needed a long thunk, we always
92 // create a long thunk, even if the thunk may be short given the current
93 // distance to the target. We do this because transitioning from long to short
94 // can create layout oscillations in certain corner cases which would prevent
95 // the layout from converging.
96 bool mayUseShortThunk = true;
99 // Base class for Thumb-2 thunks.
101 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
102 // which has a range of 16MB.
103 class ThumbThunk : public Thunk {
105 ThumbThunk(Symbol &dest) : Thunk(dest, 0) { alignment = 2; }
107 bool getMayUseShortThunk();
108 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
109 void writeTo(uint8_t *buf) override;
110 bool isCompatibleWith(const InputSection &isec,
111 const Relocation &rel) const override;
113 // Returns the size of a long thunk.
114 virtual uint32_t sizeLong() = 0;
116 // Writes a long thunk to Buf.
117 virtual void writeLong(uint8_t *buf) = 0;
120 // See comment in ARMThunk above.
121 bool mayUseShortThunk = true;
124 // Specific ARM Thunk implementations. The naming convention is:
125 // Source State, TargetState, Target Requirement, ABS or PI, Range
126 class ARMV7ABSLongThunk final : public ARMThunk {
128 ARMV7ABSLongThunk(Symbol &dest) : ARMThunk(dest) {}
130 uint32_t sizeLong() override { return 12; }
131 void writeLong(uint8_t *buf) override;
132 void addSymbols(ThunkSection &isec) override;
135 class ARMV7PILongThunk final : public ARMThunk {
137 ARMV7PILongThunk(Symbol &dest) : ARMThunk(dest) {}
139 uint32_t sizeLong() override { return 16; }
140 void writeLong(uint8_t *buf) override;
141 void addSymbols(ThunkSection &isec) override;
144 class ThumbV7ABSLongThunk final : public ThumbThunk {
146 ThumbV7ABSLongThunk(Symbol &dest) : ThumbThunk(dest) {}
148 uint32_t sizeLong() override { return 10; }
149 void writeLong(uint8_t *buf) override;
150 void addSymbols(ThunkSection &isec) override;
153 class ThumbV7PILongThunk final : public ThumbThunk {
155 ThumbV7PILongThunk(Symbol &dest) : ThumbThunk(dest) {}
157 uint32_t sizeLong() override { return 12; }
158 void writeLong(uint8_t *buf) override;
159 void addSymbols(ThunkSection &isec) override;
162 // Implementations of Thunks for older Arm architectures that do not support
163 // the movt/movw instructions. These thunks require at least Architecture v5
164 // as used on processors such as the Arm926ej-s. There are no Thumb entry
165 // points as there is no Thumb branch instruction on these architecture that
166 // can result in a thunk
167 class ARMV5ABSLongThunk final : public ARMThunk {
169 ARMV5ABSLongThunk(Symbol &dest) : ARMThunk(dest) {}
171 uint32_t sizeLong() override { return 8; }
172 void writeLong(uint8_t *buf) override;
173 void addSymbols(ThunkSection &isec) override;
174 bool isCompatibleWith(const InputSection &isec,
175 const Relocation &rel) const override;
178 class ARMV5PILongThunk final : public ARMThunk {
180 ARMV5PILongThunk(Symbol &dest) : ARMThunk(dest) {}
182 uint32_t sizeLong() override { return 16; }
183 void writeLong(uint8_t *buf) override;
184 void addSymbols(ThunkSection &isec) override;
185 bool isCompatibleWith(const InputSection &isec,
186 const Relocation &rel) const override;
189 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
190 class ThumbV6MABSLongThunk final : public ThumbThunk {
192 ThumbV6MABSLongThunk(Symbol &dest) : ThumbThunk(dest) {}
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 {
201 ThumbV6MPILongThunk(Symbol &dest) : ThumbThunk(dest) {}
203 uint32_t sizeLong() override { return 16; }
204 void writeLong(uint8_t *buf) override;
205 void addSymbols(ThunkSection &isec) override;
209 class MipsThunk final : public Thunk {
211 MipsThunk(Symbol &dest) : Thunk(dest, 0) {}
213 uint32_t size() override { return 16; }
214 void writeTo(uint8_t *buf) override;
215 void addSymbols(ThunkSection &isec) override;
216 InputSection *getTargetInputSection() const override;
219 // microMIPS R2-R5 LA25 thunk
220 class MicroMipsThunk final : public Thunk {
222 MicroMipsThunk(Symbol &dest) : Thunk(dest, 0) {}
224 uint32_t size() override { return 14; }
225 void writeTo(uint8_t *buf) override;
226 void addSymbols(ThunkSection &isec) override;
227 InputSection *getTargetInputSection() const override;
230 // microMIPS R6 LA25 thunk
231 class MicroMipsR6Thunk final : public Thunk {
233 MicroMipsR6Thunk(Symbol &dest) : Thunk(dest, 0) {}
235 uint32_t size() override { return 12; }
236 void writeTo(uint8_t *buf) override;
237 void addSymbols(ThunkSection &isec) override;
238 InputSection *getTargetInputSection() const override;
241 class PPC32PltCallStub final : public Thunk {
243 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
244 // decide the offsets in the call stub.
245 PPC32PltCallStub(const InputSection &isec, const Relocation &rel,
247 : Thunk(dest, rel.addend), file(isec.file) {}
248 uint32_t size() override { return 16; }
249 void writeTo(uint8_t *buf) override;
250 void addSymbols(ThunkSection &isec) override;
251 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
254 // Records the call site of the call stub.
255 const InputFile *file;
258 class PPC32LongThunk final : public Thunk {
260 PPC32LongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
261 uint32_t size() override { return config->isPic ? 32 : 16; }
262 void writeTo(uint8_t *buf) override;
263 void addSymbols(ThunkSection &isec) override;
266 // PPC64 Plt call stubs.
267 // Any call site that needs to call through a plt entry needs a call stub in
268 // the .text section. The call stub is responsible for:
269 // 1) Saving the toc-pointer to the stack.
270 // 2) Loading the target functions address from the procedure linkage table into
271 // r12 for use by the target functions global entry point, and into the count
273 // 3) Transferring control to the target function through an indirect branch.
274 class PPC64PltCallStub final : public Thunk {
276 PPC64PltCallStub(Symbol &dest) : Thunk(dest, 0) {}
277 uint32_t size() override { return 20; }
278 void writeTo(uint8_t *buf) override;
279 void addSymbols(ThunkSection &isec) override;
282 // PPC64 R2 Save Stub
283 // When the caller requires a valid R2 TOC pointer but the callee does not
284 // require a TOC pointer and the callee cannot guarantee that it doesn't
285 // clobber R2 then we need to save R2. This stub:
286 // 1) Saves the TOC pointer to the stack.
287 // 2) Tail calls the callee.
288 class PPC64R2SaveStub final : public Thunk {
290 PPC64R2SaveStub(Symbol &dest) : Thunk(dest, 0) {}
291 uint32_t size() override { return 8; }
292 void writeTo(uint8_t *buf) override;
293 void addSymbols(ThunkSection &isec) override;
296 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
297 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
298 // larger then that we need to emit a long-branch thunk. The target address
299 // of the callee is stored in a table to be accessed TOC-relative. Since the
300 // call must be local (a non-local call will have a PltCallStub instead) the
301 // table stores the address of the callee's local entry point. For
302 // position-independent code a corresponding relative dynamic relocation is
304 class PPC64LongBranchThunk : public Thunk {
306 uint32_t size() override { return 16; }
307 void writeTo(uint8_t *buf) override;
308 void addSymbols(ThunkSection &isec) override;
311 PPC64LongBranchThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
314 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
316 PPC64PILongBranchThunk(Symbol &dest, int64_t addend)
317 : PPC64LongBranchThunk(dest, addend) {
318 assert(!dest.isPreemptible);
319 if (Optional<uint32_t> index =
320 in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
321 mainPart->relaDyn->addReloc(
322 {target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
324 addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)});
329 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
331 PPC64PDLongBranchThunk(Symbol &dest, int64_t addend)
332 : PPC64LongBranchThunk(dest, addend) {
333 in.ppc64LongBranchTarget->addEntry(&dest, addend);
337 } // end anonymous namespace
339 Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
340 InputSectionBase §ion) {
341 Defined *d = addSyntheticLocal(name, type, value, /*size=*/0, section);
346 void Thunk::setOffset(uint64_t newOffset) {
347 for (Defined *d : syms)
348 d->value = d->value - offset + newOffset;
352 // AArch64 long range Thunks
354 static uint64_t getAArch64ThunkDestVA(const Symbol &s, int64_t a) {
355 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA(a);
359 void AArch64ABSLongThunk::writeTo(uint8_t *buf) {
360 const uint8_t data[] = {
361 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
362 0x00, 0x02, 0x1f, 0xd6, // br x16
363 0x00, 0x00, 0x00, 0x00, // L0: .xword S
364 0x00, 0x00, 0x00, 0x00,
366 uint64_t s = getAArch64ThunkDestVA(destination, addend);
367 memcpy(buf, data, sizeof(data));
368 target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
371 void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
372 addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
374 addSymbol("$x", STT_NOTYPE, 0, isec);
375 addSymbol("$d", STT_NOTYPE, 8, isec);
378 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
379 // using the small code model, including pc-relative ones. At time of writing
380 // clang and gcc do not support the large code model for position independent
381 // code so it is safe to use this for position independent thunks without
382 // worrying about the destination being more than 4Gb away.
383 void AArch64ADRPThunk::writeTo(uint8_t *buf) {
384 const uint8_t data[] = {
385 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
386 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
387 0x00, 0x02, 0x1f, 0xd6, // br x16
389 uint64_t s = getAArch64ThunkDestVA(destination, addend);
390 uint64_t p = getThunkTargetSym()->getVA();
391 memcpy(buf, data, sizeof(data));
392 target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
393 getAArch64Page(s) - getAArch64Page(p));
394 target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
397 void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
398 addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
400 addSymbol("$x", STT_NOTYPE, 0, isec);
404 static uint64_t getARMThunkDestVA(const Symbol &s) {
405 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA();
406 return SignExtend64<32>(v);
409 // This function returns true if the target is not Thumb and is within 2^26, and
410 // it has not previously returned false (see comment for mayUseShortThunk).
411 bool ARMThunk::getMayUseShortThunk() {
412 if (!mayUseShortThunk)
414 uint64_t s = getARMThunkDestVA(destination);
416 mayUseShortThunk = false;
419 uint64_t p = getThunkTargetSym()->getVA();
420 int64_t offset = s - p - 8;
421 mayUseShortThunk = llvm::isInt<26>(offset);
422 return mayUseShortThunk;
425 void ARMThunk::writeTo(uint8_t *buf) {
426 if (!getMayUseShortThunk()) {
431 uint64_t s = getARMThunkDestVA(destination);
432 uint64_t p = getThunkTargetSym()->getVA();
433 int64_t offset = s - p - 8;
434 const uint8_t data[] = {
435 0x00, 0x00, 0x00, 0xea, // b S
437 memcpy(buf, data, sizeof(data));
438 target->relocateNoSym(buf, R_ARM_JUMP24, offset);
441 bool ARMThunk::isCompatibleWith(const InputSection &isec,
442 const Relocation &rel) const {
443 // Thumb branch relocations can't use BLX
444 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
447 // This function returns true if the target is Thumb and is within 2^25, and
448 // it has not previously returned false (see comment for mayUseShortThunk).
449 bool ThumbThunk::getMayUseShortThunk() {
450 if (!mayUseShortThunk)
452 uint64_t s = getARMThunkDestVA(destination);
454 mayUseShortThunk = false;
457 uint64_t p = getThunkTargetSym()->getVA() & ~1;
458 int64_t offset = s - p - 4;
459 mayUseShortThunk = llvm::isInt<25>(offset);
460 return mayUseShortThunk;
463 void ThumbThunk::writeTo(uint8_t *buf) {
464 if (!getMayUseShortThunk()) {
469 uint64_t s = getARMThunkDestVA(destination);
470 uint64_t p = getThunkTargetSym()->getVA();
471 int64_t offset = s - p - 4;
472 const uint8_t data[] = {
473 0x00, 0xf0, 0x00, 0xb0, // b.w S
475 memcpy(buf, data, sizeof(data));
476 target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
479 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
480 const Relocation &rel) const {
481 // ARM branch relocations can't use BLX
482 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
485 void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
486 const uint8_t data[] = {
487 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
488 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
489 0x1c, 0xff, 0x2f, 0xe1, // bx ip
491 uint64_t s = getARMThunkDestVA(destination);
492 memcpy(buf, data, sizeof(data));
493 target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
494 target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
497 void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
498 addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
500 addSymbol("$a", STT_NOTYPE, 0, isec);
503 void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
504 const uint8_t data[] = {
505 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
506 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
509 uint64_t s = getARMThunkDestVA(destination);
510 memcpy(buf, data, sizeof(data));
511 target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
512 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
515 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
516 addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
518 addSymbol("$t", STT_NOTYPE, 0, isec);
521 void ARMV7PILongThunk::writeLong(uint8_t *buf) {
522 const uint8_t data[] = {
523 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
524 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
525 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
526 0x1c, 0xff, 0x2f, 0xe1, // bx ip
528 uint64_t s = getARMThunkDestVA(destination);
529 uint64_t p = getThunkTargetSym()->getVA();
530 int64_t offset = s - p - 16;
531 memcpy(buf, data, sizeof(data));
532 target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
533 target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
536 void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
537 addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
539 addSymbol("$a", STT_NOTYPE, 0, isec);
542 void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
543 const uint8_t data[] = {
544 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
545 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
546 0xfc, 0x44, // L1: add ip, pc
549 uint64_t s = getARMThunkDestVA(destination);
550 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
551 int64_t offset = s - p - 12;
552 memcpy(buf, data, sizeof(data));
553 target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
554 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
557 void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
558 addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
560 addSymbol("$t", STT_NOTYPE, 0, isec);
563 void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
564 const uint8_t data[] = {
565 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
566 0x00, 0x00, 0x00, 0x00, // L1: .word S
568 memcpy(buf, data, sizeof(data));
569 target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
572 void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
573 addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
575 addSymbol("$a", STT_NOTYPE, 0, isec);
576 addSymbol("$d", STT_NOTYPE, 4, isec);
579 bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec,
580 const Relocation &rel) const {
581 // Thumb branch relocations can't use BLX
582 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
585 void ARMV5PILongThunk::writeLong(uint8_t *buf) {
586 const uint8_t data[] = {
587 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
588 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
589 0x1c, 0xff, 0x2f, 0xe1, // bx ip
590 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
592 uint64_t s = getARMThunkDestVA(destination);
593 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
594 memcpy(buf, data, sizeof(data));
595 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
598 void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
599 addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
601 addSymbol("$a", STT_NOTYPE, 0, isec);
602 addSymbol("$d", STT_NOTYPE, 12, isec);
605 bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec,
606 const Relocation &rel) const {
607 // Thumb branch relocations can't use BLX
608 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
611 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
612 // Most Thumb instructions cannot access the high registers r8 - r15. As the
613 // only register we can corrupt is r12 we must instead spill a low register
614 // to the stack to use as a scratch register. We push r1 even though we
615 // don't need to get some space to use for the return address.
616 const uint8_t data[] = {
617 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
618 0x01, 0x48, // ldr r0, [pc, #4] ; L1
619 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
620 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
621 0x00, 0x00, 0x00, 0x00 // L1: .word S
623 uint64_t s = getARMThunkDestVA(destination);
624 memcpy(buf, data, sizeof(data));
625 target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
628 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
629 addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
631 addSymbol("$t", STT_NOTYPE, 0, isec);
632 addSymbol("$d", STT_NOTYPE, 8, isec);
635 void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
636 // Most Thumb instructions cannot access the high registers r8 - r15. As the
637 // only register we can corrupt is ip (r12) we must instead spill a low
638 // register to the stack to use as a scratch register.
639 const uint8_t data[] = {
640 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
641 0x02, 0x48, // ldr r0, [pc, #8] ; L2
642 0x84, 0x46, // mov ip, r0 ; high to low register
643 0x01, 0xbc, // pop {r0} ; restore scratch register
644 0xe7, 0x44, // L1: add pc, ip ; transfer control
645 0xc0, 0x46, // nop ; pad to 4-byte boundary
646 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
648 uint64_t s = getARMThunkDestVA(destination);
649 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
650 memcpy(buf, data, sizeof(data));
651 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
654 void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
655 addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
657 addSymbol("$t", STT_NOTYPE, 0, isec);
658 addSymbol("$d", STT_NOTYPE, 12, isec);
661 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
662 void MipsThunk::writeTo(uint8_t *buf) {
663 uint64_t s = destination.getVA();
664 write32(buf, 0x3c190000); // lui $25, %hi(func)
665 write32(buf + 4, 0x08000000 | (s >> 2)); // j func
666 write32(buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
667 write32(buf + 12, 0x00000000); // nop
668 target->relocateNoSym(buf, R_MIPS_HI16, s);
669 target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
672 void MipsThunk::addSymbols(ThunkSection &isec) {
673 addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
677 InputSection *MipsThunk::getTargetInputSection() const {
678 auto &dr = cast<Defined>(destination);
679 return dyn_cast<InputSection>(dr.section);
682 // Write microMIPS R2-R5 LA25 thunk code
683 // to call PIC function from the non-PIC one.
684 void MicroMipsThunk::writeTo(uint8_t *buf) {
685 uint64_t s = destination.getVA();
686 write16(buf, 0x41b9); // lui $25, %hi(func)
687 write16(buf + 4, 0xd400); // j func
688 write16(buf + 8, 0x3339); // addiu $25, $25, %lo(func)
689 write16(buf + 12, 0x0c00); // nop
690 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
691 target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
692 target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
695 void MicroMipsThunk::addSymbols(ThunkSection &isec) {
696 Defined *d = addSymbol(
697 saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
698 d->stOther |= STO_MIPS_MICROMIPS;
701 InputSection *MicroMipsThunk::getTargetInputSection() const {
702 auto &dr = cast<Defined>(destination);
703 return dyn_cast<InputSection>(dr.section);
706 // Write microMIPS R6 LA25 thunk code
707 // to call PIC function from the non-PIC one.
708 void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
709 uint64_t s = destination.getVA();
710 uint64_t p = getThunkTargetSym()->getVA();
711 write16(buf, 0x1320); // lui $25, %hi(func)
712 write16(buf + 4, 0x3339); // addiu $25, $25, %lo(func)
713 write16(buf + 8, 0x9400); // bc func
714 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
715 target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
716 target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
719 void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
720 Defined *d = addSymbol(
721 saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
722 d->stOther |= STO_MIPS_MICROMIPS;
725 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
726 auto &dr = cast<Defined>(destination);
727 return dyn_cast<InputSection>(dr.section);
730 void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
731 const InputFile *file, int64_t addend) {
732 if (!config->isPic) {
733 write32(buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
734 write32(buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
735 write32(buf + 8, 0x7d6903a6); // mtctr r11
736 write32(buf + 12, 0x4e800420); // bctr
740 if (addend >= 0x8000) {
741 // The stub loads an address relative to r30 (.got2+Addend). Addend is
742 // almost always 0x8000. The address of .got2 is different in another object
743 // file, so a stub cannot be shared.
744 offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
745 file->ppc32Got2OutSecOff + addend);
747 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
748 // currently the address of .got).
749 offset = gotPltVA - in.got->getVA();
751 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
753 write32(buf + 0, 0x817e0000 | l); // lwz r11,l(r30)
754 write32(buf + 4, 0x7d6903a6); // mtctr r11
755 write32(buf + 8, 0x4e800420); // bctr
756 write32(buf + 12, 0x60000000); // nop
758 write32(buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha
759 write32(buf + 4, 0x816b0000 | l); // lwz r11,l(r11)
760 write32(buf + 8, 0x7d6903a6); // mtctr r11
761 write32(buf + 12, 0x4e800420); // bctr
765 void PPC32PltCallStub::writeTo(uint8_t *buf) {
766 writePPC32PltCallStub(buf, destination.getGotPltVA(), file, addend);
769 void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
771 raw_string_ostream os(buf);
772 os << format_hex_no_prefix(addend, 8);
774 os << ".plt_call32.";
775 else if (addend >= 0x8000)
776 os << ".got2.plt_pic32.";
779 os << destination.getName();
780 addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
783 bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
784 const Relocation &rel) const {
785 return !config->isPic || (isec.file == file && rel.addend == addend);
788 void PPC32LongThunk::addSymbols(ThunkSection &isec) {
789 addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
793 void PPC32LongThunk::writeTo(uint8_t *buf) {
794 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
795 auto lo = [](uint32_t v) -> uint16_t { return v; };
796 uint32_t d = destination.getVA(addend);
798 uint32_t off = d - (getThunkTargetSym()->getVA() + 8);
799 write32(buf + 0, 0x7c0802a6); // mflr r12,0
800 write32(buf + 4, 0x429f0005); // bcl r20,r31,.+4
801 write32(buf + 8, 0x7d8802a6); // mtctr r12
802 write32(buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
803 write32(buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
804 write32(buf + 20, 0x7c0803a6); // mtlr r0
807 write32(buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
808 write32(buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
811 write32(buf + 0, 0x7d8903a6); // mtctr r12
812 write32(buf + 4, 0x4e800420); // bctr
815 void elf::writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
816 uint16_t offHa = (offset + 0x8000) >> 16;
817 uint16_t offLo = offset & 0xffff;
819 write32(buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa
820 write32(buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)
821 write32(buf + 8, 0x7d8903a6); // mtctr r12
822 write32(buf + 12, 0x4e800420); // bctr
825 void PPC64PltCallStub::writeTo(uint8_t *buf) {
826 int64_t offset = destination.getGotPltVA() - getPPC64TocBase();
827 // Save the TOC pointer to the save-slot reserved in the call frame.
828 write32(buf + 0, 0xf8410018); // std r2,24(r1)
829 writePPC64LoadAndBranch(buf + 4, offset);
832 void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
833 Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
835 s->needsTocRestore = true;
836 s->file = destination.file;
839 void PPC64R2SaveStub::writeTo(uint8_t *buf) {
840 int64_t offset = destination.getVA() - (getThunkTargetSym()->getVA() + 4);
841 // The branch offset needs to fit in 26 bits.
842 if (!isInt<26>(offset))
843 fatal("R2 save stub branch offset is too large: " + Twine(offset));
844 write32(buf + 0, 0xf8410018); // std r2,24(r1)
845 write32(buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
848 void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
849 Defined *s = addSymbol(saver.save("__toc_save_" + destination.getName()),
851 s->needsTocRestore = true;
854 void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
855 int64_t offset = in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
857 writePPC64LoadAndBranch(buf, offset);
860 void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
861 addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
865 Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {}
867 Thunk::~Thunk() = default;
869 static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
870 if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
871 type != R_AARCH64_PLT32)
872 fatal("unrecognized relocation type");
873 if (config->picThunk)
874 return make<AArch64ADRPThunk>(s, a);
875 return make<AArch64ABSLongThunk>(s, a);
878 // Creates a thunk for Thumb-ARM interworking.
879 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means
880 // - MOVT and MOVW instructions cannot be used
881 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
882 // be transformed into a BLX
883 static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s) {
890 if (config->picThunk)
891 return make<ARMV5PILongThunk>(s);
892 return make<ARMV5ABSLongThunk>(s);
894 fatal("relocation " + toString(reloc) + " to " + toString(s) +
895 " not supported for Armv5 or Armv6 targets");
898 // Create a thunk for Thumb long branch on V6-M.
899 // Arm Architecture v6-M only supports Thumb instructions. This means
900 // - MOVT and MOVW instructions cannot be used.
901 // - Only a limited number of instructions can access registers r8 and above
902 // - No interworking support is needed (all Thumb).
903 static Thunk *addThunkV6M(RelType reloc, Symbol &s) {
905 case R_ARM_THM_JUMP19:
906 case R_ARM_THM_JUMP24:
909 return make<ThumbV6MPILongThunk>(s);
910 return make<ThumbV6MABSLongThunk>(s);
912 fatal("relocation " + toString(reloc) + " to " + toString(s) +
913 " not supported for Armv6-M targets");
916 // Creates a thunk for Thumb-ARM interworking or branch range extension.
917 static Thunk *addThunkArm(RelType reloc, Symbol &s) {
918 // Decide which Thunk is needed based on:
919 // Available instruction set
920 // - An Arm Thunk can only be used if Arm state is available.
921 // - A Thumb Thunk can only be used if Thumb state is available.
922 // - Can only use a Thunk if it uses instructions that the Target supports.
923 // Relocation is branch or branch and link
924 // - Branch instructions cannot change state, can only select Thunk that
925 // starts in the same state as the caller.
926 // - Branch and link relocations can change state, can select Thunks from
927 // either Arm or Thumb.
928 // Position independent Thunks if we require position independent code.
930 // Handle architectures that have restrictions on the instructions that they
931 // can use in Thunks. The flags below are set by reading the BuildAttributes
932 // of the input objects. InputFiles.cpp contains the mapping from ARM
933 // architecture to flag.
934 if (!config->armHasMovtMovw) {
935 if (!config->armJ1J2BranchEncoding)
936 return addThunkPreArmv7(reloc, s);
937 return addThunkV6M(reloc, s);
945 if (config->picThunk)
946 return make<ARMV7PILongThunk>(s);
947 return make<ARMV7ABSLongThunk>(s);
948 case R_ARM_THM_JUMP19:
949 case R_ARM_THM_JUMP24:
951 if (config->picThunk)
952 return make<ThumbV7PILongThunk>(s);
953 return make<ThumbV7ABSLongThunk>(s);
955 fatal("unrecognized relocation type");
958 static Thunk *addThunkMips(RelType type, Symbol &s) {
959 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6())
960 return make<MicroMipsR6Thunk>(s);
961 if (s.stOther & STO_MIPS_MICROMIPS)
962 return make<MicroMipsThunk>(s);
963 return make<MipsThunk>(s);
966 static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
968 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
969 rel.type == R_PPC_PLTREL24) &&
970 "unexpected relocation type for thunk");
972 return make<PPC32PltCallStub>(isec, rel, s);
973 return make<PPC32LongThunk>(s, rel.addend);
976 static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
977 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24) &&
978 "unexpected relocation type for thunk");
980 return make<PPC64PltCallStub>(s);
982 // This check looks at the st_other bits of the callee. If the value is 1
983 // then the callee clobbers the TOC and we need an R2 save stub.
984 if ((s.stOther >> 5) == 1)
985 return make<PPC64R2SaveStub>(s);
987 if (config->picThunk)
988 return make<PPC64PILongBranchThunk>(s, a);
990 return make<PPC64PDLongBranchThunk>(s, a);
993 Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
994 Symbol &s = *rel.sym;
995 int64_t a = rel.addend;
997 if (config->emachine == EM_AARCH64)
998 return addThunkAArch64(rel.type, s, a);
1000 if (config->emachine == EM_ARM)
1001 return addThunkArm(rel.type, s);
1003 if (config->emachine == EM_MIPS)
1004 return addThunkMips(rel.type, s);
1006 if (config->emachine == EM_PPC)
1007 return addThunkPPC32(isec, rel, s);
1009 if (config->emachine == EM_PPC64)
1010 return addThunkPPC64(rel.type, s, a);
1012 llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");