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.
10//
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.
14//
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.
18//
19// i386 and x86-64 don't need thunks.
20//
21//===---------------------------------------------------------------------===//
22
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>
38
39using namespace llvm;
40using namespace llvm::object;
41using namespace llvm::ELF;
42using namespace lld;
43using namespace lld::elf;
44
45namespace {
46
47// Base class for AArch64 thunks.
48//
49// An AArch64 thunk may be either short or long. A short thunk is simply a
50// branch (B) instruction, and it may be used to call AArch64 functions when the
51// distance from the thunk to the target is less than 128MB. Long thunks can
52// branch to any virtual address and they are implemented in the derived
53// classes. This class tries to create a short thunk if the target is in range,
54// otherwise it creates a long thunk. When BTI is enabled indirect branches
55// must land on a BTI instruction. If the destination does not have a BTI
56// instruction mayNeedLandingPad is set to true and Thunk::landingPad points
57// to an alternative entry point with a BTI.
58class AArch64Thunk : public Thunk {
59public:
60 AArch64Thunk(Ctx &ctx, Symbol &dest, int64_t addend, bool mayNeedLandingPad)
61 : Thunk(ctx, dest, addend), mayNeedLandingPad(mayNeedLandingPad) {}
62 bool getMayUseShortThunk();
63 void writeTo(uint8_t *buf) override;
64 bool needsSyntheticLandingPad() override;
65
66protected:
67 bool mayNeedLandingPad;
68
69private:
70 bool mayUseShortThunk = true;
71 virtual void writeLong(uint8_t *buf) = 0;
72 // A thunk may be written out as a short or long, and we may not know which
73 // type at thunk creation time. In some thunk implementations the long thunk
74 // has additional mapping symbols. Thus function can be overridden to add
75 // these additional mapping symbols.
76 virtual void addLongMapSyms() {}
77};
78
79// AArch64 long range Thunks.
80class AArch64ABSLongThunk final : public AArch64Thunk {
81public:
82 AArch64ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,
83 bool mayNeedLandingPad)
84 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
85 uint32_t size() override { return getMayUseShortThunk() ? 4 : 16; }
86 void addSymbols(ThunkSection &isec) override;
87
88private:
89 void writeLong(uint8_t *buf) override;
90 void addLongMapSyms() override;
91 ThunkSection *tsec = nullptr;
92};
93
94// AArch64 long range Thunks compatible with execute-only code.
95class AArch64ABSXOLongThunk final : public AArch64Thunk {
96public:
97 AArch64ABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,
98 bool mayNeedLandingPad)
99 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
100 uint32_t size() override { return getMayUseShortThunk() ? 4 : 20; }
101 void addSymbols(ThunkSection &sec) override;
102
103private:
104 void writeLong(uint8_t *buf) override;
105};
106
107class AArch64ADRPThunk final : public AArch64Thunk {
108public:
109 AArch64ADRPThunk(Ctx &ctx, Symbol &dest, int64_t addend,
110 bool mayNeedLandingPad)
111 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
112 uint32_t size() override { return getMayUseShortThunk() ? 4 : 12; }
113 void addSymbols(ThunkSection &isec) override;
114
115private:
116 void writeLong(uint8_t *buf) override;
117};
118
119// AArch64 BTI Landing Pad
120// When BTI is enabled indirect branches must land on a BTI
121// compatible instruction. When the destination does not have a
122// BTI compatible instruction a Thunk doing an indirect branch
123// targets a Landing Pad Thunk that direct branches to the target.
124class AArch64BTILandingPadThunk final : public Thunk {
125public:
126 AArch64BTILandingPadThunk(Ctx &ctx, Symbol &dest, int64_t addend)
127 : Thunk(ctx, dest, addend) {}
128
129 uint32_t size() override { return getMayUseShortThunk() ? 4 : 8; }
130 void addSymbols(ThunkSection &isec) override;
131 void writeTo(uint8_t *buf) override;
132
133private:
134 bool getMayUseShortThunk();
135 void writeLong(uint8_t *buf);
136 bool mayUseShortThunk = true;
137};
138
139// Base class for ARM thunks.
140//
141// An ARM thunk may be either short or long. A short thunk is simply a branch
142// (B) instruction, and it may be used to call ARM functions when the distance
143// from the thunk to the target is less than 32MB. Long thunks can branch to any
144// virtual address and can switch between ARM and Thumb, and they are
145// implemented in the derived classes. This class tries to create a short thunk
146// if the target is in range, otherwise it creates a long thunk.
147class ARMThunk : public Thunk {
148public:
149 ARMThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}
150
151 bool getMayUseShortThunk();
152 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
153 void writeTo(uint8_t *buf) override;
154 bool isCompatibleWith(const InputSection &isec,
155 const Relocation &rel) const override;
156
157 // Returns the size of a long thunk.
158 virtual uint32_t sizeLong() = 0;
159
160 // Writes a long thunk to Buf.
161 virtual void writeLong(uint8_t *buf) = 0;
162
163private:
164 // This field tracks whether all previously considered layouts would allow
165 // this thunk to be short. If we have ever needed a long thunk, we always
166 // create a long thunk, even if the thunk may be short given the current
167 // distance to the target. We do this because transitioning from long to short
168 // can create layout oscillations in certain corner cases which would prevent
169 // the layout from converging.
170 bool mayUseShortThunk = true;
171 // See comment in AArch64Thunk.
172 virtual void addLongMapSyms() {}
173};
174
175// Base class for Thumb-2 thunks.
176//
177// This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
178// which has a range of 16MB.
179class ThumbThunk : public Thunk {
180public:
181 ThumbThunk(Ctx &ctx, Symbol &dest, int64_t addend)
182 : Thunk(ctx, dest, addend) {
183 alignment = 2;
184 }
185
186 bool getMayUseShortThunk();
187 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
188 void writeTo(uint8_t *buf) override;
189 bool isCompatibleWith(const InputSection &isec,
190 const Relocation &rel) const override;
191
192 // Returns the size of a long thunk.
193 virtual uint32_t sizeLong() = 0;
194
195 // Writes a long thunk to Buf.
196 virtual void writeLong(uint8_t *buf) = 0;
197
198private:
199 // See comment in ARMThunk above.
200 bool mayUseShortThunk = true;
201 // See comment in AArch64Thunk.
202 virtual void addLongMapSyms() {}
203};
204
205// Specific ARM Thunk implementations. The naming convention is:
206// Source State, TargetState, Target Requirement, ABS or PI, Range
207class ARMV7ABSLongThunk final : public ARMThunk {
208public:
209 ARMV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
210 : ARMThunk(ctx, dest, addend) {}
211
212 uint32_t sizeLong() override { return 12; }
213 void writeLong(uint8_t *buf) override;
214 void addSymbols(ThunkSection &isec) override;
215};
216
217class ARMV7PILongThunk final : public ARMThunk {
218public:
219 ARMV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
220 : ARMThunk(ctx, dest, addend) {}
221
222 uint32_t sizeLong() override { return 16; }
223 void writeLong(uint8_t *buf) override;
224 void addSymbols(ThunkSection &isec) override;
225};
226
227class ThumbV7ABSLongThunk final : public ThumbThunk {
228public:
229 ThumbV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
230 : ThumbThunk(ctx, dest, addend) {}
231
232 uint32_t sizeLong() override { return 10; }
233 void writeLong(uint8_t *buf) override;
234 void addSymbols(ThunkSection &isec) override;
235};
236
237class ThumbV7PILongThunk final : public ThumbThunk {
238public:
239 ThumbV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
240 : ThumbThunk(ctx, dest, addend) {}
241
242 uint32_t sizeLong() override { return 12; }
243 void writeLong(uint8_t *buf) override;
244 void addSymbols(ThunkSection &isec) override;
245};
246
247// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
248class ThumbV6MABSLongThunk final : public ThumbThunk {
249public:
250 ThumbV6MABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
251 : ThumbThunk(ctx, dest, addend) {}
252
253 uint32_t sizeLong() override { return 12; }
254 void writeLong(uint8_t *buf) override;
255 void addSymbols(ThunkSection &isec) override;
256
257private:
258 void addLongMapSyms() override;
259 ThunkSection *tsec = nullptr;
260};
261
262class ThumbV6MABSXOLongThunk final : public ThumbThunk {
263public:
264 ThumbV6MABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
265 : ThumbThunk(ctx, dest, addend) {}
266
267 uint32_t sizeLong() override { return 20; }
268 void writeLong(uint8_t *buf) override;
269 void addSymbols(ThunkSection &isec) override;
270};
271
272class ThumbV6MPILongThunk final : public ThumbThunk {
273public:
274 ThumbV6MPILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
275 : ThumbThunk(ctx, dest, addend) {}
276
277 uint32_t sizeLong() override { return 16; }
278 void writeLong(uint8_t *buf) override;
279 void addSymbols(ThunkSection &isec) override;
280
281private:
282 void addLongMapSyms() override;
283 ThunkSection *tsec = nullptr;
284};
285
286// Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
287// v6 support BLX to which BL instructions can be rewritten inline. There are no
288// Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on
289// these architecture that can result in a thunk.
290
291// LDR on v5 and v6 can switch processor state, so for v5 and v6,
292// ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4
293// can also use this thunk, but only for Arm->Arm calls.
294class ARMV5LongLdrPcThunk final : public ARMThunk {
295public:
296 ARMV5LongLdrPcThunk(Ctx &ctx, Symbol &dest, int64_t addend)
297 : ARMThunk(ctx, dest, addend) {}
298
299 uint32_t sizeLong() override { return 8; }
300 void writeLong(uint8_t *buf) override;
301 void addSymbols(ThunkSection &isec) override;
302
303private:
304 void addLongMapSyms() override;
305 ThunkSection *tsec = nullptr;
306};
307
308// Implementations of Thunks for v4. BLX is not supported, and loads
309// will not invoke Arm/Thumb state changes.
310class ARMV4PILongBXThunk final : public ARMThunk {
311public:
312 ARMV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
313 : ARMThunk(ctx, dest, addend) {}
314
315 uint32_t sizeLong() override { return 16; }
316 void writeLong(uint8_t *buf) override;
317 void addSymbols(ThunkSection &isec) override;
318
319private:
320 void addLongMapSyms() override;
321 ThunkSection *tsec = nullptr;
322};
323
324class ARMV4PILongThunk final : public ARMThunk {
325public:
326 ARMV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
327 : ARMThunk(ctx, dest, addend) {}
328
329 uint32_t sizeLong() override { return 12; }
330 void writeLong(uint8_t *buf) override;
331 void addSymbols(ThunkSection &isec) override;
332
333private:
334 void addLongMapSyms() override;
335 ThunkSection *tsec = nullptr;
336};
337
338class ThumbV4PILongBXThunk final : public ThumbThunk {
339public:
340 ThumbV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
341 : ThumbThunk(ctx, dest, addend) {}
342
343 uint32_t sizeLong() override { return 16; }
344 void writeLong(uint8_t *buf) override;
345 void addSymbols(ThunkSection &isec) override;
346
347private:
348 void addLongMapSyms() override;
349 ThunkSection *tsec = nullptr;
350};
351
352class ThumbV4PILongThunk final : public ThumbThunk {
353public:
354 ThumbV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
355 : ThumbThunk(ctx, dest, addend) {}
356
357 uint32_t sizeLong() override { return 20; }
358 void writeLong(uint8_t *buf) override;
359 void addSymbols(ThunkSection &isec) override;
360
361private:
362 void addLongMapSyms() override;
363 ThunkSection *tsec = nullptr;
364};
365
366class ARMV4ABSLongBXThunk final : public ARMThunk {
367public:
368 ARMV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
369 : ARMThunk(ctx, dest, addend) {}
370
371 uint32_t sizeLong() override { return 12; }
372 void writeLong(uint8_t *buf) override;
373 void addSymbols(ThunkSection &isec) override;
374
375private:
376 void addLongMapSyms() override;
377 ThunkSection *tsec = nullptr;
378};
379
380class ThumbV4ABSLongBXThunk final : public ThumbThunk {
381public:
382 ThumbV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)
383 : ThumbThunk(ctx, dest, addend) {}
384
385 uint32_t sizeLong() override { return 12; }
386 void writeLong(uint8_t *buf) override;
387 void addSymbols(ThunkSection &isec) override;
388
389private:
390 void addLongMapSyms() override;
391 ThunkSection *tsec = nullptr;
392};
393
394class ThumbV4ABSLongThunk final : public ThumbThunk {
395public:
396 ThumbV4ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
397 : ThumbThunk(ctx, dest, addend) {}
398
399 uint32_t sizeLong() override { return 16; }
400 void writeLong(uint8_t *buf) override;
401 void addSymbols(ThunkSection &isec) override;
402
403private:
404 void addLongMapSyms() override;
405 ThunkSection *tsec = nullptr;
406};
407
408// The AVR devices need thunks for R_AVR_LO8_LDI_GS/R_AVR_HI8_LDI_GS
409// when their destination is out of range [0, 0x1ffff].
410class AVRThunk : public Thunk {
411public:
412 AVRThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}
413 uint32_t size() override { return 4; }
414 void writeTo(uint8_t *buf) override;
415 void addSymbols(ThunkSection &isec) override;
416};
417
418// Hexagon CPUs need thunks for R_HEX_B{9,1{3,5},22}_PCREL,
419// R_HEX_{,GD_}PLT_B22_PCREL when their destination is out of
420// range.
421class HexagonThunk : public Thunk {
422public:
423 HexagonThunk(Ctx &ctx, const InputSection &isec, Relocation &rel,
424 Symbol &dest)
425 : Thunk(ctx, dest, 0), relOffset(rel.offset) {
426 alignment = 4;
427 }
428 uint32_t relOffset;
429 uint32_t size() override { return ctx.arg.isPic ? 12 : 8; }
430 void writeTo(uint8_t *buf) override;
431 void addSymbols(ThunkSection &isec) override;
432};
433
434// MIPS LA25 thunk
435class MipsThunk final : public Thunk {
436public:
437 MipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
438
439 uint32_t size() override { return 16; }
440 void writeTo(uint8_t *buf) override;
441 void addSymbols(ThunkSection &isec) override;
442 InputSection *getTargetInputSection() const override;
443};
444
445// microMIPS R2-R5 LA25 thunk
446class MicroMipsThunk final : public Thunk {
447public:
448 MicroMipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
449
450 uint32_t size() override { return 14; }
451 void writeTo(uint8_t *buf) override;
452 void addSymbols(ThunkSection &isec) override;
453 InputSection *getTargetInputSection() const override;
454};
455
456// microMIPS R6 LA25 thunk
457class MicroMipsR6Thunk final : public Thunk {
458public:
459 MicroMipsR6Thunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
460
461 uint32_t size() override { return 12; }
462 void writeTo(uint8_t *buf) override;
463 void addSymbols(ThunkSection &isec) override;
464 InputSection *getTargetInputSection() const override;
465};
466
467class PPC32PltCallStub final : public Thunk {
468public:
469 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
470 // decide the offsets in the call stub.
471 PPC32PltCallStub(Ctx &ctx, const InputSection &isec, const Relocation &rel,
472 Symbol &dest)
473 : Thunk(ctx, dest, rel.addend), file(isec.file) {}
474 uint32_t size() override { return 16; }
475 void writeTo(uint8_t *buf) override;
476 void addSymbols(ThunkSection &isec) override;
477 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
478
479private:
480 // Records the call site of the call stub.
481 const InputFile *file;
482};
483
484class PPC32LongThunk final : public Thunk {
485public:
486 PPC32LongThunk(Ctx &ctx, Symbol &dest, int64_t addend)
487 : Thunk(ctx, dest, addend) {}
488 uint32_t size() override { return ctx.arg.isPic ? 32 : 16; }
489 void writeTo(uint8_t *buf) override;
490 void addSymbols(ThunkSection &isec) override;
491};
492
493// PPC64 Plt call stubs.
494// Any call site that needs to call through a plt entry needs a call stub in
495// the .text section. The call stub is responsible for:
496// 1) Saving the toc-pointer to the stack.
497// 2) Loading the target functions address from the procedure linkage table into
498// r12 for use by the target functions global entry point, and into the count
499// register.
500// 3) Transferring control to the target function through an indirect branch.
501class PPC64PltCallStub final : public Thunk {
502public:
503 PPC64PltCallStub(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}
504 uint32_t size() override { return 20; }
505 void writeTo(uint8_t *buf) override;
506 void addSymbols(ThunkSection &isec) override;
507 bool isCompatibleWith(const InputSection &isec,
508 const Relocation &rel) const override;
509};
510
511// PPC64 R2 Save Stub
512// When the caller requires a valid R2 TOC pointer but the callee does not
513// require a TOC pointer and the callee cannot guarantee that it doesn't
514// clobber R2 then we need to save R2. This stub:
515// 1) Saves the TOC pointer to the stack.
516// 2) Tail calls the callee.
517class PPC64R2SaveStub final : public Thunk {
518public:
519 PPC64R2SaveStub(Ctx &ctx, Symbol &dest, int64_t addend)
520 : Thunk(ctx, dest, addend) {
521 alignment = 16;
522 }
523
524 // To prevent oscillations in layout when moving from short to long thunks
525 // we make sure that once a thunk has been set to long it cannot go back.
526 bool getMayUseShortThunk() {
527 if (!mayUseShortThunk)
528 return false;
529 if (!isInt<26>(x: computeOffset())) {
530 mayUseShortThunk = false;
531 return false;
532 }
533 return true;
534 }
535 uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
536 void writeTo(uint8_t *buf) override;
537 void addSymbols(ThunkSection &isec) override;
538 bool isCompatibleWith(const InputSection &isec,
539 const Relocation &rel) const override;
540
541private:
542 // Transitioning from long to short can create layout oscillations in
543 // certain corner cases which would prevent the layout from converging.
544 // This is similar to the handling for ARMThunk.
545 bool mayUseShortThunk = true;
546 int64_t computeOffset() const {
547 return destination.getVA(ctx) - (getThunkTargetSym()->getVA(ctx) + 4);
548 }
549};
550
551// PPC64 R12 Setup Stub
552// When a caller that does not maintain TOC calls a target which may possibly
553// use TOC (either non-preemptible with localentry>1 or preemptible), we need to
554// set r12 to satisfy the requirement of the global entry point.
555class PPC64R12SetupStub final : public Thunk {
556public:
557 PPC64R12SetupStub(Ctx &ctx, Symbol &dest, bool gotPlt)
558 : Thunk(ctx, dest, 0), gotPlt(gotPlt) {
559 alignment = 16;
560 }
561 uint32_t size() override { return 32; }
562 void writeTo(uint8_t *buf) override;
563 void addSymbols(ThunkSection &isec) override;
564 bool isCompatibleWith(const InputSection &isec,
565 const Relocation &rel) const override;
566
567private:
568 bool gotPlt;
569};
570
571// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
572// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
573// larger than that we need to emit a long-branch thunk. The target address
574// of the callee is stored in a table to be accessed TOC-relative. Since the
575// call must be local (a non-local call will have a PltCallStub instead) the
576// table stores the address of the callee's local entry point. For
577// position-independent code a corresponding relative dynamic relocation is
578// used.
579class PPC64LongBranchThunk : public Thunk {
580public:
581 uint32_t size() override { return 32; }
582 void writeTo(uint8_t *buf) override;
583 void addSymbols(ThunkSection &isec) override;
584 bool isCompatibleWith(const InputSection &isec,
585 const Relocation &rel) const override;
586
587protected:
588 PPC64LongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
589 : Thunk(ctx, dest, addend) {}
590};
591
592class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
593public:
594 PPC64PILongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
595 : PPC64LongBranchThunk(ctx, dest, addend) {
596 assert(!dest.isPreemptible);
597 if (std::optional<uint32_t> index =
598 ctx.in.ppc64LongBranchTarget->addEntry(sym: &dest, addend)) {
599 ctx.mainPart->relaDyn->addRelativeReloc(
600 dynType: ctx.target->relativeRel, isec&: *ctx.in.ppc64LongBranchTarget,
601 offsetInSec: *index * UINT64_C(8), sym&: dest,
602 addend: addend + getPPC64GlobalEntryToLocalEntryOffset(ctx, stOther: dest.stOther),
603 addendRelType: ctx.target->symbolicRel, expr: R_ABS);
604 }
605 }
606};
607
608class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
609public:
610 PPC64PDLongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)
611 : PPC64LongBranchThunk(ctx, dest, addend) {
612 ctx.in.ppc64LongBranchTarget->addEntry(sym: &dest, addend);
613 }
614};
615
616} // end anonymous namespace
617
618Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
619 InputSectionBase &section) {
620 Defined *d =
621 addSyntheticLocal(ctx, name, type, value: value + offset, /*size=*/0, section);
622 syms.push_back(Elt: d);
623 return d;
624}
625
626void Thunk::setOffset(uint64_t newOffset) {
627 for (Defined *d : syms)
628 d->value = d->value - offset + newOffset;
629 offset = newOffset;
630}
631
632// AArch64 Thunk base class.
633static uint64_t getAArch64ThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
634 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, addend: a);
635 return v;
636}
637
638bool AArch64Thunk::getMayUseShortThunk() {
639 if (!mayUseShortThunk)
640 return false;
641 uint64_t s = getAArch64ThunkDestVA(ctx, s: destination, a: addend);
642 uint64_t p = getThunkTargetSym()->getVA(ctx);
643 mayUseShortThunk = llvm::isInt<28>(x: s - p);
644 if (!mayUseShortThunk)
645 addLongMapSyms();
646 return mayUseShortThunk;
647}
648
649void AArch64Thunk::writeTo(uint8_t *buf) {
650 if (!getMayUseShortThunk()) {
651 writeLong(buf);
652 return;
653 }
654 uint64_t s = getAArch64ThunkDestVA(ctx, s: destination, a: addend);
655 uint64_t p = getThunkTargetSym()->getVA(ctx);
656 write32(ctx, p: buf, v: 0x14000000); // b S
657 ctx.target->relocateNoSym(loc: buf, type: R_AARCH64_CALL26, val: s - p);
658}
659
660bool AArch64Thunk::needsSyntheticLandingPad() {
661 // Short Thunks use a direct branch, no synthetic landing pad
662 // required.
663 return mayNeedLandingPad && !getMayUseShortThunk();
664}
665
666// AArch64 long range Thunks.
667void AArch64ABSLongThunk::writeLong(uint8_t *buf) {
668 const uint8_t data[] = {
669 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
670 0x00, 0x02, 0x1f, 0xd6, // br x16
671 0x00, 0x00, 0x00, 0x00, // L0: .xword S
672 0x00, 0x00, 0x00, 0x00,
673 };
674 // If mayNeedLandingPad is true then destination is an
675 // AArch64BTILandingPadThunk that defines landingPad.
676 assert(!mayNeedLandingPad || landingPad != nullptr);
677 uint64_t s = mayNeedLandingPad
678 ? landingPad->getVA(ctx, addend: 0)
679 : getAArch64ThunkDestVA(ctx, s: destination, a: addend);
680 memcpy(dest: buf, src: data, n: sizeof(data));
681 ctx.target->relocateNoSym(loc: buf + 8, type: R_AARCH64_ABS64, val: s);
682}
683
684void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
685 addSymbol(name: ctx.saver.save(S: "__AArch64AbsLongThunk_" + destination.getName()),
686 type: STT_FUNC, value: 0, section&: isec);
687 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: isec);
688 tsec = &isec;
689 (void)getMayUseShortThunk();
690}
691
692void AArch64ABSLongThunk::addLongMapSyms() {
693 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
694 // The ldr in the long Thunk requires 8-byte alignment when
695 // unaligned accesses are disabled.
696 alignment = 8;
697}
698
699void AArch64ABSXOLongThunk::writeLong(uint8_t *buf) {
700 const uint8_t data[] = {
701 0x10, 0x00, 0x80, 0xd2, // movz x16, :abs_g0_nc:S, lsl #0
702 0x10, 0x00, 0xa0, 0xf2, // movk x16, :abs_g1_nc:S, lsl #16
703 0x10, 0x00, 0xc0, 0xf2, // movk x16, :abs_g2_nc:S, lsl #32
704 0x10, 0x00, 0xe0, 0xf2, // movk x16, :abs_g3:S, lsl #48
705 0x00, 0x02, 0x1f, 0xd6, // br x16
706 };
707 // If mayNeedLandingPad is true then destination is an
708 // AArch64BTILandingPadThunk that defines landingPad.
709 assert(!mayNeedLandingPad || landingPad != nullptr);
710 uint64_t s = mayNeedLandingPad
711 ? landingPad->getVA(ctx, addend: 0)
712 : getAArch64ThunkDestVA(ctx, s: destination, a: addend);
713 memcpy(dest: buf, src: data, n: sizeof(data));
714 ctx.target->relocateNoSym(loc: buf + 0, type: R_AARCH64_MOVW_UABS_G0_NC, val: s);
715 ctx.target->relocateNoSym(loc: buf + 4, type: R_AARCH64_MOVW_UABS_G1_NC, val: s);
716 ctx.target->relocateNoSym(loc: buf + 8, type: R_AARCH64_MOVW_UABS_G2_NC, val: s);
717 ctx.target->relocateNoSym(loc: buf + 12, type: R_AARCH64_MOVW_UABS_G3, val: s);
718}
719
720void AArch64ABSXOLongThunk::addSymbols(ThunkSection &sec) {
721 addSymbol(name: ctx.saver.save(S: "__AArch64AbsXOLongThunk_" + destination.getName()),
722 type: STT_FUNC, value: 0, section&: sec);
723 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: sec);
724}
725
726// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
727// using the small code model, including pc-relative ones. At time of writing
728// clang and gcc do not support the large code model for position independent
729// code so it is safe to use this for position independent thunks without
730// worrying about the destination being more than 4Gb away.
731void AArch64ADRPThunk::writeLong(uint8_t *buf) {
732 const uint8_t data[] = {
733 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
734 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
735 0x00, 0x02, 0x1f, 0xd6, // br x16
736 };
737 // if mayNeedLandingPad is true then destination is an
738 // AArch64BTILandingPadThunk that defines landingPad.
739 assert(!mayNeedLandingPad || landingPad != nullptr);
740 uint64_t s = mayNeedLandingPad
741 ? landingPad->getVA(ctx, addend: 0)
742 : getAArch64ThunkDestVA(ctx, s: destination, a: addend);
743 uint64_t p = getThunkTargetSym()->getVA(ctx);
744 memcpy(dest: buf, src: data, n: sizeof(data));
745 ctx.target->relocateNoSym(loc: buf, type: R_AARCH64_ADR_PREL_PG_HI21,
746 val: getAArch64Page(expr: s) - getAArch64Page(expr: p));
747 ctx.target->relocateNoSym(loc: buf + 4, type: R_AARCH64_ADD_ABS_LO12_NC, val: s);
748}
749
750void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
751 addSymbol(name: ctx.saver.save(S: "__AArch64ADRPThunk_" + destination.getName()),
752 type: STT_FUNC, value: 0, section&: isec);
753 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: isec);
754}
755
756void AArch64BTILandingPadThunk::addSymbols(ThunkSection &isec) {
757 addSymbol(name: ctx.saver.save(S: "__AArch64BTIThunk_" + destination.getName()),
758 type: STT_FUNC, value: 0, section&: isec);
759 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: isec);
760}
761
762void AArch64BTILandingPadThunk::writeTo(uint8_t *buf) {
763 if (!getMayUseShortThunk()) {
764 writeLong(buf);
765 return;
766 }
767 write32(ctx, p: buf, v: 0xd503245f); // BTI c
768 // Control falls through to target in following section.
769}
770
771bool AArch64BTILandingPadThunk::getMayUseShortThunk() {
772 if (!mayUseShortThunk)
773 return false;
774 // If the target is the following instruction then we can fall
775 // through without the indirect branch.
776 uint64_t s = destination.getVA(ctx, addend);
777 uint64_t p = getThunkTargetSym()->getVA(ctx);
778 // This function is called before addresses are stable. We need to
779 // work out the range from the thunk to the next section but the
780 // address of the start of the next section depends on the size of
781 // the thunks in the previous pass. s - p + offset == 0 represents
782 // the first pass where the Thunk and following section are assigned
783 // the same offset. s - p <= 4 is the last Thunk in the Thunk
784 // Section.
785 mayUseShortThunk = (s - p + offset == 0 || s - p <= 4);
786 return mayUseShortThunk;
787}
788
789void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) {
790 uint64_t s = destination.getVA(ctx, addend);
791 uint64_t p = getThunkTargetSym()->getVA(ctx) + 4;
792 write32(ctx, p: buf, v: 0xd503245f); // BTI c
793 write32(ctx, p: buf + 4, v: 0x14000000); // B S
794 ctx.target->relocateNoSym(loc: buf + 4, type: R_AARCH64_CALL26, val: s - p);
795}
796
797// ARM Target Thunks
798static uint64_t getARMThunkDestVA(Ctx &ctx, const Symbol &s) {
799 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx);
800 return SignExtend64<32>(x: v);
801}
802
803// This function returns true if the target is not Thumb and is within 2^26, and
804// it has not previously returned false (see comment for mayUseShortThunk).
805bool ARMThunk::getMayUseShortThunk() {
806 if (!mayUseShortThunk)
807 return false;
808 uint64_t s = getARMThunkDestVA(ctx, s: destination);
809 if (s & 1) {
810 mayUseShortThunk = false;
811 addLongMapSyms();
812 return false;
813 }
814 uint64_t p = getThunkTargetSym()->getVA(ctx);
815 int64_t offset = s - p - 8;
816 mayUseShortThunk = llvm::isInt<26>(x: offset);
817 if (!mayUseShortThunk)
818 addLongMapSyms();
819 return mayUseShortThunk;
820}
821
822void ARMThunk::writeTo(uint8_t *buf) {
823 if (!getMayUseShortThunk()) {
824 writeLong(buf);
825 return;
826 }
827
828 uint64_t s = getARMThunkDestVA(ctx, s: destination);
829 uint64_t p = getThunkTargetSym()->getVA(ctx);
830 int64_t offset = s - p - 8;
831 write32(ctx, p: buf, v: 0xea000000); // b S
832 ctx.target->relocateNoSym(loc: buf, type: R_ARM_JUMP24, val: offset);
833}
834
835bool ARMThunk::isCompatibleWith(const InputSection &isec,
836 const Relocation &rel) const {
837 // v4T does not have BLX, so also deny R_ARM_THM_CALL
838 if (!ctx.arg.armHasBlx && rel.type == R_ARM_THM_CALL)
839 return false;
840
841 // Thumb branch relocations can't use BLX
842 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
843}
844
845// This function returns true if:
846// the target is Thumb
847// && is within branch range
848// && this function has not previously returned false
849// (see comment for mayUseShortThunk)
850// && the arch supports Thumb branch range extension.
851bool ThumbThunk::getMayUseShortThunk() {
852 if (!mayUseShortThunk)
853 return false;
854 uint64_t s = getARMThunkDestVA(ctx, s: destination);
855 // To use a short thunk the destination must be Thumb and the target must
856 // have the wide branch instruction B.w. This instruction is included when
857 // Thumb 2 is present, or in v8-M (and above) baseline architectures.
858 // armJ1J2BranchEncoding is available in all architectures with a profile and
859 // the one v6 CPU that implements Thumb 2 (Arm1156t2-s).
860 // Movt and Movw instructions require Thumb 2 or v8-M baseline.
861 if ((s & 1) == 0 || !ctx.arg.armJ1J2BranchEncoding ||
862 !ctx.arg.armHasMovtMovw) {
863 mayUseShortThunk = false;
864 addLongMapSyms();
865 return false;
866 }
867 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~1;
868 int64_t offset = s - p - 4;
869 mayUseShortThunk = llvm::isInt<25>(x: offset);
870 if (!mayUseShortThunk)
871 addLongMapSyms();
872 return mayUseShortThunk;
873}
874
875void ThumbThunk::writeTo(uint8_t *buf) {
876 if (!getMayUseShortThunk()) {
877 writeLong(buf);
878 return;
879 }
880
881 uint64_t s = getARMThunkDestVA(ctx, s: destination);
882 uint64_t p = getThunkTargetSym()->getVA(ctx);
883 int64_t offset = s - p - 4;
884 write16(ctx, p: buf + 0, v: 0xf000); // b.w S
885 write16(ctx, p: buf + 2, v: 0xb000);
886 ctx.target->relocateNoSym(loc: buf, type: R_ARM_THM_JUMP24, val: offset);
887}
888
889bool ThumbThunk::isCompatibleWith(const InputSection &isec,
890 const Relocation &rel) const {
891 // v4T does not have BLX, so also deny R_ARM_CALL
892 if (!ctx.arg.armHasBlx && rel.type == R_ARM_CALL)
893 return false;
894
895 // ARM branch relocations can't use BLX
896 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
897}
898
899void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
900 write32(ctx, p: buf + 0, v: 0xe300c000); // movw ip,:lower16:S
901 write32(ctx, p: buf + 4, v: 0xe340c000); // movt ip,:upper16:S
902 write32(ctx, p: buf + 8, v: 0xe12fff1c); // bx ip
903 uint64_t s = getARMThunkDestVA(ctx, s: destination);
904 ctx.target->relocateNoSym(loc: buf, type: R_ARM_MOVW_ABS_NC, val: s);
905 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_MOVT_ABS, val: s);
906}
907
908void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
909 addSymbol(name: ctx.saver.save(S: "__ARMv7ABSLongThunk_" + destination.getName()),
910 type: STT_FUNC, value: 0, section&: isec);
911 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
912}
913
914void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
915 write16(ctx, p: buf + 0, v: 0xf240); // movw ip, :lower16:S
916 write16(ctx, p: buf + 2, v: 0x0c00);
917 write16(ctx, p: buf + 4, v: 0xf2c0); // movt ip, :upper16:S
918 write16(ctx, p: buf + 6, v: 0x0c00);
919 write16(ctx, p: buf + 8, v: 0x4760); // bx ip
920 uint64_t s = getARMThunkDestVA(ctx, s: destination);
921 ctx.target->relocateNoSym(loc: buf, type: R_ARM_THM_MOVW_ABS_NC, val: s);
922 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_THM_MOVT_ABS, val: s);
923}
924
925void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
926 addSymbol(name: ctx.saver.save(S: "__Thumbv7ABSLongThunk_" + destination.getName()),
927 type: STT_FUNC, value: 1, section&: isec);
928 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
929}
930
931void ARMV7PILongThunk::writeLong(uint8_t *buf) {
932 write32(ctx, p: buf + 0,
933 v: 0xe30fcff0); // P: movw ip,:lower16:S - (P + (L1-P) + 8)
934 write32(ctx, p: buf + 4,
935 v: 0xe340c000); // movt ip,:upper16:S - (P + (L1-P) + 8)
936 write32(ctx, p: buf + 8, v: 0xe08cc00f); // L1: add ip, ip, pc
937 write32(ctx, p: buf + 12, v: 0xe12fff1c); // bx ip
938 uint64_t s = getARMThunkDestVA(ctx, s: destination);
939 uint64_t p = getThunkTargetSym()->getVA(ctx);
940 int64_t offset = s - p - 16;
941 ctx.target->relocateNoSym(loc: buf, type: R_ARM_MOVW_PREL_NC, val: offset);
942 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_MOVT_PREL, val: offset);
943}
944
945void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
946 addSymbol(name: ctx.saver.save(S: "__ARMV7PILongThunk_" + destination.getName()),
947 type: STT_FUNC, value: 0, section&: isec);
948 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
949}
950
951void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
952 write16(ctx, p: buf + 0, v: 0xf64f); // P: movw ip,:lower16:S - (P + (L1-P) + 4)
953 write16(ctx, p: buf + 2, v: 0x7cf4);
954 write16(ctx, p: buf + 4, v: 0xf2c0); // movt ip,:upper16:S - (P + (L1-P) + 4)
955 write16(ctx, p: buf + 6, v: 0x0c00);
956 write16(ctx, p: buf + 8, v: 0x44fc); // L1: add ip, pc
957 write16(ctx, p: buf + 10, v: 0x4760); // bx ip
958 uint64_t s = getARMThunkDestVA(ctx, s: destination);
959 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
960 int64_t offset = s - p - 12;
961 ctx.target->relocateNoSym(loc: buf, type: R_ARM_THM_MOVW_PREL_NC, val: offset);
962 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_THM_MOVT_PREL, val: offset);
963}
964
965void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
966 addSymbol(name: ctx.saver.save(S: "__ThumbV7PILongThunk_" + destination.getName()),
967 type: STT_FUNC, value: 1, section&: isec);
968 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
969}
970
971void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
972 // Most Thumb instructions cannot access the high registers r8 - r15. As the
973 // only register we can corrupt is r12 we must instead spill a low register
974 // to the stack to use as a scratch register. We push r1 even though we
975 // don't need to get some space to use for the return address.
976 write16(ctx, p: buf + 0, v: 0xb403); // push {r0, r1} ; Obtain scratch registers
977 write16(ctx, p: buf + 2, v: 0x4801); // ldr r0, [pc, #4] ; L1
978 write16(ctx, p: buf + 4, v: 0x9001); // str r0, [sp, #4] ; SP + 4 = S
979 write16(ctx, p: buf + 6, v: 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
980 write32(ctx, p: buf + 8, v: 0x00000000); // L1: .word S
981 uint64_t s = getARMThunkDestVA(ctx, s: destination);
982 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_ABS32, val: s);
983}
984
985void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
986 addSymbol(name: ctx.saver.save(S: "__Thumbv6MABSLongThunk_" + destination.getName()),
987 type: STT_FUNC, value: 1, section&: isec);
988 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
989 tsec = &isec;
990 (void)getMayUseShortThunk();
991}
992
993void ThumbV6MABSLongThunk::addLongMapSyms() {
994 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
995}
996
997void ThumbV6MABSXOLongThunk::writeLong(uint8_t *buf) {
998 // Most Thumb instructions cannot access the high registers r8 - r15. As the
999 // only register we can corrupt is r12 we must instead spill a low register
1000 // to the stack to use as a scratch register. We push r1 even though we
1001 // don't need to get some space to use for the return address.
1002 write16(ctx, p: buf + 0, v: 0xb403); // push {r0, r1} ; Obtain scratch registers
1003 write16(ctx, p: buf + 2, v: 0x2000); // movs r0, :upper8_15:S
1004 write16(ctx, p: buf + 4, v: 0x0200); // lsls r0, r0, #8
1005 write16(ctx, p: buf + 6, v: 0x3000); // adds r0, :upper0_7:S
1006 write16(ctx, p: buf + 8, v: 0x0200); // lsls r0, r0, #8
1007 write16(ctx, p: buf + 10, v: 0x3000); // adds r0, :lower8_15:S
1008 write16(ctx, p: buf + 12, v: 0x0200); // lsls r0, r0, #8
1009 write16(ctx, p: buf + 14, v: 0x3000); // adds r0, :lower0_7:S
1010 write16(ctx, p: buf + 16, v: 0x9001); // str r0, [sp, #4] ; SP + 4 = S
1011 write16(ctx, p: buf + 18,
1012 v: 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
1013 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1014 ctx.target->relocateNoSym(loc: buf + 2, type: R_ARM_THM_ALU_ABS_G3, val: s);
1015 ctx.target->relocateNoSym(loc: buf + 6, type: R_ARM_THM_ALU_ABS_G2_NC, val: s);
1016 ctx.target->relocateNoSym(loc: buf + 10, type: R_ARM_THM_ALU_ABS_G1_NC, val: s);
1017 ctx.target->relocateNoSym(loc: buf + 14, type: R_ARM_THM_ALU_ABS_G0_NC, val: s);
1018}
1019
1020void ThumbV6MABSXOLongThunk::addSymbols(ThunkSection &isec) {
1021 addSymbol(name: ctx.saver.save(S: "__Thumbv6MABSXOLongThunk_" + destination.getName()),
1022 type: STT_FUNC, value: 1, section&: isec);
1023 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1024}
1025
1026void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
1027 // Most Thumb instructions cannot access the high registers r8 - r15. As the
1028 // only register we can corrupt is ip (r12) we must instead spill a low
1029 // register to the stack to use as a scratch register.
1030 write16(ctx, p: buf + 0,
1031 v: 0xb401); // P: push {r0} ; Obtain scratch register
1032 write16(ctx, p: buf + 2, v: 0x4802); // ldr r0, [pc, #8] ; L2
1033 write16(ctx, p: buf + 4, v: 0x4684); // mov ip, r0 ; high to low register
1034 write16(ctx, p: buf + 6,
1035 v: 0xbc01); // pop {r0} ; restore scratch register
1036 write16(ctx, p: buf + 8, v: 0x44e7); // L1: add pc, ip ; transfer control
1037 write16(ctx, p: buf + 10,
1038 v: 0x46c0); // nop ; pad to 4-byte boundary
1039 write32(ctx, p: buf + 12, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 4)
1040 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1041 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1042 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_REL32, val: s - p - 12);
1043}
1044
1045void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
1046 addSymbol(name: ctx.saver.save(S: "__Thumbv6MPILongThunk_" + destination.getName()),
1047 type: STT_FUNC, value: 1, section&: isec);
1048 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1049 tsec = &isec;
1050 (void)getMayUseShortThunk();
1051}
1052
1053void ThumbV6MPILongThunk::addLongMapSyms() {
1054 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1055}
1056
1057void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
1058 write32(ctx, p: buf + 0, v: 0xe51ff004); // ldr pc, [pc,#-4] ; L1
1059 write32(ctx, p: buf + 4, v: 0x00000000); // L1: .word S
1060 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_ABS32,
1061 val: getARMThunkDestVA(ctx, s: destination));
1062}
1063
1064void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
1065 addSymbol(name: ctx.saver.save(S: "__ARMv5LongLdrPcThunk_" + destination.getName()),
1066 type: STT_FUNC, value: 0, section&: isec);
1067 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1068 tsec = &isec;
1069 (void)getMayUseShortThunk();
1070}
1071
1072void ARMV5LongLdrPcThunk::addLongMapSyms() {
1073 addSymbol(name: "$d", type: STT_NOTYPE, value: 4, section&: *tsec);
1074}
1075
1076void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
1077 write32(ctx, p: buf + 0, v: 0xe59fc000); // ldr r12, [pc] ; L1
1078 write32(ctx, p: buf + 4, v: 0xe12fff1c); // bx r12
1079 write32(ctx, p: buf + 8, v: 0x00000000); // L1: .word S
1080 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_ABS32,
1081 val: getARMThunkDestVA(ctx, s: destination));
1082}
1083
1084void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
1085 addSymbol(name: ctx.saver.save(S: "__ARMv4ABSLongBXThunk_" + destination.getName()),
1086 type: STT_FUNC, value: 0, section&: isec);
1087 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1088 tsec = &isec;
1089 (void)getMayUseShortThunk();
1090}
1091
1092void ARMV4ABSLongBXThunk::addLongMapSyms() {
1093 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
1094}
1095
1096void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
1097 write16(ctx, p: buf + 0, v: 0x4778); // bx pc
1098 write16(ctx, p: buf + 2,
1099 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1100 write32(ctx, p: buf + 4, v: 0xe51ff004); // ldr pc, [pc, #-4] ; L1
1101 write32(ctx, p: buf + 8, v: 0x00000000); // L1: .word S
1102 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_ABS32,
1103 val: getARMThunkDestVA(ctx, s: destination));
1104}
1105
1106void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
1107 addSymbol(name: ctx.saver.save(S: "__Thumbv4ABSLongBXThunk_" + destination.getName()),
1108 type: STT_FUNC, value: 1, section&: isec);
1109 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1110 tsec = &isec;
1111 (void)getMayUseShortThunk();
1112}
1113
1114void ThumbV4ABSLongBXThunk::addLongMapSyms() {
1115 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1116 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
1117}
1118
1119void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
1120 write16(ctx, p: buf + 0, v: 0x4778); // bx pc
1121 write16(ctx, p: buf + 2,
1122 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1123 write32(ctx, p: buf + 4, v: 0xe59fc000); // ldr r12, [pc] ; L1
1124 write32(ctx, p: buf + 8, v: 0xe12fff1c); // bx r12
1125 write32(ctx, p: buf + 12, v: 0x00000000); // L1: .word S
1126 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_ABS32,
1127 val: getARMThunkDestVA(ctx, s: destination));
1128}
1129
1130void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
1131 addSymbol(name: ctx.saver.save(S: "__Thumbv4ABSLongThunk_" + destination.getName()),
1132 type: STT_FUNC, value: 1, section&: isec);
1133 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1134 tsec = &isec;
1135 (void)getMayUseShortThunk();
1136}
1137
1138void ThumbV4ABSLongThunk::addLongMapSyms() {
1139 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1140 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1141}
1142
1143void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
1144 write32(ctx, p: buf + 0, v: 0xe59fc004); // P: ldr ip, [pc,#4] ; L2
1145 write32(ctx, p: buf + 4, v: 0xe08fc00c); // L1: add ip, pc, ip
1146 write32(ctx, p: buf + 8, v: 0xe12fff1c); // bx ip
1147 write32(ctx, p: buf + 12, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1148 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1149 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1150 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_REL32, val: s - p - 12);
1151}
1152
1153void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1154 addSymbol(name: ctx.saver.save(S: "__ARMv4PILongBXThunk_" + destination.getName()),
1155 type: STT_FUNC, value: 0, section&: isec);
1156 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1157 tsec = &isec;
1158 (void)getMayUseShortThunk();
1159}
1160
1161void ARMV4PILongBXThunk::addLongMapSyms() {
1162 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1163}
1164
1165void ARMV4PILongThunk::writeLong(uint8_t *buf) {
1166 write32(ctx, p: buf + 0, v: 0xe59fc000); // P: ldr ip, [pc] ; L2
1167 write32(ctx, p: buf + 4, v: 0xe08ff00c); // L1: add pc, pc, r12
1168 write32(ctx, p: buf + 8, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1169 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1170 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1171 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_REL32, val: s - p - 12);
1172}
1173
1174void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
1175 addSymbol(name: ctx.saver.save(S: "__ARMv4PILongThunk_" + destination.getName()),
1176 type: STT_FUNC, value: 0, section&: isec);
1177 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1178 tsec = &isec;
1179 (void)getMayUseShortThunk();
1180}
1181
1182void ARMV4PILongThunk::addLongMapSyms() {
1183 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
1184}
1185
1186void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
1187 write16(ctx, p: buf + 0, v: 0x4778); // P: bx pc
1188 write16(ctx, p: buf + 2,
1189 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1190 write32(ctx, p: buf + 4, v: 0xe59fc000); // ldr r12, [pc] ; L2
1191 write32(ctx, p: buf + 8, v: 0xe08cf00f); // L1: add pc, r12, pc
1192 write32(ctx, p: buf + 12, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1193 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1194 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1195 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_REL32, val: s - p - 16);
1196}
1197
1198void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1199 addSymbol(name: ctx.saver.save(S: "__Thumbv4PILongBXThunk_" + destination.getName()),
1200 type: STT_FUNC, value: 1, section&: isec);
1201 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1202 tsec = &isec;
1203 (void)getMayUseShortThunk();
1204}
1205
1206void ThumbV4PILongBXThunk::addLongMapSyms() {
1207 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1208 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1209}
1210
1211void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
1212 write16(ctx, p: buf + 0, v: 0x4778); // P: bx pc
1213 write16(ctx, p: buf + 2,
1214 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1215 write32(ctx, p: buf + 4, v: 0xe59fc004); // ldr ip, [pc,#4] ; L2
1216 write32(ctx, p: buf + 8, v: 0xe08fc00c); // L1: add ip, pc, ip
1217 write32(ctx, p: buf + 12, v: 0xe12fff1c); // bx ip
1218 write32(ctx, p: buf + 16, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1219 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1220 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1221 ctx.target->relocateNoSym(loc: buf + 16, type: R_ARM_REL32, val: s - p - 16);
1222}
1223
1224void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
1225 addSymbol(name: ctx.saver.save(S: "__Thumbv4PILongThunk_" + destination.getName()),
1226 type: STT_FUNC, value: 1, section&: isec);
1227 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1228 tsec = &isec;
1229 (void)getMayUseShortThunk();
1230}
1231
1232void ThumbV4PILongThunk::addLongMapSyms() {
1233 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1234 addSymbol(name: "$d", type: STT_NOTYPE, value: 16, section&: *tsec);
1235}
1236
1237// Use the long jump which covers a range up to 8MiB.
1238void AVRThunk::writeTo(uint8_t *buf) {
1239 write32(ctx, p: buf, v: 0x940c); // jmp func
1240 ctx.target->relocateNoSym(loc: buf, type: R_AVR_CALL, val: destination.getVA(ctx));
1241}
1242
1243void AVRThunk::addSymbols(ThunkSection &isec) {
1244 addSymbol(name: ctx.saver.save(S: "__AVRThunk_" + destination.getName()), type: STT_FUNC, value: 0,
1245 section&: isec);
1246}
1247
1248// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
1249void MipsThunk::writeTo(uint8_t *buf) {
1250 uint64_t s = destination.getVA(ctx);
1251 write32(ctx, p: buf, v: 0x3c190000); // lui $25, %hi(func)
1252 write32(ctx, p: buf + 4, v: 0x08000000 | (s >> 2)); // j func
1253 write32(ctx, p: buf + 8, v: 0x27390000); // addiu $25, $25, %lo(func)
1254 write32(ctx, p: buf + 12, v: 0x00000000); // nop
1255 ctx.target->relocateNoSym(loc: buf, type: R_MIPS_HI16, val: s);
1256 ctx.target->relocateNoSym(loc: buf + 8, type: R_MIPS_LO16, val: s);
1257}
1258
1259void MipsThunk::addSymbols(ThunkSection &isec) {
1260 addSymbol(name: ctx.saver.save(S: "__LA25Thunk_" + destination.getName()), type: STT_FUNC, value: 0,
1261 section&: isec);
1262}
1263
1264InputSection *MipsThunk::getTargetInputSection() const {
1265 auto &dr = cast<Defined>(Val&: destination);
1266 return dyn_cast<InputSection>(Val: dr.section);
1267}
1268
1269// Write microMIPS R2-R5 LA25 thunk code
1270// to call PIC function from the non-PIC one.
1271void MicroMipsThunk::writeTo(uint8_t *buf) {
1272 uint64_t s = destination.getVA(ctx);
1273 write16(ctx, p: buf, v: 0x41b9); // lui $25, %hi(func)
1274 write16(ctx, p: buf + 4, v: 0xd400); // j func
1275 write16(ctx, p: buf + 8, v: 0x3339); // addiu $25, $25, %lo(func)
1276 write16(ctx, p: buf + 12, v: 0x0c00); // nop
1277 ctx.target->relocateNoSym(loc: buf, type: R_MICROMIPS_HI16, val: s);
1278 ctx.target->relocateNoSym(loc: buf + 4, type: R_MICROMIPS_26_S1, val: s);
1279 ctx.target->relocateNoSym(loc: buf + 8, type: R_MICROMIPS_LO16, val: s);
1280}
1281
1282void MicroMipsThunk::addSymbols(ThunkSection &isec) {
1283 Defined *d =
1284 addSymbol(name: ctx.saver.save(S: "__microLA25Thunk_" + destination.getName()),
1285 type: STT_FUNC, value: 0, section&: isec);
1286 d->stOther |= STO_MIPS_MICROMIPS;
1287}
1288
1289InputSection *MicroMipsThunk::getTargetInputSection() const {
1290 auto &dr = cast<Defined>(Val&: destination);
1291 return dyn_cast<InputSection>(Val: dr.section);
1292}
1293
1294// Write microMIPS R6 LA25 thunk code
1295// to call PIC function from the non-PIC one.
1296void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
1297 uint64_t s = destination.getVA(ctx);
1298 uint64_t p = getThunkTargetSym()->getVA(ctx);
1299 write16(ctx, p: buf, v: 0x1320); // lui $25, %hi(func)
1300 write16(ctx, p: buf + 4, v: 0x3339); // addiu $25, $25, %lo(func)
1301 write16(ctx, p: buf + 8, v: 0x9400); // bc func
1302 ctx.target->relocateNoSym(loc: buf, type: R_MICROMIPS_HI16, val: s);
1303 ctx.target->relocateNoSym(loc: buf + 4, type: R_MICROMIPS_LO16, val: s);
1304 ctx.target->relocateNoSym(loc: buf + 8, type: R_MICROMIPS_PC26_S1, val: s - p - 12);
1305}
1306
1307void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
1308 Defined *d =
1309 addSymbol(name: ctx.saver.save(S: "__microLA25Thunk_" + destination.getName()),
1310 type: STT_FUNC, value: 0, section&: isec);
1311 d->stOther |= STO_MIPS_MICROMIPS;
1312}
1313
1314InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
1315 auto &dr = cast<Defined>(Val&: destination);
1316 return dyn_cast<InputSection>(Val: dr.section);
1317}
1318
1319void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t gotPltVA,
1320 const InputFile *file, int64_t addend) {
1321 if (!ctx.arg.isPic) {
1322 write32(ctx, p: buf + 0, v: 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
1323 write32(ctx, p: buf + 4, v: 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
1324 write32(ctx, p: buf + 8, v: 0x7d6903a6); // mtctr r11
1325 write32(ctx, p: buf + 12, v: 0x4e800420); // bctr
1326 return;
1327 }
1328 uint32_t offset;
1329 if (addend >= 0x8000) {
1330 // The stub loads an address relative to r30 (.got2+Addend). Addend is
1331 // almost always 0x8000. The address of .got2 is different in another object
1332 // file, so a stub cannot be shared.
1333 offset = gotPltVA -
1334 (ctx.in.ppc32Got2->getParent()->getVA() +
1335 (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
1336 } else {
1337 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
1338 // currently the address of .got).
1339 offset = gotPltVA - ctx.in.got->getVA();
1340 }
1341 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
1342 if (ha == 0) {
1343 write32(ctx, p: buf + 0, v: 0x817e0000 | l); // lwz r11,l(r30)
1344 write32(ctx, p: buf + 4, v: 0x7d6903a6); // mtctr r11
1345 write32(ctx, p: buf + 8, v: 0x4e800420); // bctr
1346 write32(ctx, p: buf + 12, v: 0x60000000); // nop
1347 } else {
1348 write32(ctx, p: buf + 0, v: 0x3d7e0000 | ha); // addis r11,r30,ha
1349 write32(ctx, p: buf + 4, v: 0x816b0000 | l); // lwz r11,l(r11)
1350 write32(ctx, p: buf + 8, v: 0x7d6903a6); // mtctr r11
1351 write32(ctx, p: buf + 12, v: 0x4e800420); // bctr
1352 }
1353}
1354
1355void PPC32PltCallStub::writeTo(uint8_t *buf) {
1356 writePPC32PltCallStub(ctx, buf, gotPltVA: destination.getGotPltVA(ctx), file, addend);
1357}
1358
1359void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
1360 std::string buf;
1361 raw_string_ostream os(buf);
1362 os << format_hex_no_prefix(N: addend, Width: 8);
1363 if (!ctx.arg.isPic)
1364 os << ".plt_call32.";
1365 else if (addend >= 0x8000)
1366 os << ".got2.plt_pic32.";
1367 else
1368 os << ".plt_pic32.";
1369 os << destination.getName();
1370 addSymbol(name: ctx.saver.save(S: buf), type: STT_FUNC, value: 0, section&: isec);
1371}
1372
1373bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
1374 const Relocation &rel) const {
1375 return !ctx.arg.isPic || (isec.file == file && rel.addend == addend);
1376}
1377
1378void PPC32LongThunk::addSymbols(ThunkSection &isec) {
1379 addSymbol(name: ctx.saver.save(S: "__LongThunk_" + destination.getName()), type: STT_FUNC, value: 0,
1380 section&: isec);
1381}
1382
1383void PPC32LongThunk::writeTo(uint8_t *buf) {
1384 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
1385 auto lo = [](uint32_t v) -> uint16_t { return v; };
1386 uint32_t d = destination.getVA(ctx, addend);
1387 if (ctx.arg.isPic) {
1388 uint32_t off = d - (getThunkTargetSym()->getVA(ctx) + 8);
1389 write32(ctx, p: buf + 0, v: 0x7c0802a6); // mflr r12,0
1390 write32(ctx, p: buf + 4, v: 0x429f0005); // bcl r20,r31,.+4
1391 write32(ctx, p: buf + 8, v: 0x7d8802a6); // mtctr r12
1392 write32(ctx, p: buf + 12, v: 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
1393 write32(ctx, p: buf + 16, v: 0x398c0000 | lo(off)); // addi r12,r12,off@l
1394 write32(ctx, p: buf + 20, v: 0x7c0803a6); // mtlr r0
1395 buf += 24;
1396 } else {
1397 write32(ctx, p: buf + 0, v: 0x3d800000 | ha(d)); // lis r12,d@ha
1398 write32(ctx, p: buf + 4, v: 0x398c0000 | lo(d)); // addi r12,r12,d@l
1399 buf += 8;
1400 }
1401 write32(ctx, p: buf + 0, v: 0x7d8903a6); // mtctr r12
1402 write32(ctx, p: buf + 4, v: 0x4e800420); // bctr
1403}
1404
1405void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, int64_t offset) {
1406 uint16_t offHa = (offset + 0x8000) >> 16;
1407 uint16_t offLo = offset & 0xffff;
1408
1409 write32(ctx, p: buf + 0, v: 0x3d820000 | offHa); // addis r12, r2, OffHa
1410 write32(ctx, p: buf + 4, v: 0xe98c0000 | offLo); // ld r12, OffLo(r12)
1411 write32(ctx, p: buf + 8, v: 0x7d8903a6); // mtctr r12
1412 write32(ctx, p: buf + 12, v: 0x4e800420); // bctr
1413}
1414
1415void PPC64PltCallStub::writeTo(uint8_t *buf) {
1416 int64_t offset = destination.getGotPltVA(ctx) - getPPC64TocBase(ctx);
1417 // Save the TOC pointer to the save-slot reserved in the call frame.
1418 write32(ctx, p: buf + 0, v: 0xf8410018); // std r2,24(r1)
1419 writePPC64LoadAndBranch(ctx, buf: buf + 4, offset);
1420}
1421
1422void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
1423 Defined *s = addSymbol(name: ctx.saver.save(S: "__plt_" + destination.getName()),
1424 type: STT_FUNC, value: 0, section&: isec);
1425 s->setNeedsTocRestore(true);
1426 s->file = destination.file;
1427}
1428
1429bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
1430 const Relocation &rel) const {
1431 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1432}
1433
1434void PPC64R2SaveStub::writeTo(uint8_t *buf) {
1435 const int64_t offset = computeOffset();
1436 write32(ctx, p: buf + 0, v: 0xf8410018); // std r2,24(r1)
1437 // The branch offset needs to fit in 26 bits.
1438 if (getMayUseShortThunk()) {
1439 write32(ctx, p: buf + 4, v: 0x48000000 | (offset & 0x03fffffc)); // b <offset>
1440 } else if (isInt<34>(x: offset)) {
1441 int nextInstOffset;
1442 uint64_t tocOffset = destination.getVA(ctx) - getPPC64TocBase(ctx);
1443 if (tocOffset >> 16 > 0) {
1444 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
1445 const uint64_t addis =
1446 ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
1447 write32(ctx, p: buf + 4, v: addis); // addis r12, r2 , top of offset
1448 write32(ctx, p: buf + 8, v: addi); // addi r12, r12, bottom of offset
1449 nextInstOffset = 12;
1450 } else {
1451 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
1452 write32(ctx, p: buf + 4, v: addi); // addi r12, r2, offset
1453 nextInstOffset = 8;
1454 }
1455 write32(ctx, p: buf + nextInstOffset, v: MTCTR_R12); // mtctr r12
1456 write32(ctx, p: buf + nextInstOffset + 4, v: BCTR); // bctr
1457 } else {
1458 ctx.in.ppc64LongBranchTarget->addEntry(sym: &destination, addend);
1459 const int64_t offsetFromTOC =
1460 ctx.in.ppc64LongBranchTarget->getEntryVA(sym: &destination, addend) -
1461 getPPC64TocBase(ctx);
1462 writePPC64LoadAndBranch(ctx, buf: buf + 4, offset: offsetFromTOC);
1463 }
1464}
1465
1466void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
1467 Defined *s = addSymbol(name: ctx.saver.save(S: "__toc_save_" + destination.getName()),
1468 type: STT_FUNC, value: 0, section&: isec);
1469 s->setNeedsTocRestore(true);
1470}
1471
1472bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
1473 const Relocation &rel) const {
1474 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1475}
1476
1477void PPC64R12SetupStub::writeTo(uint8_t *buf) {
1478 int64_t offset =
1479 (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA(ctx)) -
1480 getThunkTargetSym()->getVA(ctx);
1481 if (!isInt<34>(x: offset))
1482 reportRangeError(ctx, loc: buf, v: offset, n: 34, sym: destination,
1483 msg: "R12 setup stub offset");
1484
1485 int nextInstOffset;
1486 if (ctx.arg.power10Stubs) {
1487 const uint64_t imm = (((offset >> 16) & 0x3ffff) << 32) | (offset & 0xffff);
1488 // pld 12, func@plt@pcrel or paddi r12, 0, func@pcrel
1489 writePrefixedInst(ctx, loc: buf,
1490 insn: (gotPlt ? PLD_R12_NO_DISP : PADDI_R12_NO_DISP) | imm);
1491 nextInstOffset = 8;
1492 } else {
1493 uint32_t off = offset - 8;
1494 write32(ctx, p: buf + 0, v: 0x7d8802a6); // mflr 12
1495 write32(ctx, p: buf + 4, v: 0x429f0005); // bcl 20,31,.+4
1496 write32(ctx, p: buf + 8, v: 0x7d6802a6); // mflr 11
1497 write32(ctx, p: buf + 12, v: 0x7d8803a6); // mtlr 12
1498 write32(ctx, p: buf + 16,
1499 v: 0x3d8b0000 | ((off + 0x8000) >> 16)); // addis 12,11,off@ha
1500 if (gotPlt)
1501 write32(ctx, p: buf + 20, v: 0xe98c0000 | (off & 0xffff)); // ld 12, off@l(12)
1502 else
1503 write32(ctx, p: buf + 20, v: 0x398c0000 | (off & 0xffff)); // addi 12,12,off@l
1504 nextInstOffset = 24;
1505 }
1506 write32(ctx, p: buf + nextInstOffset, v: MTCTR_R12); // mtctr r12
1507 write32(ctx, p: buf + nextInstOffset + 4, v: BCTR); // bctr
1508}
1509
1510void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
1511 addSymbol(name: ctx.saver.save(S: (gotPlt ? "__plt_pcrel_" : "__gep_setup_") +
1512 destination.getName()),
1513 type: STT_FUNC, value: 0, section&: isec);
1514}
1515
1516bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
1517 const Relocation &rel) const {
1518 return rel.type == R_PPC64_REL24_NOTOC;
1519}
1520
1521void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
1522 int64_t offset =
1523 ctx.in.ppc64LongBranchTarget->getEntryVA(sym: &destination, addend) -
1524 getPPC64TocBase(ctx);
1525 writePPC64LoadAndBranch(ctx, buf, offset);
1526}
1527
1528void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
1529 addSymbol(name: ctx.saver.save(S: "__long_branch_" + destination.getName()), type: STT_FUNC,
1530 value: 0, section&: isec);
1531}
1532
1533bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
1534 const Relocation &rel) const {
1535 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1536}
1537
1538// Hexagon Target Thunks
1539static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
1540 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, addend: a);
1541 return SignExtend64<32>(x: v);
1542}
1543
1544void HexagonThunk::writeTo(uint8_t *buf) {
1545 uint64_t s = getHexagonThunkDestVA(ctx, s: destination, a: addend);
1546 uint64_t p = getThunkTargetSym()->getVA(ctx);
1547
1548 if (ctx.arg.isPic) {
1549 write32(ctx, p: buf + 0, v: 0x00004000); // { immext(#0)
1550 ctx.target->relocateNoSym(loc: buf, type: R_HEX_B32_PCREL_X, val: s - p);
1551 write32(ctx, p: buf + 4, v: 0x6a49c00e); // r14 = add(pc,##0) }
1552 ctx.target->relocateNoSym(loc: buf + 4, type: R_HEX_6_PCREL_X, val: s - p);
1553
1554 write32(ctx, p: buf + 8, v: 0x528ec000); // { jumpr r14 }
1555 } else {
1556 write32(ctx, p: buf + 0, v: 0x00004000); // { immext
1557 ctx.target->relocateNoSym(loc: buf, type: R_HEX_B32_PCREL_X, val: s - p);
1558 write32(ctx, p: buf + 4, v: 0x5800c000); // jump <> }
1559 ctx.target->relocateNoSym(loc: buf + 4, type: R_HEX_B22_PCREL_X, val: s - p);
1560 }
1561}
1562void HexagonThunk::addSymbols(ThunkSection &isec) {
1563 Symbol *enclosing = isec.getEnclosingSymbol(offset: relOffset);
1564 StringRef src = enclosing ? enclosing->getName() : isec.name;
1565
1566 addSymbol(
1567 name: saver().save(S: "__hexagon_thunk_" + destination.getName() + "_from_" + src),
1568 type: STT_FUNC, value: 0, section&: isec);
1569}
1570
1571Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
1572 : ctx(ctx), destination(d), addend(a), offset(0) {
1573 destination.thunkAccessed = true;
1574}
1575
1576Thunk::~Thunk() = default;
1577
1578static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, const InputSection &sec,
1579 RelType type, Symbol &s,
1580 int64_t a) {
1581 assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
1582 type));
1583 bool mayNeedLandingPad =
1584 (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
1585 !isAArch64BTILandingPad(ctx, s, a);
1586 if (ctx.arg.picThunk)
1587 return std::make_unique<AArch64ADRPThunk>(args&: ctx, args&: s, args&: a, args&: mayNeedLandingPad);
1588 if (sec.getParent()->flags & SHF_AARCH64_PURECODE)
1589 return std::make_unique<AArch64ABSXOLongThunk>(args&: ctx, args&: s, args&: a,
1590 args&: mayNeedLandingPad);
1591 return std::make_unique<AArch64ABSLongThunk>(args&: ctx, args&: s, args&: a, args&: mayNeedLandingPad);
1592}
1593
1594// Creates a thunk for long branches or Thumb-ARM interworking.
1595// Arm Architectures v4t does not support Thumb2 technology, and does not
1596// support BLX or LDR Arm/Thumb state switching. This means that
1597// - MOVT and MOVW instructions cannot be used.
1598// - We can't rewrite BL in place to BLX. We will need thunks.
1599//
1600// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
1601// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
1602static std::unique_ptr<Thunk> addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s,
1603 int64_t a) {
1604 bool thumb_target = s.getVA(ctx, addend: a) & 1;
1605
1606 switch (reloc) {
1607 case R_ARM_PC24:
1608 case R_ARM_PLT32:
1609 case R_ARM_JUMP24:
1610 case R_ARM_CALL:
1611 if (ctx.arg.picThunk) {
1612 if (thumb_target)
1613 return std::make_unique<ARMV4PILongBXThunk>(args&: ctx, args&: s, args&: a);
1614 return std::make_unique<ARMV4PILongThunk>(args&: ctx, args&: s, args&: a);
1615 }
1616 if (thumb_target)
1617 return std::make_unique<ARMV4ABSLongBXThunk>(args&: ctx, args&: s, args&: a);
1618 return std::make_unique<ARMV5LongLdrPcThunk>(args&: ctx, args&: s, args&: a);
1619 case R_ARM_THM_CALL:
1620 if (ctx.arg.picThunk) {
1621 if (thumb_target)
1622 return std::make_unique<ThumbV4PILongThunk>(args&: ctx, args&: s, args&: a);
1623 return std::make_unique<ThumbV4PILongBXThunk>(args&: ctx, args&: s, args&: a);
1624 }
1625 if (thumb_target)
1626 return std::make_unique<ThumbV4ABSLongThunk>(args&: ctx, args&: s, args&: a);
1627 return std::make_unique<ThumbV4ABSLongBXThunk>(args&: ctx, args&: s, args&: a);
1628 }
1629 Fatal(ctx) << "relocation " << reloc << " to " << &s
1630 << " not supported for Armv4 or Armv4T target";
1631 llvm_unreachable("");
1632}
1633
1634// Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
1635// Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
1636// - MOVT and MOVW instructions cannot be used
1637// - Only Thumb relocation that can generate a Thunk is a BL, this can always
1638// be transformed into a BLX
1639static std::unique_ptr<Thunk> addThunkArmv5v6(Ctx &ctx, RelType reloc,
1640 Symbol &s, int64_t a) {
1641 switch (reloc) {
1642 case R_ARM_PC24:
1643 case R_ARM_PLT32:
1644 case R_ARM_JUMP24:
1645 case R_ARM_CALL:
1646 case R_ARM_THM_CALL:
1647 if (ctx.arg.picThunk)
1648 return std::make_unique<ARMV4PILongBXThunk>(args&: ctx, args&: s, args&: a);
1649 return std::make_unique<ARMV5LongLdrPcThunk>(args&: ctx, args&: s, args&: a);
1650 }
1651 Fatal(ctx) << "relocation " << reloc << " to " << &s
1652 << " not supported for Armv5 or Armv6 targets";
1653 llvm_unreachable("");
1654}
1655
1656// Create a thunk for Thumb long branch on V6-M.
1657// Arm Architecture v6-M only supports Thumb instructions. This means
1658// - MOVT and MOVW instructions cannot be used.
1659// - Only a limited number of instructions can access registers r8 and above
1660// - No interworking support is needed (all Thumb).
1661static std::unique_ptr<Thunk> addThunkV6M(Ctx &ctx, const InputSection &isec,
1662 RelType reloc, Symbol &s, int64_t a) {
1663 const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE;
1664 switch (reloc) {
1665 case R_ARM_THM_JUMP19:
1666 case R_ARM_THM_JUMP24:
1667 case R_ARM_THM_CALL:
1668 if (ctx.arg.isPic) {
1669 if (!isPureCode)
1670 return std::make_unique<ThumbV6MPILongThunk>(args&: ctx, args&: s, args&: a);
1671
1672 Fatal(ctx)
1673 << "relocation " << reloc << " to " << &s
1674 << " not supported for Armv6-M targets for position independent"
1675 " and execute only code";
1676 llvm_unreachable("");
1677 }
1678 if (isPureCode)
1679 return std::make_unique<ThumbV6MABSXOLongThunk>(args&: ctx, args&: s, args&: a);
1680 return std::make_unique<ThumbV6MABSLongThunk>(args&: ctx, args&: s, args&: a);
1681 }
1682 Fatal(ctx) << "relocation " << reloc << " to " << &s
1683 << " not supported for Armv6-M targets";
1684 llvm_unreachable("");
1685}
1686
1687// Creates a thunk for Thumb-ARM interworking or branch range extension.
1688static std::unique_ptr<Thunk> addThunkArm(Ctx &ctx, const InputSection &isec,
1689 RelType reloc, Symbol &s, int64_t a) {
1690 // Decide which Thunk is needed based on:
1691 // Available instruction set
1692 // - An Arm Thunk can only be used if Arm state is available.
1693 // - A Thumb Thunk can only be used if Thumb state is available.
1694 // - Can only use a Thunk if it uses instructions that the Target supports.
1695 // Relocation is branch or branch and link
1696 // - Branch instructions cannot change state, can only select Thunk that
1697 // starts in the same state as the caller.
1698 // - Branch and link relocations can change state, can select Thunks from
1699 // either Arm or Thumb.
1700 // Position independent Thunks if we require position independent code.
1701 // Execute Only Thunks if the output section is execute only code.
1702
1703 // Handle architectures that have restrictions on the instructions that they
1704 // can use in Thunks. The flags below are set by reading the BuildAttributes
1705 // of the input objects. InputFiles.cpp contains the mapping from ARM
1706 // architecture to flag.
1707 if (!ctx.arg.armHasMovtMovw) {
1708 if (ctx.arg.armJ1J2BranchEncoding)
1709 return addThunkV6M(ctx, isec, reloc, s, a);
1710 if (ctx.arg.armHasBlx)
1711 return addThunkArmv5v6(ctx, reloc, s, a);
1712 return addThunkArmv4(ctx, reloc, s, a);
1713 }
1714
1715 switch (reloc) {
1716 case R_ARM_PC24:
1717 case R_ARM_PLT32:
1718 case R_ARM_JUMP24:
1719 case R_ARM_CALL:
1720 if (ctx.arg.picThunk)
1721 return std::make_unique<ARMV7PILongThunk>(args&: ctx, args&: s, args&: a);
1722 return std::make_unique<ARMV7ABSLongThunk>(args&: ctx, args&: s, args&: a);
1723 case R_ARM_THM_JUMP19:
1724 case R_ARM_THM_JUMP24:
1725 case R_ARM_THM_CALL:
1726 if (ctx.arg.picThunk)
1727 return std::make_unique<ThumbV7PILongThunk>(args&: ctx, args&: s, args&: a);
1728 return std::make_unique<ThumbV7ABSLongThunk>(args&: ctx, args&: s, args&: a);
1729 }
1730 llvm_unreachable("");
1731}
1732
1733static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,
1734 int64_t a) {
1735 switch (type) {
1736 case R_AVR_LO8_LDI_GS:
1737 case R_AVR_HI8_LDI_GS:
1738 return std::make_unique<AVRThunk>(args&: ctx, args&: s, args&: a);
1739 default:
1740 llvm_unreachable("");
1741 }
1742}
1743
1744static std::unique_ptr<Thunk> addThunkHexagon(Ctx &ctx,
1745 const InputSection &isec,
1746 Relocation &rel, Symbol &s) {
1747 switch (rel.type) {
1748 case R_HEX_B9_PCREL:
1749 case R_HEX_B13_PCREL:
1750 case R_HEX_B15_PCREL:
1751 case R_HEX_B22_PCREL:
1752 case R_HEX_PLT_B22_PCREL:
1753 case R_HEX_GD_PLT_B22_PCREL:
1754 return std::make_unique<HexagonThunk>(args&: ctx, args: isec, args&: rel, args&: s);
1755 default:
1756 Fatal(ctx) << "unrecognized relocation " << rel.type << " to " << &s
1757 << " for hexagon target";
1758 llvm_unreachable("");
1759 }
1760}
1761
1762static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
1763 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
1764 return std::make_unique<MicroMipsR6Thunk>(args&: ctx, args&: s);
1765 if (s.stOther & STO_MIPS_MICROMIPS)
1766 return std::make_unique<MicroMipsThunk>(args&: ctx, args&: s);
1767 return std::make_unique<MipsThunk>(args&: ctx, args&: s);
1768}
1769
1770static std::unique_ptr<Thunk> addThunkPPC32(Ctx &ctx, const InputSection &isec,
1771 const Relocation &rel, Symbol &s) {
1772 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
1773 rel.type == R_PPC_PLTREL24) &&
1774 "unexpected relocation type for thunk");
1775 if (s.isInPlt(ctx))
1776 return std::make_unique<PPC32PltCallStub>(args&: ctx, args: isec, args: rel, args&: s);
1777 return std::make_unique<PPC32LongThunk>(args&: ctx, args&: s, args: rel.addend);
1778}
1779
1780static std::unique_ptr<Thunk> addThunkPPC64(Ctx &ctx, RelType type, Symbol &s,
1781 int64_t a) {
1782 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
1783 type == R_PPC64_REL24_NOTOC) &&
1784 "unexpected relocation type for thunk");
1785
1786 // If we are emitting stubs for NOTOC relocations, we need to tell
1787 // the PLT resolver that there can be multiple TOCs.
1788 if (type == R_PPC64_REL24_NOTOC)
1789 ctx.target->ppc64DynamicSectionOpt = 0x2;
1790
1791 if (s.isInPlt(ctx)) {
1792 if (type == R_PPC64_REL24_NOTOC)
1793 return std::make_unique<PPC64R12SetupStub>(args&: ctx, args&: s,
1794 /*gotPlt=*/args: true);
1795 return std::make_unique<PPC64PltCallStub>(args&: ctx, args&: s);
1796 }
1797
1798 // This check looks at the st_other bits of the callee. If the value is 1
1799 // then the callee clobbers the TOC and we need an R2 save stub when RelType
1800 // is R_PPC64_REL14 or R_PPC64_REL24.
1801 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
1802 return std::make_unique<PPC64R2SaveStub>(args&: ctx, args&: s, args&: a);
1803
1804 if (type == R_PPC64_REL24_NOTOC)
1805 return std::make_unique<PPC64R12SetupStub>(args&: ctx, args&: s, /*gotPlt=*/args: false);
1806
1807 if (ctx.arg.picThunk)
1808 return std::make_unique<PPC64PILongBranchThunk>(args&: ctx, args&: s, args&: a);
1809
1810 return std::make_unique<PPC64PDLongBranchThunk>(args&: ctx, args&: s, args&: a);
1811}
1812
1813std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
1814 Relocation &rel) {
1815 Symbol &s = *rel.sym;
1816 int64_t a = rel.addend;
1817
1818 switch (ctx.arg.emachine) {
1819 case EM_AARCH64:
1820 return addThunkAArch64(ctx, sec: isec, type: rel.type, s, a);
1821 case EM_ARM:
1822 return addThunkArm(ctx, isec, reloc: rel.type, s, a);
1823 case EM_AVR:
1824 return addThunkAVR(ctx, type: rel.type, s, a);
1825 case EM_MIPS:
1826 return addThunkMips(ctx, type: rel.type, s);
1827 case EM_PPC:
1828 return addThunkPPC32(ctx, isec, rel, s);
1829 case EM_PPC64:
1830 return addThunkPPC64(ctx, type: rel.type, s, a);
1831 case EM_HEXAGON:
1832 return addThunkHexagon(ctx, isec, rel, s);
1833 default:
1834 llvm_unreachable(
1835 "add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC");
1836 }
1837}
1838
1839std::unique_ptr<Thunk> elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) {
1840 switch (ctx.arg.emachine) {
1841 case EM_AARCH64:
1842 return std::make_unique<AArch64BTILandingPadThunk>(args&: ctx, args&: s, args&: a);
1843 default:
1844 llvm_unreachable("add landing pad only supported for AArch64");
1845 }
1846}
1847