xref: /llvm-project-15.0.7/lld/ELF/Thunks.cpp (revision fe5eaab2)
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 "InputSection.h"
26 #include "OutputSections.h"
27 #include "Symbols.h"
28 #include "SyntheticSections.h"
29 #include "Target.h"
30 #include "lld/Common/ErrorHandler.h"
31 #include "lld/Common/Memory.h"
32 #include "llvm/BinaryFormat/ELF.h"
33 #include "llvm/Support/Casting.h"
34 #include "llvm/Support/Endian.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/MathExtras.h"
37 #include <cstdint>
38 #include <cstring>
39 
40 using namespace llvm;
41 using namespace llvm::object;
42 using namespace llvm::ELF;
43 
44 namespace lld {
45 namespace elf {
46 
47 namespace {
48 
49 // AArch64 long range Thunks
50 class AArch64ABSLongThunk final : public Thunk {
51 public:
52   AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {}
53   uint32_t size() override { return 16; }
54   void writeTo(uint8_t *Buf) override;
55   void addSymbols(ThunkSection &IS) override;
56 };
57 
58 class AArch64ADRPThunk final : public Thunk {
59 public:
60   AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {}
61   uint32_t size() override { return 12; }
62   void writeTo(uint8_t *Buf) override;
63   void addSymbols(ThunkSection &IS) override;
64 };
65 
66 // Base class for ARM thunks.
67 //
68 // An ARM thunk may be either short or long. A short thunk is simply a branch
69 // (B) instruction, and it may be used to call ARM functions when the distance
70 // from the thunk to the target is less than 32MB. Long thunks can branch to any
71 // virtual address and can switch between ARM and Thumb, and they are
72 // implemented in the derived classes. This class tries to create a short thunk
73 // if the target is in range, otherwise it creates a long thunk.
74 class ARMThunk : public Thunk {
75 public:
76   ARMThunk(Symbol &Dest) : Thunk(Dest) {}
77 
78   bool mayUseShortThunk();
79   uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
80   void writeTo(uint8_t *Buf) override;
81   bool isCompatibleWith(RelType Type) const override;
82 
83   // Returns the size of a long thunk.
84   virtual uint32_t sizeLong() = 0;
85 
86   // Writes a long thunk to Buf.
87   virtual void writeLong(uint8_t *Buf) = 0;
88 
89 private:
90   // This field tracks whether all previously considered layouts would allow
91   // this thunk to be short. If we have ever needed a long thunk, we always
92   // create a long thunk, even if the thunk may be short given the current
93   // distance to the target. We do this because transitioning from long to short
94   // can create layout oscillations in certain corner cases which would prevent
95   // the layout from converging.
96   bool MayUseShortThunk = true;
97 };
98 
99 // Base class for Thumb-2 thunks.
100 //
101 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
102 // which has a range of 16MB.
103 class ThumbThunk : public Thunk {
104 public:
105   ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
106 
107   bool mayUseShortThunk();
108   uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
109   void writeTo(uint8_t *Buf) override;
110   bool isCompatibleWith(RelType Type) const override;
111 
112   // Returns the size of a long thunk.
113   virtual uint32_t sizeLong() = 0;
114 
115   // Writes a long thunk to Buf.
116   virtual void writeLong(uint8_t *Buf) = 0;
117 
118 private:
119   // See comment in ARMThunk above.
120   bool MayUseShortThunk = true;
121 };
122 
123 // Specific ARM Thunk implementations. The naming convention is:
124 // Source State, TargetState, Target Requirement, ABS or PI, Range
125 class ARMV7ABSLongThunk final : public ARMThunk {
126 public:
127   ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
128 
129   uint32_t sizeLong() override { return 12; }
130   void writeLong(uint8_t *Buf) override;
131   void addSymbols(ThunkSection &IS) override;
132 };
133 
134 class ARMV7PILongThunk final : public ARMThunk {
135 public:
136   ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
137 
138   uint32_t sizeLong() override { return 16; }
139   void writeLong(uint8_t *Buf) override;
140   void addSymbols(ThunkSection &IS) override;
141 };
142 
143 class ThumbV7ABSLongThunk final : public ThumbThunk {
144 public:
145   ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
146 
147   uint32_t sizeLong() override { return 10; }
148   void writeLong(uint8_t *Buf) override;
149   void addSymbols(ThunkSection &IS) override;
150 };
151 
152 class ThumbV7PILongThunk final : public ThumbThunk {
153 public:
154   ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
155 
156   uint32_t sizeLong() override { return 12; }
157   void writeLong(uint8_t *Buf) override;
158   void addSymbols(ThunkSection &IS) override;
159 };
160 
161 // Implementations of Thunks for older Arm architectures that do not support
162 // the movt/movw instructions. These thunks require at least Architecture v5
163 // as used on processors such as the Arm926ej-s. There are no Thumb entry
164 // points as there is no Thumb branch instruction on these architecture that
165 // can result in a thunk
166 class ARMV5ABSLongThunk final : public ARMThunk {
167 public:
168   ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
169 
170   uint32_t sizeLong() override { return 8; }
171   void writeLong(uint8_t *Buf) override;
172   void addSymbols(ThunkSection &IS) override;
173   bool isCompatibleWith(uint32_t RelocType) const override;
174 };
175 
176 class ARMV5PILongThunk final : public ARMThunk {
177 public:
178   ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
179 
180   uint32_t sizeLong() override { return 16; }
181   void writeLong(uint8_t *Buf) override;
182   void addSymbols(ThunkSection &IS) override;
183   bool isCompatibleWith(uint32_t RelocType) const override;
184 };
185 
186 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
187 class ThumbV6MABSLongThunk final : public ThumbThunk {
188 public:
189   ThumbV6MABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
190 
191   uint32_t sizeLong() override { return 12; }
192   void writeLong(uint8_t *Buf) override;
193   void addSymbols(ThunkSection &IS) override;
194 };
195 
196 class ThumbV6MPILongThunk final : public ThumbThunk {
197 public:
198   ThumbV6MPILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
199 
200   uint32_t sizeLong() override { return 16; }
201   void writeLong(uint8_t *Buf) override;
202   void addSymbols(ThunkSection &IS) override;
203 };
204 
205 // MIPS LA25 thunk
206 class MipsThunk final : public Thunk {
207 public:
208   MipsThunk(Symbol &Dest) : Thunk(Dest) {}
209 
210   uint32_t size() override { return 16; }
211   void writeTo(uint8_t *Buf) override;
212   void addSymbols(ThunkSection &IS) override;
213   InputSection *getTargetInputSection() const override;
214 };
215 
216 // microMIPS R2-R5 LA25 thunk
217 class MicroMipsThunk final : public Thunk {
218 public:
219   MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {}
220 
221   uint32_t size() override { return 14; }
222   void writeTo(uint8_t *Buf) override;
223   void addSymbols(ThunkSection &IS) override;
224   InputSection *getTargetInputSection() const override;
225 };
226 
227 // microMIPS R6 LA25 thunk
228 class MicroMipsR6Thunk final : public Thunk {
229 public:
230   MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {}
231 
232   uint32_t size() override { return 12; }
233   void writeTo(uint8_t *Buf) override;
234   void addSymbols(ThunkSection &IS) override;
235   InputSection *getTargetInputSection() const override;
236 };
237 
238 
239 // PPC64 Plt call stubs.
240 // Any call site that needs to call through a plt entry needs a call stub in
241 // the .text section. The call stub is responsible for:
242 // 1) Saving the toc-pointer to the stack.
243 // 2) Loading the target functions address from the procedure linkage table into
244 //    r12 for use by the target functions global entry point, and into the count
245 //    register.
246 // 3) Transfering control to the target function through an indirect branch.
247 class PPC64PltCallStub final : public Thunk {
248 public:
249   PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {}
250   uint32_t size() override { return 20; }
251   void writeTo(uint8_t *Buf) override;
252   void addSymbols(ThunkSection &IS) override;
253 };
254 
255 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
256 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
257 // larger then that we need to emit a long-branch thunk. The target address
258 // of the callee is stored in a table to be accessed TOC-relative. Since the
259 // call must be local (a non-local call will have a PltCallStub instead) the
260 // table stores the address of the callee's local entry point. For
261 // position-independent code a corresponding relative dynamic relocation is
262 // used.
263 class PPC64LongBranchThunk : public Thunk {
264 public:
265   uint32_t size() override { return 16; }
266   void writeTo(uint8_t *Buf) override;
267   void addSymbols(ThunkSection &IS) override;
268 
269 protected:
270   PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {}
271 };
272 
273 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
274 public:
275   PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
276     assert(!Dest.IsPreemptible);
277     if (Dest.isInPPC64Branchlt())
278       return;
279 
280     In.PPC64LongBranchTarget->addEntry(Dest);
281     In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget,
282                           Dest.getPPC64LongBranchOffset(), true, &Dest,
283                           getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)});
284   }
285 };
286 
287 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
288 public:
289   PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
290     if (!Dest.isInPPC64Branchlt())
291       In.PPC64LongBranchTarget->addEntry(Dest);
292   }
293 };
294 
295 } // end anonymous namespace
296 
297 Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
298                           InputSectionBase &Section) {
299   Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section);
300   Syms.push_back(D);
301   return D;
302 }
303 
304 void Thunk::setOffset(uint64_t NewOffset) {
305   for (Defined *D : Syms)
306     D->Value = D->Value - Offset + NewOffset;
307   Offset = NewOffset;
308 }
309 
310 // AArch64 long range Thunks
311 
312 static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
313   uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
314   return V;
315 }
316 
317 void AArch64ABSLongThunk::writeTo(uint8_t *Buf) {
318   const uint8_t Data[] = {
319     0x50, 0x00, 0x00, 0x58, //     ldr x16, L0
320     0x00, 0x02, 0x1f, 0xd6, //     br  x16
321     0x00, 0x00, 0x00, 0x00, // L0: .xword S
322     0x00, 0x00, 0x00, 0x00,
323   };
324   uint64_t S = getAArch64ThunkDestVA(Destination);
325   memcpy(Buf, Data, sizeof(Data));
326   Target->relocateOne(Buf + 8, R_AARCH64_ABS64, S);
327 }
328 
329 void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
330   addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()),
331             STT_FUNC, 0, IS);
332   addSymbol("$x", STT_NOTYPE, 0, IS);
333   addSymbol("$d", STT_NOTYPE, 8, IS);
334 }
335 
336 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
337 // using the small code model, including pc-relative ones. At time of writing
338 // clang and gcc do not support the large code model for position independent
339 // code so it is safe to use this for position independent thunks without
340 // worrying about the destination being more than 4Gb away.
341 void AArch64ADRPThunk::writeTo(uint8_t *Buf) {
342   const uint8_t Data[] = {
343       0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
344       0x10, 0x02, 0x00, 0x91, // add  x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
345       0x00, 0x02, 0x1f, 0xd6, // br   x16
346   };
347   uint64_t S = getAArch64ThunkDestVA(Destination);
348   uint64_t P = getThunkTargetSym()->getVA();
349   memcpy(Buf, Data, sizeof(Data));
350   Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
351                       getAArch64Page(S) - getAArch64Page(P));
352   Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S);
353 }
354 
355 void AArch64ADRPThunk::addSymbols(ThunkSection &IS) {
356   addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
357             0, IS);
358   addSymbol("$x", STT_NOTYPE, 0, IS);
359 }
360 
361 // ARM Target Thunks
362 static uint64_t getARMThunkDestVA(const Symbol &S) {
363   uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
364   return SignExtend64<32>(V);
365 }
366 
367 // This function returns true if the target is not Thumb and is within 2^26, and
368 // it has not previously returned false (see comment for MayUseShortThunk).
369 bool ARMThunk::mayUseShortThunk() {
370   if (!MayUseShortThunk)
371     return false;
372   uint64_t S = getARMThunkDestVA(Destination);
373   if (S & 1) {
374     MayUseShortThunk = false;
375     return false;
376   }
377   uint64_t P = getThunkTargetSym()->getVA();
378   int64_t Offset = S - P - 8;
379   MayUseShortThunk = llvm::isInt<26>(Offset);
380   return MayUseShortThunk;
381 }
382 
383 void ARMThunk::writeTo(uint8_t *Buf) {
384   if (!mayUseShortThunk()) {
385     writeLong(Buf);
386     return;
387   }
388 
389   uint64_t S = getARMThunkDestVA(Destination);
390   uint64_t P = getThunkTargetSym()->getVA();
391   int64_t Offset = S - P - 8;
392   const uint8_t Data[] = {
393     0x00, 0x00, 0x00, 0xea, // b S
394   };
395   memcpy(Buf, Data, sizeof(Data));
396   Target->relocateOne(Buf, R_ARM_JUMP24, Offset);
397 }
398 
399 bool ARMThunk::isCompatibleWith(RelType Type) const {
400   // Thumb branch relocations can't use BLX
401   return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
402 }
403 
404 // This function returns true if the target is Thumb and is within 2^25, and
405 // it has not previously returned false (see comment for MayUseShortThunk).
406 bool ThumbThunk::mayUseShortThunk() {
407   if (!MayUseShortThunk)
408     return false;
409   uint64_t S = getARMThunkDestVA(Destination);
410   if ((S & 1) == 0) {
411     MayUseShortThunk = false;
412     return false;
413   }
414   uint64_t P = getThunkTargetSym()->getVA() & ~1;
415   int64_t Offset = S - P - 4;
416   MayUseShortThunk = llvm::isInt<25>(Offset);
417   return MayUseShortThunk;
418 }
419 
420 void ThumbThunk::writeTo(uint8_t *Buf) {
421   if (!mayUseShortThunk()) {
422     writeLong(Buf);
423     return;
424   }
425 
426   uint64_t S = getARMThunkDestVA(Destination);
427   uint64_t P = getThunkTargetSym()->getVA();
428   int64_t Offset = S - P - 4;
429   const uint8_t Data[] = {
430       0x00, 0xf0, 0x00, 0xb0, // b.w S
431   };
432   memcpy(Buf, Data, sizeof(Data));
433   Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset);
434 }
435 
436 bool ThumbThunk::isCompatibleWith(RelType Type) const {
437   // ARM branch relocations can't use BLX
438   return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
439 }
440 
441 void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) {
442   const uint8_t Data[] = {
443       0x00, 0xc0, 0x00, 0xe3, // movw         ip,:lower16:S
444       0x00, 0xc0, 0x40, 0xe3, // movt         ip,:upper16:S
445       0x1c, 0xff, 0x2f, 0xe1, // bx   ip
446   };
447   uint64_t S = getARMThunkDestVA(Destination);
448   memcpy(Buf, Data, sizeof(Data));
449   Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
450   Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
451 }
452 
453 void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
454   addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()),
455             STT_FUNC, 0, IS);
456   addSymbol("$a", STT_NOTYPE, 0, IS);
457 }
458 
459 void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) {
460   const uint8_t Data[] = {
461       0x40, 0xf2, 0x00, 0x0c, // movw         ip, :lower16:S
462       0xc0, 0xf2, 0x00, 0x0c, // movt         ip, :upper16:S
463       0x60, 0x47,             // bx   ip
464   };
465   uint64_t S = getARMThunkDestVA(Destination);
466   memcpy(Buf, Data, sizeof(Data));
467   Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
468   Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
469 }
470 
471 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
472   addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()),
473             STT_FUNC, 1, IS);
474   addSymbol("$t", STT_NOTYPE, 0, IS);
475 }
476 
477 void ARMV7PILongThunk::writeLong(uint8_t *Buf) {
478   const uint8_t Data[] = {
479       0xf0, 0xcf, 0x0f, 0xe3, // P:  movw ip,:lower16:S - (P + (L1-P) + 8)
480       0x00, 0xc0, 0x40, 0xe3, //     movt ip,:upper16:S - (P + (L1-P) + 8)
481       0x0f, 0xc0, 0x8c, 0xe0, // L1: add  ip, ip, pc
482       0x1c, 0xff, 0x2f, 0xe1, //     bx   ip
483   };
484   uint64_t S = getARMThunkDestVA(Destination);
485   uint64_t P = getThunkTargetSym()->getVA();
486   int64_t Offset = S - P - 16;
487   memcpy(Buf, Data, sizeof(Data));
488   Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
489   Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset);
490 }
491 
492 void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
493   addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
494             0, IS);
495   addSymbol("$a", STT_NOTYPE, 0, IS);
496 }
497 
498 void ThumbV7PILongThunk::writeLong(uint8_t *Buf) {
499   const uint8_t Data[] = {
500       0x4f, 0xf6, 0xf4, 0x7c, // P:  movw ip,:lower16:S - (P + (L1-P) + 4)
501       0xc0, 0xf2, 0x00, 0x0c, //     movt ip,:upper16:S - (P + (L1-P) + 4)
502       0xfc, 0x44,             // L1: add  ip, pc
503       0x60, 0x47,             //     bx   ip
504   };
505   uint64_t S = getARMThunkDestVA(Destination);
506   uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
507   int64_t Offset = S - P - 12;
508   memcpy(Buf, Data, sizeof(Data));
509   Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
510   Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset);
511 }
512 
513 void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
514   addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()),
515             STT_FUNC, 1, IS);
516   addSymbol("$t", STT_NOTYPE, 0, IS);
517 }
518 
519 void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) {
520   const uint8_t Data[] = {
521       0x04, 0xf0, 0x1f, 0xe5, //     ldr pc, [pc,#-4] ; L1
522       0x00, 0x00, 0x00, 0x00, // L1: .word S
523   };
524   memcpy(Buf, Data, sizeof(Data));
525   Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination));
526 }
527 
528 void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) {
529   addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()),
530             STT_FUNC, 0, IS);
531   addSymbol("$a", STT_NOTYPE, 0, IS);
532   addSymbol("$d", STT_NOTYPE, 4, IS);
533 }
534 
535 bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
536   // Thumb branch relocations can't use BLX
537   return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
538 }
539 
540 void ARMV5PILongThunk::writeLong(uint8_t *Buf) {
541   const uint8_t Data[] = {
542       0x04, 0xc0, 0x9f, 0xe5, // P:  ldr ip, [pc,#4] ; L2
543       0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
544       0x1c, 0xff, 0x2f, 0xe1, //     bx ip
545       0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
546   };
547   uint64_t S = getARMThunkDestVA(Destination);
548   uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
549   memcpy(Buf, Data, sizeof(Data));
550   Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
551 }
552 
553 void ARMV5PILongThunk::addSymbols(ThunkSection &IS) {
554   addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC,
555             0, IS);
556   addSymbol("$a", STT_NOTYPE, 0, IS);
557   addSymbol("$d", STT_NOTYPE, 12, IS);
558 }
559 
560 bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const {
561   // Thumb branch relocations can't use BLX
562   return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
563 }
564 
565 void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) {
566   // Most Thumb instructions cannot access the high registers r8 - r15. As the
567   // only register we can corrupt is r12 we must instead spill a low register
568   // to the stack to use as a scratch register. We push r1 even though we
569   // don't need to get some space to use for the return address.
570   const uint8_t Data[] = {
571       0x03, 0xb4,            // push {r0, r1} ; Obtain scratch registers
572       0x01, 0x48,            // ldr r0, [pc, #4] ; L1
573       0x01, 0x90,            // str r0, [sp, #4] ; SP + 4 = S
574       0x01, 0xbd,            // pop {r0, pc} ; restore r0 and branch to dest
575       0x00, 0x00, 0x00, 0x00 // L1: .word S
576   };
577   uint64_t S = getARMThunkDestVA(Destination);
578   memcpy(Buf, Data, sizeof(Data));
579   Target->relocateOne(Buf + 8, R_ARM_ABS32, S);
580 }
581 
582 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &IS) {
583   addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + Destination.getName()),
584             STT_FUNC, 1, IS);
585   addSymbol("$t", STT_NOTYPE, 0, IS);
586   addSymbol("$d", STT_NOTYPE, 8, IS);
587 }
588 
589 void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) {
590   // Most Thumb instructions cannot access the high registers r8 - r15. As the
591   // only register we can corrupt is ip (r12) we must instead spill a low
592   // register to the stack to use as a scratch register.
593   const uint8_t Data[] = {
594       0x01, 0xb4,             // P:  push {r0}        ; Obtain scratch register
595       0x02, 0x48,             //     ldr r0, [pc, #8] ; L2
596       0x84, 0x46,             //     mov ip, r0       ; high to low register
597       0x01, 0xbc,             //     pop {r0}         ; restore scratch register
598       0xe7, 0x44,             // L1: add pc, ip       ; transfer control
599       0xc0, 0x46,             //     nop              ; pad to 4-byte boundary
600       0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
601   };
602   uint64_t S = getARMThunkDestVA(Destination);
603   uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
604   memcpy(Buf, Data, sizeof(Data));
605   Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
606 }
607 
608 void ThumbV6MPILongThunk::addSymbols(ThunkSection &IS) {
609   addSymbol(Saver.save("__Thumbv6MPILongThunk_" + Destination.getName()),
610             STT_FUNC, 1, IS);
611   addSymbol("$t", STT_NOTYPE, 0, IS);
612   addSymbol("$d", STT_NOTYPE, 12, IS);
613 }
614 
615 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
616 void MipsThunk::writeTo(uint8_t *Buf) {
617   uint64_t S = Destination.getVA();
618   write32(Buf, 0x3c190000); // lui   $25, %hi(func)
619   write32(Buf + 4, 0x08000000 | (S >> 2)); // j     func
620   write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
621   write32(Buf + 12, 0x00000000); // nop
622   Target->relocateOne(Buf, R_MIPS_HI16, S);
623   Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
624 }
625 
626 void MipsThunk::addSymbols(ThunkSection &IS) {
627   addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0,
628             IS);
629 }
630 
631 InputSection *MipsThunk::getTargetInputSection() const {
632   auto &DR = cast<Defined>(Destination);
633   return dyn_cast<InputSection>(DR.Section);
634 }
635 
636 // Write microMIPS R2-R5 LA25 thunk code
637 // to call PIC function from the non-PIC one.
638 void MicroMipsThunk::writeTo(uint8_t *Buf) {
639   uint64_t S = Destination.getVA();
640   write16(Buf, 0x41b9);       // lui   $25, %hi(func)
641   write16(Buf + 4, 0xd400);   // j     func
642   write16(Buf + 8, 0x3339);   // addiu $25, $25, %lo(func)
643   write16(Buf + 12, 0x0c00);  // nop
644   Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
645   Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S);
646   Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S);
647 }
648 
649 void MicroMipsThunk::addSymbols(ThunkSection &IS) {
650   Defined *D = addSymbol(
651       Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
652   D->StOther |= STO_MIPS_MICROMIPS;
653 }
654 
655 InputSection *MicroMipsThunk::getTargetInputSection() const {
656   auto &DR = cast<Defined>(Destination);
657   return dyn_cast<InputSection>(DR.Section);
658 }
659 
660 // Write microMIPS R6 LA25 thunk code
661 // to call PIC function from the non-PIC one.
662 void MicroMipsR6Thunk::writeTo(uint8_t *Buf) {
663   uint64_t S = Destination.getVA();
664   uint64_t P = getThunkTargetSym()->getVA();
665   write16(Buf, 0x1320);       // lui   $25, %hi(func)
666   write16(Buf + 4, 0x3339);   // addiu $25, $25, %lo(func)
667   write16(Buf + 8, 0x9400);   // bc    func
668   Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
669   Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S);
670   Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12);
671 }
672 
673 void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) {
674   Defined *D = addSymbol(
675       Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
676   D->StOther |= STO_MIPS_MICROMIPS;
677 }
678 
679 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
680   auto &DR = cast<Defined>(Destination);
681   return dyn_cast<InputSection>(DR.Section);
682 }
683 
684 static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) {
685   uint16_t OffHa = (Offset + 0x8000) >> 16;
686   uint16_t OffLo = Offset & 0xffff;
687 
688   write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa
689   write32(Buf + 4, 0xe98c0000 | OffLo); // ld    r12, OffLo(r12)
690   write32(Buf + 8, 0x7d8903a6);         // mtctr r12
691   write32(Buf + 12, 0x4e800420);        // bctr
692 }
693 
694 void PPC64PltCallStub::writeTo(uint8_t *Buf) {
695   int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase();
696   // Save the TOC pointer to the save-slot reserved in the call frame.
697   write32(Buf + 0, 0xf8410018); // std     r2,24(r1)
698   writePPCLoadAndBranch(Buf + 4, Offset);
699 }
700 
701 void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
702   Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC,
703                          0, IS);
704   S->NeedsTocRestore = true;
705 }
706 
707 void PPC64LongBranchThunk::writeTo(uint8_t *Buf) {
708   int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase();
709   writePPCLoadAndBranch(Buf, Offset);
710 }
711 
712 void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) {
713   addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0,
714             IS);
715 }
716 
717 Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
718 
719 Thunk::~Thunk() = default;
720 
721 static Thunk *addThunkAArch64(RelType Type, Symbol &S) {
722   if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
723     fatal("unrecognized relocation type");
724   if (Config->PicThunk)
725     return make<AArch64ADRPThunk>(S);
726   return make<AArch64ABSLongThunk>(S);
727 }
728 
729 // Creates a thunk for Thumb-ARM interworking.
730 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means
731 // - MOVT and MOVW instructions cannot be used
732 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
733 //   be transformed into a BLX
734 static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) {
735   switch (Reloc) {
736   case R_ARM_PC24:
737   case R_ARM_PLT32:
738   case R_ARM_JUMP24:
739   case R_ARM_CALL:
740   case R_ARM_THM_CALL:
741     if (Config->PicThunk)
742       return make<ARMV5PILongThunk>(S);
743     return make<ARMV5ABSLongThunk>(S);
744   }
745   fatal("relocation " + toString(Reloc) + " to " + toString(S) +
746         " not supported for Armv5 or Armv6 targets");
747 }
748 
749 // Create a thunk for Thumb long branch on V6-M.
750 // Arm Architecture v6-M only supports Thumb instructions. This means
751 // - MOVT and MOVW instructions cannot be used.
752 // - Only a limited number of instructions can access registers r8 and above
753 // - No interworking support is needed (all Thumb).
754 static Thunk *addThunkV6M(RelType Reloc, Symbol &S) {
755   switch (Reloc) {
756   case R_ARM_THM_JUMP19:
757   case R_ARM_THM_JUMP24:
758   case R_ARM_THM_CALL:
759     if (Config->Pic)
760       return make<ThumbV6MPILongThunk>(S);
761     return make<ThumbV6MABSLongThunk>(S);
762   }
763   fatal("relocation " + toString(Reloc) + " to " + toString(S) +
764         " not supported for Armv6-M targets");
765 }
766 
767 // Creates a thunk for Thumb-ARM interworking or branch range extension.
768 static Thunk *addThunkArm(RelType Reloc, Symbol &S) {
769   // Decide which Thunk is needed based on:
770   // Available instruction set
771   // - An Arm Thunk can only be used if Arm state is available.
772   // - A Thumb Thunk can only be used if Thumb state is available.
773   // - Can only use a Thunk if it uses instructions that the Target supports.
774   // Relocation is branch or branch and link
775   // - Branch instructions cannot change state, can only select Thunk that
776   //   starts in the same state as the caller.
777   // - Branch and link relocations can change state, can select Thunks from
778   //   either Arm or Thumb.
779   // Position independent Thunks if we require position independent code.
780 
781   // Handle architectures that have restrictions on the instructions that they
782   // can use in Thunks. The flags below are set by reading the BuildAttributes
783   // of the input objects. InputFiles.cpp contains the mapping from ARM
784   // architecture to flag.
785   if (!Config->ARMHasMovtMovw) {
786     if (!Config->ARMJ1J2BranchEncoding)
787       return addThunkPreArmv7(Reloc, S);
788     return addThunkV6M(Reloc, S);
789   }
790 
791   switch (Reloc) {
792   case R_ARM_PC24:
793   case R_ARM_PLT32:
794   case R_ARM_JUMP24:
795   case R_ARM_CALL:
796     if (Config->PicThunk)
797       return make<ARMV7PILongThunk>(S);
798     return make<ARMV7ABSLongThunk>(S);
799   case R_ARM_THM_JUMP19:
800   case R_ARM_THM_JUMP24:
801   case R_ARM_THM_CALL:
802     if (Config->PicThunk)
803       return make<ThumbV7PILongThunk>(S);
804     return make<ThumbV7ABSLongThunk>(S);
805   }
806   fatal("unrecognized relocation type");
807 }
808 
809 static Thunk *addThunkMips(RelType Type, Symbol &S) {
810   if ((S.StOther & STO_MIPS_MICROMIPS) && isMipsR6())
811     return make<MicroMipsR6Thunk>(S);
812   if (S.StOther & STO_MIPS_MICROMIPS)
813     return make<MicroMipsThunk>(S);
814   return make<MipsThunk>(S);
815 }
816 
817 static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
818   assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk");
819   if (S.isInPlt())
820     return make<PPC64PltCallStub>(S);
821 
822   if (Config->PicThunk)
823     return make<PPC64PILongBranchThunk>(S);
824 
825   return make<PPC64PDLongBranchThunk>(S);
826 }
827 
828 Thunk *addThunk(RelType Type, Symbol &S) {
829   if (Config->EMachine == EM_AARCH64)
830     return addThunkAArch64(Type, S);
831 
832   if (Config->EMachine == EM_ARM)
833     return addThunkArm(Type, S);
834 
835   if (Config->EMachine == EM_MIPS)
836     return addThunkMips(Type, S);
837 
838   if (Config->EMachine == EM_PPC64)
839     return addThunkPPC64(Type, S);
840 
841   llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
842 }
843 
844 } // end namespace elf
845 } // end namespace lld
846