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