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 "InputFiles.h"
26 #include "InputSection.h"
27 #include "OutputSections.h"
29 #include "SyntheticSections.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"
40 using namespace llvm::object
;
41 using namespace llvm::ELF
;
43 using namespace lld::elf
;
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
{
57 AArch64Thunk(Symbol
&dest
, int64_t addend
) : Thunk(dest
, addend
) {}
58 bool getMayUseShortThunk();
59 void writeTo(uint8_t *buf
) override
;
62 bool mayUseShortThunk
= true;
63 virtual void writeLong(uint8_t *buf
) = 0;
66 // AArch64 long range Thunks.
67 class AArch64ABSLongThunk final
: public AArch64Thunk
{
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
;
75 void writeLong(uint8_t *buf
) override
;
78 class AArch64ADRPThunk final
: public AArch64Thunk
{
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
;
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
{
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;
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
{
128 ThumbThunk(Symbol
&dest
, int64_t addend
) : Thunk(dest
, addend
) {
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;
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
;
306 class MipsThunk final
: public Thunk
{
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
{
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
{
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
{
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
,
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
;
351 // Records the call site of the call stub.
352 const InputFile
*file
;
355 class PPC32LongThunk final
: public Thunk
{
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
370 // 3) Transferring control to the target function through an indirect branch.
371 class PPC64PltCallStub final
: public Thunk
{
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
{
389 PPC64R2SaveStub(Symbol
&dest
, int64_t addend
) : Thunk(dest
, addend
) {
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
)
398 if (!isInt
<26>(computeOffset())) {
399 mayUseShortThunk
= false;
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
;
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
{
426 PPC64R12SetupStub(Symbol
&dest
, bool gotPlt
)
427 : Thunk(dest
, 0), gotPlt(gotPlt
) {
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
;
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
448 class PPC64LongBranchThunk
: public Thunk
{
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
;
457 PPC64LongBranchThunk(Symbol
&dest
, int64_t addend
) : Thunk(dest
, addend
) {}
460 class PPC64PILongBranchThunk final
: public PPC64LongBranchThunk
{
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
{
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
§ion
) {
487 Defined
*d
= addSyntheticLocal(name
, type
, value
, /*size=*/0, section
);
492 void Thunk::setOffset(uint64_t newOffset
) {
493 for (Defined
*d
: syms
)
494 d
->value
= d
->value
- 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
);
504 bool AArch64Thunk::getMayUseShortThunk() {
505 if (!mayUseShortThunk
)
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()) {
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()),
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()),
567 addSymbol("$x", STT_NOTYPE
, 0, isec
);
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
)
581 uint64_t s
= getARMThunkDestVA(destination
);
583 mayUseShortThunk
= 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()) {
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
)
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
)
624 uint64_t s
= getARMThunkDestVA(destination
);
626 mayUseShortThunk
= 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()) {
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
)
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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()),
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,
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,
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
) {
952 addSymbol(saver().save("__microLA25Thunk_" + destination
.getName()),
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
) {
977 addSymbol(saver().save("__microLA25Thunk_" + destination
.getName()),
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
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.
1002 (in
.ppc32Got2
->getParent()->getVA() +
1003 (file
->ppc32Got2
? file
->ppc32Got2
->outSecOff
: 0) + addend
);
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
;
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
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
) {
1029 raw_string_ostream
os(buf
);
1030 os
<< format_hex_no_prefix(addend
, 8);
1032 os
<< ".plt_call32.";
1033 else if (addend
>= 0x8000)
1034 os
<< ".got2.plt_pic32.";
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,
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
1065 write32(buf
+ 0, 0x3d800000 | ha(d
)); // lis r12,d@ha
1066 write32(buf
+ 4, 0x398c0000 | lo(d
)); // addi r12,r12,d@l
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()),
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
)) {
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;
1119 const uint64_t addi
= ADDI_R12_TO_R2_NO_DISP
| (tocOffset
& 0xffff);
1120 write32(buf
+ 4, addi
); // addi r12, r2, offset
1123 write32(buf
+ nextInstOffset
, MTCTR_R12
); // mtctr r12
1124 write32(buf
+ nextInstOffset
+ 4, BCTR
); // bctr
1126 in
.ppc64LongBranchTarget
->addEntry(&destination
, addend
);
1127 const int64_t offsetFromTOC
=
1128 in
.ppc64LongBranchTarget
->getEntryVA(&destination
, addend
) -
1130 writePPC64LoadAndBranch(buf
+ 4, offsetFromTOC
);
1134 void PPC64R2SaveStub::addSymbols(ThunkSection
&isec
) {
1135 Defined
*s
= addSymbol(saver().save("__toc_save_" + destination
.getName()),
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");
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
);
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
1165 0x3d8b0000 | ((off
+ 0x8000) >> 16)); // addis 12,11,off@ha
1167 write32(buf
+ 20, 0xe98c0000 | (off
& 0xffff)); // ld 12, off@l(12)
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()),
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
) -
1190 writePPC64LoadAndBranch(buf
, offset
);
1193 void PPC64LongBranchThunk::addSymbols(ThunkSection
&isec
) {
1194 addSymbol(saver().save("__long_branch_" + destination
.getName()), STT_FUNC
, 0,
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;
1234 if (config
->picThunk
) {
1236 return make
<ARMV4PILongBXThunk
>(s
, a
);
1237 return make
<ARMV4PILongThunk
>(s
, a
);
1240 return make
<ARMV4ABSLongBXThunk
>(s
, a
);
1241 return make
<ARMV5LongLdrPcThunk
>(s
, a
);
1242 case R_ARM_THM_CALL
:
1243 if (config
->picThunk
) {
1245 return make
<ThumbV4PILongThunk
>(s
, a
);
1246 return make
<ThumbV4PILongBXThunk
>(s
, a
);
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
) {
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
) {
1283 case R_ARM_THM_JUMP19
:
1284 case R_ARM_THM_JUMP24
:
1285 case R_ARM_THM_CALL
:
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
);
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
) {
1340 case R_AVR_LO8_LDI_GS
:
1341 case R_AVR_HI8_LDI_GS
:
1342 return make
<AVRThunk
>(s
, a
);
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
,
1358 assert((rel
.type
== R_PPC_LOCAL24PC
|| rel
.type
== R_PPC_REL24
||
1359 rel
.type
== R_PPC_PLTREL24
) &&
1360 "unexpected relocation type for thunk");
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");
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
) {
1396 return addThunkAArch64(rel
.type
, s
, a
);
1398 return addThunkArm(rel
.type
, s
, a
);
1400 return addThunkAVR(rel
.type
, s
, a
);
1402 return addThunkMips(rel
.type
, s
);
1404 return addThunkPPC32(isec
, rel
, s
);
1406 return addThunkPPC64(rel
.type
, s
, a
);
1408 llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");