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