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