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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lld/ELF/Thunks.cpp