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.in.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
632uint64_t Thunk::getDestVA() const {
633 return destination.isInPlt(ctx) ? destination.getPltVA(ctx)
634 : destination.getVA(ctx, addend);
635}
636
637// AArch64 Thunk base class.
638bool AArch64Thunk::getMayUseShortThunk() {
639 if (!mayUseShortThunk)
640 return false;
641 uint64_t s = getDestVA();
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 = getDestVA();
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 ? landingPad->getVA(ctx, addend: 0) : getDestVA();
678 memcpy(dest: buf, src: data, n: sizeof(data));
679 ctx.target->relocateNoSym(loc: buf + 8, type: R_AARCH64_ABS64, val: s);
680}
681
682void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
683 addSymbol(name: ctx.saver.save(S: "__AArch64AbsLongThunk_" + destination.getName()),
684 type: STT_FUNC, value: 0, section&: isec);
685 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: isec);
686 tsec = &isec;
687 (void)getMayUseShortThunk();
688}
689
690void AArch64ABSLongThunk::addLongMapSyms() {
691 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
692 // The ldr in the long Thunk requires 8-byte alignment when
693 // unaligned accesses are disabled.
694 alignment = 8;
695}
696
697void AArch64ABSXOLongThunk::writeLong(uint8_t *buf) {
698 const uint8_t data[] = {
699 0x10, 0x00, 0x80, 0xd2, // movz x16, :abs_g0_nc:S, lsl #0
700 0x10, 0x00, 0xa0, 0xf2, // movk x16, :abs_g1_nc:S, lsl #16
701 0x10, 0x00, 0xc0, 0xf2, // movk x16, :abs_g2_nc:S, lsl #32
702 0x10, 0x00, 0xe0, 0xf2, // movk x16, :abs_g3:S, lsl #48
703 0x00, 0x02, 0x1f, 0xd6, // br x16
704 };
705 // If mayNeedLandingPad is true then destination is an
706 // AArch64BTILandingPadThunk that defines landingPad.
707 assert(!mayNeedLandingPad || landingPad != nullptr);
708 uint64_t s = mayNeedLandingPad ? landingPad->getVA(ctx, addend: 0) : getDestVA();
709 memcpy(dest: buf, src: data, n: sizeof(data));
710 ctx.target->relocateNoSym(loc: buf + 0, type: R_AARCH64_MOVW_UABS_G0_NC, val: s);
711 ctx.target->relocateNoSym(loc: buf + 4, type: R_AARCH64_MOVW_UABS_G1_NC, val: s);
712 ctx.target->relocateNoSym(loc: buf + 8, type: R_AARCH64_MOVW_UABS_G2_NC, val: s);
713 ctx.target->relocateNoSym(loc: buf + 12, type: R_AARCH64_MOVW_UABS_G3, val: s);
714}
715
716void AArch64ABSXOLongThunk::addSymbols(ThunkSection &sec) {
717 addSymbol(name: ctx.saver.save(S: "__AArch64AbsXOLongThunk_" + destination.getName()),
718 type: STT_FUNC, value: 0, section&: sec);
719 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: sec);
720}
721
722// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
723// using the small code model, including pc-relative ones. At time of writing
724// clang and gcc do not support the large code model for position independent
725// code so it is safe to use this for position independent thunks without
726// worrying about the destination being more than 4Gb away.
727void AArch64ADRPThunk::writeLong(uint8_t *buf) {
728 const uint8_t data[] = {
729 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
730 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
731 0x00, 0x02, 0x1f, 0xd6, // br x16
732 };
733 // if mayNeedLandingPad is true then destination is an
734 // AArch64BTILandingPadThunk that defines landingPad.
735 assert(!mayNeedLandingPad || landingPad != nullptr);
736 uint64_t s = mayNeedLandingPad ? landingPad->getVA(ctx, addend: 0) : getDestVA();
737 uint64_t p = getThunkTargetSym()->getVA(ctx);
738 memcpy(dest: buf, src: data, n: sizeof(data));
739 ctx.target->relocateNoSym(loc: buf, type: R_AARCH64_ADR_PREL_PG_HI21,
740 val: getAArch64Page(expr: s) - getAArch64Page(expr: p));
741 ctx.target->relocateNoSym(loc: buf + 4, type: R_AARCH64_ADD_ABS_LO12_NC, val: s);
742}
743
744void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
745 addSymbol(name: ctx.saver.save(S: "__AArch64ADRPThunk_" + destination.getName()),
746 type: STT_FUNC, value: 0, section&: isec);
747 addSymbol(name: "$x", type: STT_NOTYPE, value: 0, section&: isec);
748}
749
750void AArch64BTILandingPadThunk::addSymbols(ThunkSection &isec) {
751 addSymbol(name: ctx.saver.save(S: "__AArch64BTIThunk_" + 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::writeTo(uint8_t *buf) {
757 if (!getMayUseShortThunk()) {
758 writeLong(buf);
759 return;
760 }
761 write32(ctx, p: buf, v: 0xd503245f); // BTI c
762 // Control falls through to target in following section.
763}
764
765bool AArch64BTILandingPadThunk::getMayUseShortThunk() {
766 if (!mayUseShortThunk)
767 return false;
768 // If the target is the following instruction then we can fall
769 // through without the indirect branch.
770 uint64_t s = destination.getVA(ctx, addend);
771 uint64_t p = getThunkTargetSym()->getVA(ctx);
772 // This function is called before addresses are stable. We need to
773 // work out the range from the thunk to the next section but the
774 // address of the start of the next section depends on the size of
775 // the thunks in the previous pass. s - p + offset == 0 represents
776 // the first pass where the Thunk and following section are assigned
777 // the same offset. s - p <= 4 is the last Thunk in the Thunk
778 // Section.
779 mayUseShortThunk = (s - p + offset == 0 || s - p <= 4);
780 return mayUseShortThunk;
781}
782
783void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) {
784 uint64_t s = destination.getVA(ctx, addend);
785 uint64_t p = getThunkTargetSym()->getVA(ctx) + 4;
786 write32(ctx, p: buf, v: 0xd503245f); // BTI c
787 write32(ctx, p: buf + 4, v: 0x14000000); // B S
788 ctx.target->relocateNoSym(loc: buf + 4, type: R_AARCH64_CALL26, val: s - p);
789}
790
791// ARM Target Thunks
792static uint64_t getARMThunkDestVA(Ctx &ctx, const Symbol &s) {
793 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx);
794 return SignExtend64<32>(x: v);
795}
796
797// This function returns true if the target is not Thumb and is within 2^26, and
798// it has not previously returned false (see comment for mayUseShortThunk).
799bool ARMThunk::getMayUseShortThunk() {
800 if (!mayUseShortThunk)
801 return false;
802 uint64_t s = getARMThunkDestVA(ctx, s: destination);
803 if (s & 1) {
804 mayUseShortThunk = false;
805 addLongMapSyms();
806 return false;
807 }
808 uint64_t p = getThunkTargetSym()->getVA(ctx);
809 int64_t offset = s - p - 8;
810 mayUseShortThunk = llvm::isInt<26>(x: offset);
811 if (!mayUseShortThunk)
812 addLongMapSyms();
813 return mayUseShortThunk;
814}
815
816void ARMThunk::writeTo(uint8_t *buf) {
817 if (!getMayUseShortThunk()) {
818 writeLong(buf);
819 return;
820 }
821
822 uint64_t s = getARMThunkDestVA(ctx, s: destination);
823 uint64_t p = getThunkTargetSym()->getVA(ctx);
824 int64_t offset = s - p - 8;
825 write32(ctx, p: buf, v: 0xea000000); // b S
826 ctx.target->relocateNoSym(loc: buf, type: R_ARM_JUMP24, val: offset);
827}
828
829bool ARMThunk::isCompatibleWith(const InputSection &isec,
830 const Relocation &rel) const {
831 // v4T does not have BLX, so also deny R_ARM_THM_CALL
832 if (!ctx.arg.armHasBlx && rel.type == R_ARM_THM_CALL)
833 return false;
834
835 // Thumb branch relocations can't use BLX
836 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
837}
838
839// This function returns true if:
840// the target is Thumb
841// && is within branch range
842// && this function has not previously returned false
843// (see comment for mayUseShortThunk)
844// && the arch supports Thumb branch range extension.
845bool ThumbThunk::getMayUseShortThunk() {
846 if (!mayUseShortThunk)
847 return false;
848 uint64_t s = getARMThunkDestVA(ctx, s: destination);
849 // To use a short thunk the destination must be Thumb and the target must
850 // have the wide branch instruction B.w. This instruction is included when
851 // Thumb 2 is present, or in v8-M (and above) baseline architectures.
852 // armJ1J2BranchEncoding is available in all architectures with a profile and
853 // the one v6 CPU that implements Thumb 2 (Arm1156t2-s).
854 // Movt and Movw instructions require Thumb 2 or v8-M baseline.
855 if ((s & 1) == 0 || !ctx.arg.armJ1J2BranchEncoding ||
856 !ctx.arg.armHasMovtMovw) {
857 mayUseShortThunk = false;
858 addLongMapSyms();
859 return false;
860 }
861 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~1;
862 int64_t offset = s - p - 4;
863 mayUseShortThunk = llvm::isInt<25>(x: offset);
864 if (!mayUseShortThunk)
865 addLongMapSyms();
866 return mayUseShortThunk;
867}
868
869void ThumbThunk::writeTo(uint8_t *buf) {
870 if (!getMayUseShortThunk()) {
871 writeLong(buf);
872 return;
873 }
874
875 uint64_t s = getARMThunkDestVA(ctx, s: destination);
876 uint64_t p = getThunkTargetSym()->getVA(ctx);
877 int64_t offset = s - p - 4;
878 write16(ctx, p: buf + 0, v: 0xf000); // b.w S
879 write16(ctx, p: buf + 2, v: 0xb000);
880 ctx.target->relocateNoSym(loc: buf, type: R_ARM_THM_JUMP24, val: offset);
881}
882
883bool ThumbThunk::isCompatibleWith(const InputSection &isec,
884 const Relocation &rel) const {
885 // v4T does not have BLX, so also deny R_ARM_CALL
886 if (!ctx.arg.armHasBlx && rel.type == R_ARM_CALL)
887 return false;
888
889 // ARM branch relocations can't use BLX
890 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
891}
892
893void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
894 write32(ctx, p: buf + 0, v: 0xe300c000); // movw ip,:lower16:S
895 write32(ctx, p: buf + 4, v: 0xe340c000); // movt ip,:upper16:S
896 write32(ctx, p: buf + 8, v: 0xe12fff1c); // bx ip
897 uint64_t s = getARMThunkDestVA(ctx, s: destination);
898 ctx.target->relocateNoSym(loc: buf, type: R_ARM_MOVW_ABS_NC, val: s);
899 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_MOVT_ABS, val: s);
900}
901
902void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
903 addSymbol(name: ctx.saver.save(S: "__ARMv7ABSLongThunk_" + destination.getName()),
904 type: STT_FUNC, value: 0, section&: isec);
905 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
906}
907
908void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
909 write16(ctx, p: buf + 0, v: 0xf240); // movw ip, :lower16:S
910 write16(ctx, p: buf + 2, v: 0x0c00);
911 write16(ctx, p: buf + 4, v: 0xf2c0); // movt ip, :upper16:S
912 write16(ctx, p: buf + 6, v: 0x0c00);
913 write16(ctx, p: buf + 8, v: 0x4760); // bx ip
914 uint64_t s = getARMThunkDestVA(ctx, s: destination);
915 ctx.target->relocateNoSym(loc: buf, type: R_ARM_THM_MOVW_ABS_NC, val: s);
916 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_THM_MOVT_ABS, val: s);
917}
918
919void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
920 addSymbol(name: ctx.saver.save(S: "__Thumbv7ABSLongThunk_" + destination.getName()),
921 type: STT_FUNC, value: 1, section&: isec);
922 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
923}
924
925void ARMV7PILongThunk::writeLong(uint8_t *buf) {
926 write32(ctx, p: buf + 0,
927 v: 0xe30fcff0); // P: movw ip,:lower16:S - (P + (L1-P) + 8)
928 write32(ctx, p: buf + 4,
929 v: 0xe340c000); // movt ip,:upper16:S - (P + (L1-P) + 8)
930 write32(ctx, p: buf + 8, v: 0xe08cc00f); // L1: add ip, ip, pc
931 write32(ctx, p: buf + 12, v: 0xe12fff1c); // bx ip
932 uint64_t s = getARMThunkDestVA(ctx, s: destination);
933 uint64_t p = getThunkTargetSym()->getVA(ctx);
934 int64_t offset = s - p - 16;
935 ctx.target->relocateNoSym(loc: buf, type: R_ARM_MOVW_PREL_NC, val: offset);
936 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_MOVT_PREL, val: offset);
937}
938
939void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
940 addSymbol(name: ctx.saver.save(S: "__ARMV7PILongThunk_" + destination.getName()),
941 type: STT_FUNC, value: 0, section&: isec);
942 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
943}
944
945void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
946 write16(ctx, p: buf + 0, v: 0xf64f); // P: movw ip,:lower16:S - (P + (L1-P) + 4)
947 write16(ctx, p: buf + 2, v: 0x7cf4);
948 write16(ctx, p: buf + 4, v: 0xf2c0); // movt ip,:upper16:S - (P + (L1-P) + 4)
949 write16(ctx, p: buf + 6, v: 0x0c00);
950 write16(ctx, p: buf + 8, v: 0x44fc); // L1: add ip, pc
951 write16(ctx, p: buf + 10, v: 0x4760); // bx ip
952 uint64_t s = getARMThunkDestVA(ctx, s: destination);
953 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
954 int64_t offset = s - p - 12;
955 ctx.target->relocateNoSym(loc: buf, type: R_ARM_THM_MOVW_PREL_NC, val: offset);
956 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_THM_MOVT_PREL, val: offset);
957}
958
959void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
960 addSymbol(name: ctx.saver.save(S: "__ThumbV7PILongThunk_" + destination.getName()),
961 type: STT_FUNC, value: 1, section&: isec);
962 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
963}
964
965void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
966 // Most Thumb instructions cannot access the high registers r8 - r15. As the
967 // only register we can corrupt is r12 we must instead spill a low register
968 // to the stack to use as a scratch register. We push r1 even though we
969 // don't need to get some space to use for the return address.
970 write16(ctx, p: buf + 0, v: 0xb403); // push {r0, r1} ; Obtain scratch registers
971 write16(ctx, p: buf + 2, v: 0x4801); // ldr r0, [pc, #4] ; L1
972 write16(ctx, p: buf + 4, v: 0x9001); // str r0, [sp, #4] ; SP + 4 = S
973 write16(ctx, p: buf + 6, v: 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
974 write32(ctx, p: buf + 8, v: 0x00000000); // L1: .word S
975 uint64_t s = getARMThunkDestVA(ctx, s: destination);
976 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_ABS32, val: s);
977}
978
979void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
980 addSymbol(name: ctx.saver.save(S: "__Thumbv6MABSLongThunk_" + destination.getName()),
981 type: STT_FUNC, value: 1, section&: isec);
982 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
983 tsec = &isec;
984 (void)getMayUseShortThunk();
985}
986
987void ThumbV6MABSLongThunk::addLongMapSyms() {
988 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
989}
990
991void ThumbV6MABSXOLongThunk::writeLong(uint8_t *buf) {
992 // Most Thumb instructions cannot access the high registers r8 - r15. As the
993 // only register we can corrupt is r12 we must instead spill a low register
994 // to the stack to use as a scratch register. We push r1 even though we
995 // don't need to get some space to use for the return address.
996 write16(ctx, p: buf + 0, v: 0xb403); // push {r0, r1} ; Obtain scratch registers
997 write16(ctx, p: buf + 2, v: 0x2000); // movs r0, :upper8_15:S
998 write16(ctx, p: buf + 4, v: 0x0200); // lsls r0, r0, #8
999 write16(ctx, p: buf + 6, v: 0x3000); // adds r0, :upper0_7:S
1000 write16(ctx, p: buf + 8, v: 0x0200); // lsls r0, r0, #8
1001 write16(ctx, p: buf + 10, v: 0x3000); // adds r0, :lower8_15:S
1002 write16(ctx, p: buf + 12, v: 0x0200); // lsls r0, r0, #8
1003 write16(ctx, p: buf + 14, v: 0x3000); // adds r0, :lower0_7:S
1004 write16(ctx, p: buf + 16, v: 0x9001); // str r0, [sp, #4] ; SP + 4 = S
1005 write16(ctx, p: buf + 18,
1006 v: 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest
1007 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1008 ctx.target->relocateNoSym(loc: buf + 2, type: R_ARM_THM_ALU_ABS_G3, val: s);
1009 ctx.target->relocateNoSym(loc: buf + 6, type: R_ARM_THM_ALU_ABS_G2_NC, val: s);
1010 ctx.target->relocateNoSym(loc: buf + 10, type: R_ARM_THM_ALU_ABS_G1_NC, val: s);
1011 ctx.target->relocateNoSym(loc: buf + 14, type: R_ARM_THM_ALU_ABS_G0_NC, val: s);
1012}
1013
1014void ThumbV6MABSXOLongThunk::addSymbols(ThunkSection &isec) {
1015 addSymbol(name: ctx.saver.save(S: "__Thumbv6MABSXOLongThunk_" + destination.getName()),
1016 type: STT_FUNC, value: 1, section&: isec);
1017 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1018}
1019
1020void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
1021 // Most Thumb instructions cannot access the high registers r8 - r15. As the
1022 // only register we can corrupt is ip (r12) we must instead spill a low
1023 // register to the stack to use as a scratch register.
1024 write16(ctx, p: buf + 0,
1025 v: 0xb401); // P: push {r0} ; Obtain scratch register
1026 write16(ctx, p: buf + 2, v: 0x4802); // ldr r0, [pc, #8] ; L2
1027 write16(ctx, p: buf + 4, v: 0x4684); // mov ip, r0 ; high to low register
1028 write16(ctx, p: buf + 6,
1029 v: 0xbc01); // pop {r0} ; restore scratch register
1030 write16(ctx, p: buf + 8, v: 0x44e7); // L1: add pc, ip ; transfer control
1031 write16(ctx, p: buf + 10,
1032 v: 0x46c0); // nop ; pad to 4-byte boundary
1033 write32(ctx, p: buf + 12, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 4)
1034 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1035 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1036 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_REL32, val: s - p - 12);
1037}
1038
1039void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
1040 addSymbol(name: ctx.saver.save(S: "__Thumbv6MPILongThunk_" + destination.getName()),
1041 type: STT_FUNC, value: 1, section&: isec);
1042 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1043 tsec = &isec;
1044 (void)getMayUseShortThunk();
1045}
1046
1047void ThumbV6MPILongThunk::addLongMapSyms() {
1048 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1049}
1050
1051void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
1052 write32(ctx, p: buf + 0, v: 0xe51ff004); // ldr pc, [pc,#-4] ; L1
1053 write32(ctx, p: buf + 4, v: 0x00000000); // L1: .word S
1054 ctx.target->relocateNoSym(loc: buf + 4, type: R_ARM_ABS32,
1055 val: getARMThunkDestVA(ctx, s: destination));
1056}
1057
1058void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
1059 addSymbol(name: ctx.saver.save(S: "__ARMv5LongLdrPcThunk_" + destination.getName()),
1060 type: STT_FUNC, value: 0, section&: isec);
1061 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1062 tsec = &isec;
1063 (void)getMayUseShortThunk();
1064}
1065
1066void ARMV5LongLdrPcThunk::addLongMapSyms() {
1067 addSymbol(name: "$d", type: STT_NOTYPE, value: 4, section&: *tsec);
1068}
1069
1070void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
1071 write32(ctx, p: buf + 0, v: 0xe59fc000); // ldr r12, [pc] ; L1
1072 write32(ctx, p: buf + 4, v: 0xe12fff1c); // bx r12
1073 write32(ctx, p: buf + 8, v: 0x00000000); // L1: .word S
1074 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_ABS32,
1075 val: getARMThunkDestVA(ctx, s: destination));
1076}
1077
1078void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
1079 addSymbol(name: ctx.saver.save(S: "__ARMv4ABSLongBXThunk_" + destination.getName()),
1080 type: STT_FUNC, value: 0, section&: isec);
1081 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1082 tsec = &isec;
1083 (void)getMayUseShortThunk();
1084}
1085
1086void ARMV4ABSLongBXThunk::addLongMapSyms() {
1087 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
1088}
1089
1090void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
1091 write16(ctx, p: buf + 0, v: 0x4778); // bx pc
1092 write16(ctx, p: buf + 2,
1093 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1094 write32(ctx, p: buf + 4, v: 0xe51ff004); // ldr pc, [pc, #-4] ; L1
1095 write32(ctx, p: buf + 8, v: 0x00000000); // L1: .word S
1096 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_ABS32,
1097 val: getARMThunkDestVA(ctx, s: destination));
1098}
1099
1100void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
1101 addSymbol(name: ctx.saver.save(S: "__Thumbv4ABSLongBXThunk_" + destination.getName()),
1102 type: STT_FUNC, value: 1, section&: isec);
1103 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1104 tsec = &isec;
1105 (void)getMayUseShortThunk();
1106}
1107
1108void ThumbV4ABSLongBXThunk::addLongMapSyms() {
1109 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1110 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
1111}
1112
1113void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
1114 write16(ctx, p: buf + 0, v: 0x4778); // bx pc
1115 write16(ctx, p: buf + 2,
1116 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1117 write32(ctx, p: buf + 4, v: 0xe59fc000); // ldr r12, [pc] ; L1
1118 write32(ctx, p: buf + 8, v: 0xe12fff1c); // bx r12
1119 write32(ctx, p: buf + 12, v: 0x00000000); // L1: .word S
1120 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_ABS32,
1121 val: getARMThunkDestVA(ctx, s: destination));
1122}
1123
1124void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
1125 addSymbol(name: ctx.saver.save(S: "__Thumbv4ABSLongThunk_" + destination.getName()),
1126 type: STT_FUNC, value: 1, section&: isec);
1127 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1128 tsec = &isec;
1129 (void)getMayUseShortThunk();
1130}
1131
1132void ThumbV4ABSLongThunk::addLongMapSyms() {
1133 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1134 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1135}
1136
1137void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
1138 write32(ctx, p: buf + 0, v: 0xe59fc004); // P: ldr ip, [pc,#4] ; L2
1139 write32(ctx, p: buf + 4, v: 0xe08fc00c); // L1: add ip, pc, ip
1140 write32(ctx, p: buf + 8, v: 0xe12fff1c); // bx ip
1141 write32(ctx, p: buf + 12, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1142 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1143 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1144 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_REL32, val: s - p - 12);
1145}
1146
1147void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1148 addSymbol(name: ctx.saver.save(S: "__ARMv4PILongBXThunk_" + destination.getName()),
1149 type: STT_FUNC, value: 0, section&: isec);
1150 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1151 tsec = &isec;
1152 (void)getMayUseShortThunk();
1153}
1154
1155void ARMV4PILongBXThunk::addLongMapSyms() {
1156 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1157}
1158
1159void ARMV4PILongThunk::writeLong(uint8_t *buf) {
1160 write32(ctx, p: buf + 0, v: 0xe59fc000); // P: ldr ip, [pc] ; L2
1161 write32(ctx, p: buf + 4, v: 0xe08ff00c); // L1: add pc, pc, r12
1162 write32(ctx, p: buf + 8, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1163 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1164 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1165 ctx.target->relocateNoSym(loc: buf + 8, type: R_ARM_REL32, val: s - p - 12);
1166}
1167
1168void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
1169 addSymbol(name: ctx.saver.save(S: "__ARMv4PILongThunk_" + destination.getName()),
1170 type: STT_FUNC, value: 0, section&: isec);
1171 addSymbol(name: "$a", type: STT_NOTYPE, value: 0, section&: isec);
1172 tsec = &isec;
1173 (void)getMayUseShortThunk();
1174}
1175
1176void ARMV4PILongThunk::addLongMapSyms() {
1177 addSymbol(name: "$d", type: STT_NOTYPE, value: 8, section&: *tsec);
1178}
1179
1180void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
1181 write16(ctx, p: buf + 0, v: 0x4778); // P: bx pc
1182 write16(ctx, p: buf + 2,
1183 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1184 write32(ctx, p: buf + 4, v: 0xe59fc000); // ldr r12, [pc] ; L2
1185 write32(ctx, p: buf + 8, v: 0xe08cf00f); // L1: add pc, r12, pc
1186 write32(ctx, p: buf + 12, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1187 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1188 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1189 ctx.target->relocateNoSym(loc: buf + 12, type: R_ARM_REL32, val: s - p - 16);
1190}
1191
1192void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
1193 addSymbol(name: ctx.saver.save(S: "__Thumbv4PILongBXThunk_" + destination.getName()),
1194 type: STT_FUNC, value: 1, section&: isec);
1195 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1196 tsec = &isec;
1197 (void)getMayUseShortThunk();
1198}
1199
1200void ThumbV4PILongBXThunk::addLongMapSyms() {
1201 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1202 addSymbol(name: "$d", type: STT_NOTYPE, value: 12, section&: *tsec);
1203}
1204
1205void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
1206 write16(ctx, p: buf + 0, v: 0x4778); // P: bx pc
1207 write16(ctx, p: buf + 2,
1208 v: 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc
1209 write32(ctx, p: buf + 4, v: 0xe59fc004); // ldr ip, [pc,#4] ; L2
1210 write32(ctx, p: buf + 8, v: 0xe08fc00c); // L1: add ip, pc, ip
1211 write32(ctx, p: buf + 12, v: 0xe12fff1c); // bx ip
1212 write32(ctx, p: buf + 16, v: 0x00000000); // L2: .word S - (P + (L1 - P) + 8)
1213 uint64_t s = getARMThunkDestVA(ctx, s: destination);
1214 uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1;
1215 ctx.target->relocateNoSym(loc: buf + 16, type: R_ARM_REL32, val: s - p - 16);
1216}
1217
1218void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
1219 addSymbol(name: ctx.saver.save(S: "__Thumbv4PILongThunk_" + destination.getName()),
1220 type: STT_FUNC, value: 1, section&: isec);
1221 addSymbol(name: "$t", type: STT_NOTYPE, value: 0, section&: isec);
1222 tsec = &isec;
1223 (void)getMayUseShortThunk();
1224}
1225
1226void ThumbV4PILongThunk::addLongMapSyms() {
1227 addSymbol(name: "$a", type: STT_NOTYPE, value: 4, section&: *tsec);
1228 addSymbol(name: "$d", type: STT_NOTYPE, value: 16, section&: *tsec);
1229}
1230
1231// Use the long jump which covers a range up to 8MiB.
1232void AVRThunk::writeTo(uint8_t *buf) {
1233 write32(ctx, p: buf, v: 0x940c); // jmp func
1234 ctx.target->relocateNoSym(loc: buf, type: R_AVR_CALL, val: destination.getVA(ctx));
1235}
1236
1237void AVRThunk::addSymbols(ThunkSection &isec) {
1238 addSymbol(name: ctx.saver.save(S: "__AVRThunk_" + destination.getName()), type: STT_FUNC, value: 0,
1239 section&: isec);
1240}
1241
1242// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
1243void MipsThunk::writeTo(uint8_t *buf) {
1244 uint64_t s = destination.getVA(ctx);
1245 write32(ctx, p: buf, v: 0x3c190000); // lui $25, %hi(func)
1246 write32(ctx, p: buf + 4, v: 0x08000000 | (s >> 2)); // j func
1247 write32(ctx, p: buf + 8, v: 0x27390000); // addiu $25, $25, %lo(func)
1248 write32(ctx, p: buf + 12, v: 0x00000000); // nop
1249 ctx.target->relocateNoSym(loc: buf, type: R_MIPS_HI16, val: s);
1250 ctx.target->relocateNoSym(loc: buf + 8, type: R_MIPS_LO16, val: s);
1251}
1252
1253void MipsThunk::addSymbols(ThunkSection &isec) {
1254 addSymbol(name: ctx.saver.save(S: "__LA25Thunk_" + destination.getName()), type: STT_FUNC, value: 0,
1255 section&: isec);
1256}
1257
1258InputSection *MipsThunk::getTargetInputSection() const {
1259 auto &dr = cast<Defined>(Val&: destination);
1260 return dyn_cast<InputSection>(Val: dr.section);
1261}
1262
1263// Write microMIPS R2-R5 LA25 thunk code
1264// to call PIC function from the non-PIC one.
1265void MicroMipsThunk::writeTo(uint8_t *buf) {
1266 uint64_t s = destination.getVA(ctx);
1267 write16(ctx, p: buf, v: 0x41b9); // lui $25, %hi(func)
1268 write16(ctx, p: buf + 4, v: 0xd400); // j func
1269 write16(ctx, p: buf + 8, v: 0x3339); // addiu $25, $25, %lo(func)
1270 write16(ctx, p: buf + 12, v: 0x0c00); // nop
1271 ctx.target->relocateNoSym(loc: buf, type: R_MICROMIPS_HI16, val: s);
1272 ctx.target->relocateNoSym(loc: buf + 4, type: R_MICROMIPS_26_S1, val: s);
1273 ctx.target->relocateNoSym(loc: buf + 8, type: R_MICROMIPS_LO16, val: s);
1274}
1275
1276void MicroMipsThunk::addSymbols(ThunkSection &isec) {
1277 Defined *d =
1278 addSymbol(name: ctx.saver.save(S: "__microLA25Thunk_" + destination.getName()),
1279 type: STT_FUNC, value: 0, section&: isec);
1280 d->stOther |= STO_MIPS_MICROMIPS;
1281}
1282
1283InputSection *MicroMipsThunk::getTargetInputSection() const {
1284 auto &dr = cast<Defined>(Val&: destination);
1285 return dyn_cast<InputSection>(Val: dr.section);
1286}
1287
1288// Write microMIPS R6 LA25 thunk code
1289// to call PIC function from the non-PIC one.
1290void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
1291 uint64_t s = destination.getVA(ctx);
1292 uint64_t p = getThunkTargetSym()->getVA(ctx);
1293 write16(ctx, p: buf, v: 0x1320); // lui $25, %hi(func)
1294 write16(ctx, p: buf + 4, v: 0x3339); // addiu $25, $25, %lo(func)
1295 write16(ctx, p: buf + 8, v: 0x9400); // bc func
1296 ctx.target->relocateNoSym(loc: buf, type: R_MICROMIPS_HI16, val: s);
1297 ctx.target->relocateNoSym(loc: buf + 4, type: R_MICROMIPS_LO16, val: s);
1298 ctx.target->relocateNoSym(loc: buf + 8, type: R_MICROMIPS_PC26_S1, val: s - p - 12);
1299}
1300
1301void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
1302 Defined *d =
1303 addSymbol(name: ctx.saver.save(S: "__microLA25Thunk_" + destination.getName()),
1304 type: STT_FUNC, value: 0, section&: isec);
1305 d->stOther |= STO_MIPS_MICROMIPS;
1306}
1307
1308InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
1309 auto &dr = cast<Defined>(Val&: destination);
1310 return dyn_cast<InputSection>(Val: dr.section);
1311}
1312
1313void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t p,
1314 uint64_t gotPltVA, const InputFile *file,
1315 std::optional<int64_t> addend) {
1316 if (!ctx.arg.isPic) {
1317 write32(ctx, p: buf + 0, v: 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
1318 write32(ctx, p: buf + 4, v: 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
1319 write32(ctx, p: buf + 8, v: 0x7d6903a6); // mtctr r11
1320 write32(ctx, p: buf + 12, v: 0x4e800420); // bctr
1321 return;
1322 }
1323 uint32_t offset;
1324 uint32_t reg;
1325 uint64_t written = 0;
1326 if (!addend) {
1327 // We're a (position-independent) IPLT entry, so cannot assume anything
1328 // about what value the caller left in r30 as this could be an indirect
1329 // call.
1330 write32(ctx, p: buf + 0, v: 0x7c0802a6); // mflr r0
1331 write32(ctx, p: buf + 4, v: 0x429f0005); // bcl 20, 31, 1f
1332 write32(ctx, p: buf + 8, v: 0x7d6802a6); // 1: mflr r11
1333 write32(ctx, p: buf + 12, v: 0x7c0803a6); // mtlr r0
1334 offset = gotPltVA - p - 8;
1335 reg = 11;
1336 written = 16;
1337 } else if (*addend >= 0x8000) {
1338 // The stub loads an address relative to r30 (.got2+Addend). Addend is
1339 // almost always 0x8000. The address of .got2 is different in another object
1340 // file, so a stub cannot be shared.
1341 reg = 30;
1342 offset = gotPltVA -
1343 (ctx.in.ppc32Got2->getParent()->getVA() +
1344 (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + *addend);
1345 } else {
1346 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
1347 // currently the address of .got).
1348 reg = 30;
1349 offset = gotPltVA - ctx.in.got->getVA();
1350 }
1351 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
1352 if (ha == 0) {
1353 write32(ctx, p: buf + written + 0,
1354 v: 0x81600000 | (reg << 16) | l); // lwz r11,l(r[11|30])
1355 write32(ctx, p: buf + written + 4, v: 0x7d6903a6); // mtctr r11
1356 write32(ctx, p: buf + written + 8, v: 0x4e800420); // bctr
1357 write32(ctx, p: buf + written + 12, v: 0x60000000); // nop
1358 } else {
1359 write32(ctx, p: buf + written + 0,
1360 v: 0x3d600000 | (reg << 16) | ha); // addis r11,r[11|30],ha
1361 write32(ctx, p: buf + written + 4, v: 0x816b0000 | l); // lwz r11,l(r11)
1362 write32(ctx, p: buf + written + 8, v: 0x7d6903a6); // mtctr r11
1363 write32(ctx, p: buf + written + 12, v: 0x4e800420); // bctr
1364 }
1365}
1366
1367void PPC32PltCallStub::writeTo(uint8_t *buf) {
1368 writePPC32PltCallStub(ctx, buf, p: getThunkTargetSym()->getVA(ctx),
1369 gotPltVA: destination.getGotPltVA(ctx), file, addend);
1370}
1371
1372void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
1373 std::string buf;
1374 raw_string_ostream os(buf);
1375 os << format_hex_no_prefix(N: addend, Width: 8);
1376 if (!ctx.arg.isPic)
1377 os << ".plt_call32.";
1378 else if (addend >= 0x8000)
1379 os << ".got2.plt_pic32.";
1380 else
1381 os << ".plt_pic32.";
1382 os << destination.getName();
1383 addSymbol(name: ctx.saver.save(S: buf), type: STT_FUNC, value: 0, section&: isec);
1384}
1385
1386bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
1387 const Relocation &rel) const {
1388 return !ctx.arg.isPic || (isec.file == file && rel.addend == addend);
1389}
1390
1391void PPC32LongThunk::addSymbols(ThunkSection &isec) {
1392 addSymbol(name: ctx.saver.save(S: "__LongThunk_" + destination.getName()), type: STT_FUNC, value: 0,
1393 section&: isec);
1394}
1395
1396void PPC32LongThunk::writeTo(uint8_t *buf) {
1397 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
1398 auto lo = [](uint32_t v) -> uint16_t { return v; };
1399 uint32_t d = destination.getVA(ctx, addend);
1400 if (ctx.arg.isPic) {
1401 uint32_t off = d - (getThunkTargetSym()->getVA(ctx) + 8);
1402 write32(ctx, p: buf + 0, v: 0x7c0802a6); // mflr r12,0
1403 write32(ctx, p: buf + 4, v: 0x429f0005); // bcl r20,r31,.+4
1404 write32(ctx, p: buf + 8, v: 0x7d8802a6); // mtctr r12
1405 write32(ctx, p: buf + 12, v: 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
1406 write32(ctx, p: buf + 16, v: 0x398c0000 | lo(off)); // addi r12,r12,off@l
1407 write32(ctx, p: buf + 20, v: 0x7c0803a6); // mtlr r0
1408 buf += 24;
1409 } else {
1410 write32(ctx, p: buf + 0, v: 0x3d800000 | ha(d)); // lis r12,d@ha
1411 write32(ctx, p: buf + 4, v: 0x398c0000 | lo(d)); // addi r12,r12,d@l
1412 buf += 8;
1413 }
1414 write32(ctx, p: buf + 0, v: 0x7d8903a6); // mtctr r12
1415 write32(ctx, p: buf + 4, v: 0x4e800420); // bctr
1416}
1417
1418void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, uint64_t p,
1419 uint64_t addr, bool toc) {
1420 uint64_t offset;
1421 uint32_t reg;
1422 if (toc) {
1423 offset = addr - getPPC64TocBase(ctx);
1424 reg = 2;
1425 } else {
1426 offset = addr - p;
1427 reg = 12;
1428 }
1429 uint16_t offHa = (offset + 0x8000) >> 16;
1430 uint16_t offLo = offset & 0xffff;
1431
1432 write32(ctx, p: buf + 0,
1433 v: 0x3d800000 | (reg << 16) | offHa); // addis r12, r[2|12], OffHa
1434 write32(ctx, p: buf + 4, v: 0xe98c0000 | offLo); // ld r12, OffLo(r12)
1435 write32(ctx, p: buf + 8, v: 0x7d8903a6); // mtctr r12
1436 write32(ctx, p: buf + 12, v: 0x4e800420); // bctr
1437}
1438
1439void PPC64PltCallStub::writeTo(uint8_t *buf) {
1440 // Save the TOC pointer to the save-slot reserved in the call frame.
1441 write32(ctx, p: buf + 0, v: 0xf8410018); // std r2,24(r1)
1442 writePPC64LoadAndBranch(ctx, buf: buf + 4, p: getThunkTargetSym()->getVA(ctx) + 4,
1443 addr: destination.getGotPltVA(ctx));
1444}
1445
1446void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
1447 Defined *s = addSymbol(name: ctx.saver.save(S: "__plt_" + destination.getName()),
1448 type: STT_FUNC, value: 0, section&: isec);
1449 s->setNeedsTocRestore(true);
1450 s->file = destination.file;
1451}
1452
1453bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
1454 const Relocation &rel) const {
1455 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1456}
1457
1458void PPC64R2SaveStub::writeTo(uint8_t *buf) {
1459 const int64_t offset = computeOffset();
1460 write32(ctx, p: buf + 0, v: 0xf8410018); // std r2,24(r1)
1461 // The branch offset needs to fit in 26 bits.
1462 if (getMayUseShortThunk()) {
1463 write32(ctx, p: buf + 4, v: 0x48000000 | (offset & 0x03fffffc)); // b <offset>
1464 } else if (isInt<34>(x: offset)) {
1465 int nextInstOffset;
1466 uint64_t tocOffset = destination.getVA(ctx) - getPPC64TocBase(ctx);
1467 if (tocOffset >> 16 > 0) {
1468 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
1469 const uint64_t addis =
1470 ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
1471 write32(ctx, p: buf + 4, v: addis); // addis r12, r2 , top of offset
1472 write32(ctx, p: buf + 8, v: addi); // addi r12, r12, bottom of offset
1473 nextInstOffset = 12;
1474 } else {
1475 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
1476 write32(ctx, p: buf + 4, v: addi); // addi r12, r2, offset
1477 nextInstOffset = 8;
1478 }
1479 write32(ctx, p: buf + nextInstOffset, v: MTCTR_R12); // mtctr r12
1480 write32(ctx, p: buf + nextInstOffset + 4, v: BCTR); // bctr
1481 } else {
1482 ctx.in.ppc64LongBranchTarget->addEntry(sym: &destination, addend);
1483 const uint64_t addr =
1484 ctx.in.ppc64LongBranchTarget->getEntryVA(sym: &destination, addend);
1485 writePPC64LoadAndBranch(ctx, buf: buf + 4, p: getThunkTargetSym()->getVA(ctx) + 4,
1486 addr);
1487 }
1488}
1489
1490void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
1491 Defined *s = addSymbol(name: ctx.saver.save(S: "__toc_save_" + destination.getName()),
1492 type: STT_FUNC, value: 0, section&: isec);
1493 s->setNeedsTocRestore(true);
1494}
1495
1496bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
1497 const Relocation &rel) const {
1498 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1499}
1500
1501void PPC64R12SetupStub::writeTo(uint8_t *buf) {
1502 int64_t offset =
1503 (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA(ctx)) -
1504 getThunkTargetSym()->getVA(ctx);
1505 if (!isInt<34>(x: offset))
1506 reportRangeError(ctx, loc: buf, v: offset, n: 34, sym: destination,
1507 msg: "R12 setup stub offset");
1508
1509 int nextInstOffset;
1510 if (ctx.arg.power10Stubs) {
1511 const uint64_t imm = (((offset >> 16) & 0x3ffff) << 32) | (offset & 0xffff);
1512 // pld 12, func@plt@pcrel or paddi r12, 0, func@pcrel
1513 writePrefixedInst(ctx, loc: buf,
1514 insn: (gotPlt ? PLD_R12_NO_DISP : PADDI_R12_NO_DISP) | imm);
1515 nextInstOffset = 8;
1516 } else {
1517 uint32_t off = offset - 8;
1518 write32(ctx, p: buf + 0, v: 0x7d8802a6); // mflr 12
1519 write32(ctx, p: buf + 4, v: 0x429f0005); // bcl 20,31,.+4
1520 write32(ctx, p: buf + 8, v: 0x7d6802a6); // mflr 11
1521 write32(ctx, p: buf + 12, v: 0x7d8803a6); // mtlr 12
1522 write32(ctx, p: buf + 16,
1523 v: 0x3d8b0000 | ((off + 0x8000) >> 16)); // addis 12,11,off@ha
1524 if (gotPlt)
1525 write32(ctx, p: buf + 20, v: 0xe98c0000 | (off & 0xffff)); // ld 12, off@l(12)
1526 else
1527 write32(ctx, p: buf + 20, v: 0x398c0000 | (off & 0xffff)); // addi 12,12,off@l
1528 nextInstOffset = 24;
1529 }
1530 write32(ctx, p: buf + nextInstOffset, v: MTCTR_R12); // mtctr r12
1531 write32(ctx, p: buf + nextInstOffset + 4, v: BCTR); // bctr
1532}
1533
1534void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
1535 addSymbol(name: ctx.saver.save(S: (gotPlt ? "__plt_pcrel_" : "__gep_setup_") +
1536 destination.getName()),
1537 type: STT_FUNC, value: 0, section&: isec);
1538}
1539
1540bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
1541 const Relocation &rel) const {
1542 return rel.type == R_PPC64_REL24_NOTOC;
1543}
1544
1545void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
1546 uint64_t addr =
1547 ctx.in.ppc64LongBranchTarget->getEntryVA(sym: &destination, addend);
1548 writePPC64LoadAndBranch(ctx, buf, p: getThunkTargetSym()->getVA(ctx), addr);
1549}
1550
1551void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
1552 addSymbol(name: ctx.saver.save(S: "__long_branch_" + destination.getName()), type: STT_FUNC,
1553 value: 0, section&: isec);
1554}
1555
1556bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
1557 const Relocation &rel) const {
1558 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1559}
1560
1561// Hexagon Target Thunks
1562static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {
1563 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, addend: a);
1564 return SignExtend64<32>(x: v);
1565}
1566
1567void HexagonThunk::writeTo(uint8_t *buf) {
1568 uint64_t s = getHexagonThunkDestVA(ctx, s: destination, a: addend);
1569 uint64_t p = getThunkTargetSym()->getVA(ctx);
1570
1571 if (ctx.arg.isPic) {
1572 write32(ctx, p: buf + 0, v: 0x00004000); // { immext(#0)
1573 ctx.target->relocateNoSym(loc: buf, type: R_HEX_B32_PCREL_X, val: s - p);
1574 write32(ctx, p: buf + 4, v: 0x6a49c00e); // r14 = add(pc,##0) }
1575 ctx.target->relocateNoSym(loc: buf + 4, type: R_HEX_6_PCREL_X, val: s - p);
1576
1577 write32(ctx, p: buf + 8, v: 0x528ec000); // { jumpr r14 }
1578 } else {
1579 write32(ctx, p: buf + 0, v: 0x00004000); // { immext
1580 ctx.target->relocateNoSym(loc: buf, type: R_HEX_B32_PCREL_X, val: s - p);
1581 write32(ctx, p: buf + 4, v: 0x5800c000); // jump <> }
1582 ctx.target->relocateNoSym(loc: buf + 4, type: R_HEX_B22_PCREL_X, val: s - p);
1583 }
1584}
1585void HexagonThunk::addSymbols(ThunkSection &isec) {
1586 Symbol *enclosing = isec.getEnclosingSymbol(offset: relOffset);
1587 StringRef src = enclosing ? enclosing->getName() : isec.name;
1588
1589 addSymbol(
1590 name: saver().save(S: "__hexagon_thunk_" + destination.getName() + "_from_" + src),
1591 type: STT_FUNC, value: 0, section&: isec);
1592}
1593
1594Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
1595 : ctx(ctx), destination(d), addend(a), offset(0) {
1596 destination.thunkAccessed = true;
1597}
1598
1599Thunk::~Thunk() = default;
1600
1601static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, const InputSection &sec,
1602 RelType type, Symbol &s,
1603 int64_t a) {
1604 assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
1605 type));
1606 bool mayNeedLandingPad =
1607 (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
1608 !isAArch64BTILandingPad(ctx, s, a);
1609 if (ctx.arg.picThunk)
1610 return std::make_unique<AArch64ADRPThunk>(args&: ctx, args&: s, args&: a, args&: mayNeedLandingPad);
1611 if (sec.getParent()->flags & SHF_AARCH64_PURECODE)
1612 return std::make_unique<AArch64ABSXOLongThunk>(args&: ctx, args&: s, args&: a,
1613 args&: mayNeedLandingPad);
1614 return std::make_unique<AArch64ABSLongThunk>(args&: ctx, args&: s, args&: a, args&: mayNeedLandingPad);
1615}
1616
1617// Creates a thunk for long branches or Thumb-ARM interworking.
1618// Arm Architectures v4t does not support Thumb2 technology, and does not
1619// support BLX or LDR Arm/Thumb state switching. This means that
1620// - MOVT and MOVW instructions cannot be used.
1621// - We can't rewrite BL in place to BLX. We will need thunks.
1622//
1623// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
1624// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
1625static std::unique_ptr<Thunk> addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s,
1626 int64_t a) {
1627 bool thumb_target = s.getVA(ctx, addend: a) & 1;
1628
1629 switch (reloc) {
1630 case R_ARM_PC24:
1631 case R_ARM_PLT32:
1632 case R_ARM_JUMP24:
1633 case R_ARM_CALL:
1634 if (ctx.arg.picThunk) {
1635 if (thumb_target)
1636 return std::make_unique<ARMV4PILongBXThunk>(args&: ctx, args&: s, args&: a);
1637 return std::make_unique<ARMV4PILongThunk>(args&: ctx, args&: s, args&: a);
1638 }
1639 if (thumb_target)
1640 return std::make_unique<ARMV4ABSLongBXThunk>(args&: ctx, args&: s, args&: a);
1641 return std::make_unique<ARMV5LongLdrPcThunk>(args&: ctx, args&: s, args&: a);
1642 case R_ARM_THM_CALL:
1643 if (ctx.arg.picThunk) {
1644 if (thumb_target)
1645 return std::make_unique<ThumbV4PILongThunk>(args&: ctx, args&: s, args&: a);
1646 return std::make_unique<ThumbV4PILongBXThunk>(args&: ctx, args&: s, args&: a);
1647 }
1648 if (thumb_target)
1649 return std::make_unique<ThumbV4ABSLongThunk>(args&: ctx, args&: s, args&: a);
1650 return std::make_unique<ThumbV4ABSLongBXThunk>(args&: ctx, args&: s, args&: a);
1651 }
1652 Fatal(ctx) << "relocation " << reloc << " to " << &s
1653 << " not supported for Armv4 or Armv4T target";
1654 llvm_unreachable("");
1655}
1656
1657// Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
1658// Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
1659// - MOVT and MOVW instructions cannot be used
1660// - Only Thumb relocation that can generate a Thunk is a BL, this can always
1661// be transformed into a BLX
1662static std::unique_ptr<Thunk> addThunkArmv5v6(Ctx &ctx, RelType reloc,
1663 Symbol &s, int64_t a) {
1664 switch (reloc) {
1665 case R_ARM_PC24:
1666 case R_ARM_PLT32:
1667 case R_ARM_JUMP24:
1668 case R_ARM_CALL:
1669 case R_ARM_THM_CALL:
1670 if (ctx.arg.picThunk)
1671 return std::make_unique<ARMV4PILongBXThunk>(args&: ctx, args&: s, args&: a);
1672 return std::make_unique<ARMV5LongLdrPcThunk>(args&: ctx, args&: s, args&: a);
1673 }
1674 Fatal(ctx) << "relocation " << reloc << " to " << &s
1675 << " not supported for Armv5 or Armv6 targets";
1676 llvm_unreachable("");
1677}
1678
1679// Create a thunk for Thumb long branch on V6-M.
1680// Arm Architecture v6-M only supports Thumb instructions. This means
1681// - MOVT and MOVW instructions cannot be used.
1682// - Only a limited number of instructions can access registers r8 and above
1683// - No interworking support is needed (all Thumb).
1684static std::unique_ptr<Thunk> addThunkV6M(Ctx &ctx, const InputSection &isec,
1685 RelType reloc, Symbol &s, int64_t a) {
1686 const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE;
1687 switch (reloc) {
1688 case R_ARM_THM_JUMP19:
1689 case R_ARM_THM_JUMP24:
1690 case R_ARM_THM_CALL:
1691 if (ctx.arg.isPic) {
1692 if (!isPureCode)
1693 return std::make_unique<ThumbV6MPILongThunk>(args&: ctx, args&: s, args&: a);
1694
1695 Fatal(ctx)
1696 << "relocation " << reloc << " to " << &s
1697 << " not supported for Armv6-M targets for position independent"
1698 " and execute only code";
1699 llvm_unreachable("");
1700 }
1701 if (isPureCode)
1702 return std::make_unique<ThumbV6MABSXOLongThunk>(args&: ctx, args&: s, args&: a);
1703 return std::make_unique<ThumbV6MABSLongThunk>(args&: ctx, args&: s, args&: a);
1704 }
1705 Fatal(ctx) << "relocation " << reloc << " to " << &s
1706 << " not supported for Armv6-M targets";
1707 llvm_unreachable("");
1708}
1709
1710// Creates a thunk for Thumb-ARM interworking or branch range extension.
1711static std::unique_ptr<Thunk> addThunkArm(Ctx &ctx, const InputSection &isec,
1712 RelType reloc, Symbol &s, int64_t a) {
1713 // Decide which Thunk is needed based on:
1714 // Available instruction set
1715 // - An Arm Thunk can only be used if Arm state is available.
1716 // - A Thumb Thunk can only be used if Thumb state is available.
1717 // - Can only use a Thunk if it uses instructions that the Target supports.
1718 // Relocation is branch or branch and link
1719 // - Branch instructions cannot change state, can only select Thunk that
1720 // starts in the same state as the caller.
1721 // - Branch and link relocations can change state, can select Thunks from
1722 // either Arm or Thumb.
1723 // Position independent Thunks if we require position independent code.
1724 // Execute Only Thunks if the output section is execute only code.
1725
1726 // Handle architectures that have restrictions on the instructions that they
1727 // can use in Thunks. The flags below are set by reading the BuildAttributes
1728 // of the input objects. InputFiles.cpp contains the mapping from ARM
1729 // architecture to flag.
1730 if (!ctx.arg.armHasMovtMovw) {
1731 if (ctx.arg.armJ1J2BranchEncoding)
1732 return addThunkV6M(ctx, isec, reloc, s, a);
1733 if (ctx.arg.armHasBlx)
1734 return addThunkArmv5v6(ctx, reloc, s, a);
1735 return addThunkArmv4(ctx, reloc, s, a);
1736 }
1737
1738 switch (reloc) {
1739 case R_ARM_PC24:
1740 case R_ARM_PLT32:
1741 case R_ARM_JUMP24:
1742 case R_ARM_CALL:
1743 if (ctx.arg.picThunk)
1744 return std::make_unique<ARMV7PILongThunk>(args&: ctx, args&: s, args&: a);
1745 return std::make_unique<ARMV7ABSLongThunk>(args&: ctx, args&: s, args&: a);
1746 case R_ARM_THM_JUMP19:
1747 case R_ARM_THM_JUMP24:
1748 case R_ARM_THM_CALL:
1749 if (ctx.arg.picThunk)
1750 return std::make_unique<ThumbV7PILongThunk>(args&: ctx, args&: s, args&: a);
1751 return std::make_unique<ThumbV7ABSLongThunk>(args&: ctx, args&: s, args&: a);
1752 }
1753 llvm_unreachable("");
1754}
1755
1756static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,
1757 int64_t a) {
1758 switch (type) {
1759 case R_AVR_LO8_LDI_GS:
1760 case R_AVR_HI8_LDI_GS:
1761 return std::make_unique<AVRThunk>(args&: ctx, args&: s, args&: a);
1762 default:
1763 llvm_unreachable("");
1764 }
1765}
1766
1767static std::unique_ptr<Thunk> addThunkHexagon(Ctx &ctx,
1768 const InputSection &isec,
1769 Relocation &rel, Symbol &s) {
1770 switch (rel.type) {
1771 case R_HEX_B9_PCREL:
1772 case R_HEX_B13_PCREL:
1773 case R_HEX_B15_PCREL:
1774 case R_HEX_B22_PCREL:
1775 case R_HEX_PLT_B22_PCREL:
1776 case R_HEX_GD_PLT_B22_PCREL:
1777 return std::make_unique<HexagonThunk>(args&: ctx, args: isec, args&: rel, args&: s);
1778 default:
1779 Fatal(ctx) << "unrecognized relocation " << rel.type << " to " << &s
1780 << " for hexagon target";
1781 llvm_unreachable("");
1782 }
1783}
1784
1785static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
1786 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
1787 return std::make_unique<MicroMipsR6Thunk>(args&: ctx, args&: s);
1788 if (s.stOther & STO_MIPS_MICROMIPS)
1789 return std::make_unique<MicroMipsThunk>(args&: ctx, args&: s);
1790 return std::make_unique<MipsThunk>(args&: ctx, args&: s);
1791}
1792
1793static std::unique_ptr<Thunk> addThunkPPC32(Ctx &ctx, const InputSection &isec,
1794 const Relocation &rel, Symbol &s) {
1795 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
1796 rel.type == R_PPC_PLTREL24) &&
1797 "unexpected relocation type for thunk");
1798 if (s.isInPlt(ctx))
1799 return std::make_unique<PPC32PltCallStub>(args&: ctx, args: isec, args: rel, args&: s);
1800 return std::make_unique<PPC32LongThunk>(args&: ctx, args&: s, args: rel.addend);
1801}
1802
1803static std::unique_ptr<Thunk> addThunkPPC64(Ctx &ctx, RelType type, Symbol &s,
1804 int64_t a) {
1805 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
1806 type == R_PPC64_REL24_NOTOC) &&
1807 "unexpected relocation type for thunk");
1808
1809 // If we are emitting stubs for NOTOC relocations, we need to tell
1810 // the PLT resolver that there can be multiple TOCs.
1811 if (type == R_PPC64_REL24_NOTOC)
1812 ctx.target->ppc64DynamicSectionOpt = 0x2;
1813
1814 if (s.isInPlt(ctx)) {
1815 if (type == R_PPC64_REL24_NOTOC)
1816 return std::make_unique<PPC64R12SetupStub>(args&: ctx, args&: s,
1817 /*gotPlt=*/args: true);
1818 return std::make_unique<PPC64PltCallStub>(args&: ctx, args&: s);
1819 }
1820
1821 // This check looks at the st_other bits of the callee. If the value is 1
1822 // then the callee clobbers the TOC and we need an R2 save stub when RelType
1823 // is R_PPC64_REL14 or R_PPC64_REL24.
1824 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
1825 return std::make_unique<PPC64R2SaveStub>(args&: ctx, args&: s, args&: a);
1826
1827 if (type == R_PPC64_REL24_NOTOC)
1828 return std::make_unique<PPC64R12SetupStub>(args&: ctx, args&: s, /*gotPlt=*/args: false);
1829
1830 if (ctx.arg.picThunk)
1831 return std::make_unique<PPC64PILongBranchThunk>(args&: ctx, args&: s, args&: a);
1832
1833 return std::make_unique<PPC64PDLongBranchThunk>(args&: ctx, args&: s, args&: a);
1834}
1835
1836std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
1837 Relocation &rel) {
1838 Symbol &s = *rel.sym;
1839 int64_t a = rel.addend;
1840
1841 switch (ctx.arg.emachine) {
1842 case EM_AARCH64:
1843 return addThunkAArch64(ctx, sec: isec, type: rel.type, s, a);
1844 case EM_ARM:
1845 return addThunkArm(ctx, isec, reloc: rel.type, s, a);
1846 case EM_AVR:
1847 return addThunkAVR(ctx, type: rel.type, s, a);
1848 case EM_MIPS:
1849 return addThunkMips(ctx, type: rel.type, s);
1850 case EM_PPC:
1851 return addThunkPPC32(ctx, isec, rel, s);
1852 case EM_PPC64:
1853 return addThunkPPC64(ctx, type: rel.type, s, a);
1854 case EM_HEXAGON:
1855 return addThunkHexagon(ctx, isec, rel, s);
1856 default:
1857 llvm_unreachable(
1858 "add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC");
1859 }
1860}
1861
1862std::unique_ptr<Thunk> elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) {
1863 switch (ctx.arg.emachine) {
1864 case EM_AARCH64:
1865 return std::make_unique<AArch64BTILandingPadThunk>(args&: ctx, args&: s, args&: a);
1866 default:
1867 llvm_unreachable("add landing pad only supported for AArch64");
1868 }
1869}
1870