1 //===- Thunks.cpp --------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===---------------------------------------------------------------------===//
8 //
9 // This file contains Thunk subclasses.
10 //
11 // A thunk is a small piece of code written after an input section
12 // which is used to jump between "incompatible" functions
13 // such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions.
14 //
15 // If a jump target is too far and its address doesn't fit to a
16 // short jump instruction, we need to create a thunk too, but we
17 // haven't supported it yet.
18 //
19 // i386 and x86-64 don't need thunks.
20 //
21 //===---------------------------------------------------------------------===//
22
23 #include "Thunks.h"
24 #include "Config.h"
25 #include "InputSection.h"
26 #include "OutputSections.h"
27 #include "Symbols.h"
28 #include "SyntheticSections.h"
29 #include "Target.h"
30 #include "lld/Common/ErrorHandler.h"
31 #include "lld/Common/Memory.h"
32 #include "llvm/BinaryFormat/ELF.h"
33 #include "llvm/Support/Casting.h"
34 #include "llvm/Support/Endian.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/MathExtras.h"
37 #include <cstdint>
38 #include <cstring>
39
40 using namespace llvm;
41 using namespace llvm::object;
42 using namespace llvm::ELF;
43 using namespace lld;
44 using namespace lld::elf;
45
46 namespace {
47
48 // AArch64 long range Thunks
49 class AArch64ABSLongThunk final : public Thunk {
50 public:
AArch64ABSLongThunk(Symbol & dest,int64_t addend)51 AArch64ABSLongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
size()52 uint32_t size() override { return 16; }
53 void writeTo(uint8_t *buf) override;
54 void addSymbols(ThunkSection &isec) override;
55 };
56
57 class AArch64ADRPThunk final : public Thunk {
58 public:
AArch64ADRPThunk(Symbol & dest,int64_t addend)59 AArch64ADRPThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
size()60 uint32_t size() override { return 12; }
61 void writeTo(uint8_t *buf) override;
62 void addSymbols(ThunkSection &isec) override;
63 };
64
65 // Base class for ARM thunks.
66 //
67 // An ARM thunk may be either short or long. A short thunk is simply a branch
68 // (B) instruction, and it may be used to call ARM functions when the distance
69 // from the thunk to the target is less than 32MB. Long thunks can branch to any
70 // virtual address and can switch between ARM and Thumb, and they are
71 // implemented in the derived classes. This class tries to create a short thunk
72 // if the target is in range, otherwise it creates a long thunk.
73 class ARMThunk : public Thunk {
74 public:
ARMThunk(Symbol & dest,int64_t addend)75 ARMThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
76
77 bool getMayUseShortThunk();
size()78 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
79 void writeTo(uint8_t *buf) override;
80 bool isCompatibleWith(const InputSection &isec,
81 const Relocation &rel) const override;
82
83 // Returns the size of a long thunk.
84 virtual uint32_t sizeLong() = 0;
85
86 // Writes a long thunk to Buf.
87 virtual void writeLong(uint8_t *buf) = 0;
88
89 private:
90 // This field tracks whether all previously considered layouts would allow
91 // this thunk to be short. If we have ever needed a long thunk, we always
92 // create a long thunk, even if the thunk may be short given the current
93 // distance to the target. We do this because transitioning from long to short
94 // can create layout oscillations in certain corner cases which would prevent
95 // the layout from converging.
96 bool mayUseShortThunk = true;
97 };
98
99 // Base class for Thumb-2 thunks.
100 //
101 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
102 // which has a range of 16MB.
103 class ThumbThunk : public Thunk {
104 public:
ThumbThunk(Symbol & dest,int64_t addend)105 ThumbThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
106 alignment = 2;
107 }
108
109 bool getMayUseShortThunk();
size()110 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
111 void writeTo(uint8_t *buf) override;
112 bool isCompatibleWith(const InputSection &isec,
113 const Relocation &rel) const override;
114
115 // Returns the size of a long thunk.
116 virtual uint32_t sizeLong() = 0;
117
118 // Writes a long thunk to Buf.
119 virtual void writeLong(uint8_t *buf) = 0;
120
121 private:
122 // See comment in ARMThunk above.
123 bool mayUseShortThunk = true;
124 };
125
126 // Specific ARM Thunk implementations. The naming convention is:
127 // Source State, TargetState, Target Requirement, ABS or PI, Range
128 class ARMV7ABSLongThunk final : public ARMThunk {
129 public:
ARMV7ABSLongThunk(Symbol & dest,int64_t addend)130 ARMV7ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
131
sizeLong()132 uint32_t sizeLong() override { return 12; }
133 void writeLong(uint8_t *buf) override;
134 void addSymbols(ThunkSection &isec) override;
135 };
136
137 class ARMV7PILongThunk final : public ARMThunk {
138 public:
ARMV7PILongThunk(Symbol & dest,int64_t addend)139 ARMV7PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
140
sizeLong()141 uint32_t sizeLong() override { return 16; }
142 void writeLong(uint8_t *buf) override;
143 void addSymbols(ThunkSection &isec) override;
144 };
145
146 class ThumbV7ABSLongThunk final : public ThumbThunk {
147 public:
ThumbV7ABSLongThunk(Symbol & dest,int64_t addend)148 ThumbV7ABSLongThunk(Symbol &dest, int64_t addend)
149 : ThumbThunk(dest, addend) {}
150
sizeLong()151 uint32_t sizeLong() override { return 10; }
152 void writeLong(uint8_t *buf) override;
153 void addSymbols(ThunkSection &isec) override;
154 };
155
156 class ThumbV7PILongThunk final : public ThumbThunk {
157 public:
ThumbV7PILongThunk(Symbol & dest,int64_t addend)158 ThumbV7PILongThunk(Symbol &dest, int64_t addend) : ThumbThunk(dest, addend) {}
159
sizeLong()160 uint32_t sizeLong() override { return 12; }
161 void writeLong(uint8_t *buf) override;
162 void addSymbols(ThunkSection &isec) override;
163 };
164
165 // Implementations of Thunks for older Arm architectures that do not support
166 // the movt/movw instructions. These thunks require at least Architecture v5
167 // as used on processors such as the Arm926ej-s. There are no Thumb entry
168 // points as there is no Thumb branch instruction on these architecture that
169 // can result in a thunk
170 class ARMV5ABSLongThunk final : public ARMThunk {
171 public:
ARMV5ABSLongThunk(Symbol & dest,int64_t addend)172 ARMV5ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
173
sizeLong()174 uint32_t sizeLong() override { return 8; }
175 void writeLong(uint8_t *buf) override;
176 void addSymbols(ThunkSection &isec) override;
177 bool isCompatibleWith(const InputSection &isec,
178 const Relocation &rel) const override;
179 };
180
181 class ARMV5PILongThunk final : public ARMThunk {
182 public:
ARMV5PILongThunk(Symbol & dest,int64_t addend)183 ARMV5PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
184
sizeLong()185 uint32_t sizeLong() override { return 16; }
186 void writeLong(uint8_t *buf) override;
187 void addSymbols(ThunkSection &isec) override;
188 bool isCompatibleWith(const InputSection &isec,
189 const Relocation &rel) const override;
190 };
191
192 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
193 class ThumbV6MABSLongThunk final : public ThumbThunk {
194 public:
ThumbV6MABSLongThunk(Symbol & dest,int64_t addend)195 ThumbV6MABSLongThunk(Symbol &dest, int64_t addend)
196 : ThumbThunk(dest, addend) {}
197
sizeLong()198 uint32_t sizeLong() override { return 12; }
199 void writeLong(uint8_t *buf) override;
200 void addSymbols(ThunkSection &isec) override;
201 };
202
203 class ThumbV6MPILongThunk final : public ThumbThunk {
204 public:
ThumbV6MPILongThunk(Symbol & dest,int64_t addend)205 ThumbV6MPILongThunk(Symbol &dest, int64_t addend)
206 : ThumbThunk(dest, addend) {}
207
sizeLong()208 uint32_t sizeLong() override { return 16; }
209 void writeLong(uint8_t *buf) override;
210 void addSymbols(ThunkSection &isec) override;
211 };
212
213 // MIPS LA25 thunk
214 class MipsThunk final : public Thunk {
215 public:
MipsThunk(Symbol & dest)216 MipsThunk(Symbol &dest) : Thunk(dest, 0) {}
217
size()218 uint32_t size() override { return 16; }
219 void writeTo(uint8_t *buf) override;
220 void addSymbols(ThunkSection &isec) override;
221 InputSection *getTargetInputSection() const override;
222 };
223
224 // microMIPS R2-R5 LA25 thunk
225 class MicroMipsThunk final : public Thunk {
226 public:
MicroMipsThunk(Symbol & dest)227 MicroMipsThunk(Symbol &dest) : Thunk(dest, 0) {}
228
size()229 uint32_t size() override { return 14; }
230 void writeTo(uint8_t *buf) override;
231 void addSymbols(ThunkSection &isec) override;
232 InputSection *getTargetInputSection() const override;
233 };
234
235 // microMIPS R6 LA25 thunk
236 class MicroMipsR6Thunk final : public Thunk {
237 public:
MicroMipsR6Thunk(Symbol & dest)238 MicroMipsR6Thunk(Symbol &dest) : Thunk(dest, 0) {}
239
size()240 uint32_t size() override { return 12; }
241 void writeTo(uint8_t *buf) override;
242 void addSymbols(ThunkSection &isec) override;
243 InputSection *getTargetInputSection() const override;
244 };
245
246 class PPC32PltCallStub final : public Thunk {
247 public:
248 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to
249 // decide the offsets in the call stub.
PPC32PltCallStub(const InputSection & isec,const Relocation & rel,Symbol & dest)250 PPC32PltCallStub(const InputSection &isec, const Relocation &rel,
251 Symbol &dest)
252 : Thunk(dest, rel.addend), file(isec.file) {}
size()253 uint32_t size() override { return 16; }
254 void writeTo(uint8_t *buf) override;
255 void addSymbols(ThunkSection &isec) override;
256 bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override;
257
258 private:
259 // Records the call site of the call stub.
260 const InputFile *file;
261 };
262
263 class PPC32LongThunk final : public Thunk {
264 public:
PPC32LongThunk(Symbol & dest,int64_t addend)265 PPC32LongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
size()266 uint32_t size() override { return config->isPic ? 32 : 16; }
267 void writeTo(uint8_t *buf) override;
268 void addSymbols(ThunkSection &isec) override;
269 };
270
271 // PPC64 Plt call stubs.
272 // Any call site that needs to call through a plt entry needs a call stub in
273 // the .text section. The call stub is responsible for:
274 // 1) Saving the toc-pointer to the stack.
275 // 2) Loading the target functions address from the procedure linkage table into
276 // r12 for use by the target functions global entry point, and into the count
277 // register.
278 // 3) Transferring control to the target function through an indirect branch.
279 class PPC64PltCallStub final : public Thunk {
280 public:
PPC64PltCallStub(Symbol & dest)281 PPC64PltCallStub(Symbol &dest) : Thunk(dest, 0) {}
size()282 uint32_t size() override { return 20; }
283 void writeTo(uint8_t *buf) override;
284 void addSymbols(ThunkSection &isec) override;
285 bool isCompatibleWith(const InputSection &isec,
286 const Relocation &rel) const override;
287 };
288
289 // PPC64 R2 Save Stub
290 // When the caller requires a valid R2 TOC pointer but the callee does not
291 // require a TOC pointer and the callee cannot guarantee that it doesn't
292 // clobber R2 then we need to save R2. This stub:
293 // 1) Saves the TOC pointer to the stack.
294 // 2) Tail calls the callee.
295 class PPC64R2SaveStub final : public Thunk {
296 public:
PPC64R2SaveStub(Symbol & dest,int64_t addend)297 PPC64R2SaveStub(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
298 alignment = 16;
299 }
300
301 // To prevent oscillations in layout when moving from short to long thunks
302 // we make sure that once a thunk has been set to long it cannot go back.
getMayUseShortThunk()303 bool getMayUseShortThunk() {
304 if (!mayUseShortThunk)
305 return false;
306 if (!isInt<26>(computeOffset())) {
307 mayUseShortThunk = false;
308 return false;
309 }
310 return true;
311 }
size()312 uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
313 void writeTo(uint8_t *buf) override;
314 void addSymbols(ThunkSection &isec) override;
315 bool isCompatibleWith(const InputSection &isec,
316 const Relocation &rel) const override;
317
318 private:
319 // Transitioning from long to short can create layout oscillations in
320 // certain corner cases which would prevent the layout from converging.
321 // This is similar to the handling for ARMThunk.
322 bool mayUseShortThunk = true;
computeOffset() const323 int64_t computeOffset() const {
324 return destination.getVA() - (getThunkTargetSym()->getVA() + 4);
325 }
326 };
327
328 // PPC64 R12 Setup Stub
329 // When a caller that does not maintain a toc-pointer performs a local call to
330 // a callee which requires a toc-pointer then we need this stub to place the
331 // callee's global entry point into r12 without a save of R2.
332 class PPC64R12SetupStub final : public Thunk {
333 public:
PPC64R12SetupStub(Symbol & dest)334 PPC64R12SetupStub(Symbol &dest) : Thunk(dest, 0) { alignment = 16; }
size()335 uint32_t size() override { return 32; }
336 void writeTo(uint8_t *buf) override;
337 void addSymbols(ThunkSection &isec) override;
338 bool isCompatibleWith(const InputSection &isec,
339 const Relocation &rel) const override;
340 };
341
342 // PPC64 PC-relative PLT Stub
343 // When a caller that does not maintain a toc-pointer performs an extern call
344 // then this stub is needed for:
345 // 1) Loading the target functions address from the procedure linkage table into
346 // r12 for use by the target functions global entry point, and into the count
347 // register with pc-relative instructions.
348 // 2) Transferring control to the target function through an indirect branch.
349 class PPC64PCRelPLTStub final : public Thunk {
350 public:
PPC64PCRelPLTStub(Symbol & dest)351 PPC64PCRelPLTStub(Symbol &dest) : Thunk(dest, 0) { alignment = 16; }
size()352 uint32_t size() override { return 32; }
353 void writeTo(uint8_t *buf) override;
354 void addSymbols(ThunkSection &isec) override;
355 bool isCompatibleWith(const InputSection &isec,
356 const Relocation &rel) const override;
357 };
358
359 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
360 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is
361 // larger than that we need to emit a long-branch thunk. The target address
362 // of the callee is stored in a table to be accessed TOC-relative. Since the
363 // call must be local (a non-local call will have a PltCallStub instead) the
364 // table stores the address of the callee's local entry point. For
365 // position-independent code a corresponding relative dynamic relocation is
366 // used.
367 class PPC64LongBranchThunk : public Thunk {
368 public:
size()369 uint32_t size() override { return 32; }
370 void writeTo(uint8_t *buf) override;
371 void addSymbols(ThunkSection &isec) override;
372 bool isCompatibleWith(const InputSection &isec,
373 const Relocation &rel) const override;
374
375 protected:
PPC64LongBranchThunk(Symbol & dest,int64_t addend)376 PPC64LongBranchThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
377 };
378
379 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
380 public:
PPC64PILongBranchThunk(Symbol & dest,int64_t addend)381 PPC64PILongBranchThunk(Symbol &dest, int64_t addend)
382 : PPC64LongBranchThunk(dest, addend) {
383 assert(!dest.isPreemptible);
384 if (Optional<uint32_t> index =
385 in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
386 mainPart->relaDyn->addRelativeReloc(
387 target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
388 dest, addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther),
389 target->symbolicRel, R_ABS);
390 }
391 }
392 };
393
394 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
395 public:
PPC64PDLongBranchThunk(Symbol & dest,int64_t addend)396 PPC64PDLongBranchThunk(Symbol &dest, int64_t addend)
397 : PPC64LongBranchThunk(dest, addend) {
398 in.ppc64LongBranchTarget->addEntry(&dest, addend);
399 }
400 };
401
402 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
403 // alignment. This gives a possible 26 bits of 'reach'. If the caller and
404 // callee do not use toc and the call offset is larger than 26 bits,
405 // we need to emit a pc-rel based long-branch thunk. The target address of
406 // the callee is computed with a PC-relative offset.
407 class PPC64PCRelLongBranchThunk final : public Thunk {
408 public:
PPC64PCRelLongBranchThunk(Symbol & dest,int64_t addend)409 PPC64PCRelLongBranchThunk(Symbol &dest, int64_t addend)
410 : Thunk(dest, addend) {
411 alignment = 16;
412 }
size()413 uint32_t size() override { return 32; }
414 void writeTo(uint8_t *buf) override;
415 void addSymbols(ThunkSection &isec) override;
416 bool isCompatibleWith(const InputSection &isec,
417 const Relocation &rel) const override;
418 };
419
420 } // end anonymous namespace
421
addSymbol(StringRef name,uint8_t type,uint64_t value,InputSectionBase & section)422 Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
423 InputSectionBase §ion) {
424 Defined *d = addSyntheticLocal(name, type, value, /*size=*/0, section);
425 syms.push_back(d);
426 return d;
427 }
428
setOffset(uint64_t newOffset)429 void Thunk::setOffset(uint64_t newOffset) {
430 for (Defined *d : syms)
431 d->value = d->value - offset + newOffset;
432 offset = newOffset;
433 }
434
435 // AArch64 long range Thunks
436
getAArch64ThunkDestVA(const Symbol & s,int64_t a)437 static uint64_t getAArch64ThunkDestVA(const Symbol &s, int64_t a) {
438 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA(a);
439 return v;
440 }
441
writeTo(uint8_t * buf)442 void AArch64ABSLongThunk::writeTo(uint8_t *buf) {
443 const uint8_t data[] = {
444 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
445 0x00, 0x02, 0x1f, 0xd6, // br x16
446 0x00, 0x00, 0x00, 0x00, // L0: .xword S
447 0x00, 0x00, 0x00, 0x00,
448 };
449 uint64_t s = getAArch64ThunkDestVA(destination, addend);
450 memcpy(buf, data, sizeof(data));
451 target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
452 }
453
addSymbols(ThunkSection & isec)454 void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
455 addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
456 STT_FUNC, 0, isec);
457 addSymbol("$x", STT_NOTYPE, 0, isec);
458 addSymbol("$d", STT_NOTYPE, 8, isec);
459 }
460
461 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
462 // using the small code model, including pc-relative ones. At time of writing
463 // clang and gcc do not support the large code model for position independent
464 // code so it is safe to use this for position independent thunks without
465 // worrying about the destination being more than 4Gb away.
writeTo(uint8_t * buf)466 void AArch64ADRPThunk::writeTo(uint8_t *buf) {
467 const uint8_t data[] = {
468 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
469 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
470 0x00, 0x02, 0x1f, 0xd6, // br x16
471 };
472 uint64_t s = getAArch64ThunkDestVA(destination, addend);
473 uint64_t p = getThunkTargetSym()->getVA();
474 memcpy(buf, data, sizeof(data));
475 target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
476 getAArch64Page(s) - getAArch64Page(p));
477 target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
478 }
479
addSymbols(ThunkSection & isec)480 void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
481 addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
482 0, isec);
483 addSymbol("$x", STT_NOTYPE, 0, isec);
484 }
485
486 // ARM Target Thunks
getARMThunkDestVA(const Symbol & s)487 static uint64_t getARMThunkDestVA(const Symbol &s) {
488 uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA();
489 return SignExtend64<32>(v);
490 }
491
492 // This function returns true if the target is not Thumb and is within 2^26, and
493 // it has not previously returned false (see comment for mayUseShortThunk).
getMayUseShortThunk()494 bool ARMThunk::getMayUseShortThunk() {
495 if (!mayUseShortThunk)
496 return false;
497 uint64_t s = getARMThunkDestVA(destination);
498 if (s & 1) {
499 mayUseShortThunk = false;
500 return false;
501 }
502 uint64_t p = getThunkTargetSym()->getVA();
503 int64_t offset = s - p - 8;
504 mayUseShortThunk = llvm::isInt<26>(offset);
505 return mayUseShortThunk;
506 }
507
writeTo(uint8_t * buf)508 void ARMThunk::writeTo(uint8_t *buf) {
509 if (!getMayUseShortThunk()) {
510 writeLong(buf);
511 return;
512 }
513
514 uint64_t s = getARMThunkDestVA(destination);
515 uint64_t p = getThunkTargetSym()->getVA();
516 int64_t offset = s - p - 8;
517 const uint8_t data[] = {
518 0x00, 0x00, 0x00, 0xea, // b S
519 };
520 memcpy(buf, data, sizeof(data));
521 target->relocateNoSym(buf, R_ARM_JUMP24, offset);
522 }
523
isCompatibleWith(const InputSection & isec,const Relocation & rel) const524 bool ARMThunk::isCompatibleWith(const InputSection &isec,
525 const Relocation &rel) const {
526 // Thumb branch relocations can't use BLX
527 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
528 }
529
530 // This function returns true if the target is Thumb and is within 2^25, and
531 // it has not previously returned false (see comment for mayUseShortThunk).
getMayUseShortThunk()532 bool ThumbThunk::getMayUseShortThunk() {
533 if (!mayUseShortThunk)
534 return false;
535 uint64_t s = getARMThunkDestVA(destination);
536 if ((s & 1) == 0) {
537 mayUseShortThunk = false;
538 return false;
539 }
540 uint64_t p = getThunkTargetSym()->getVA() & ~1;
541 int64_t offset = s - p - 4;
542 mayUseShortThunk = llvm::isInt<25>(offset);
543 return mayUseShortThunk;
544 }
545
writeTo(uint8_t * buf)546 void ThumbThunk::writeTo(uint8_t *buf) {
547 if (!getMayUseShortThunk()) {
548 writeLong(buf);
549 return;
550 }
551
552 uint64_t s = getARMThunkDestVA(destination);
553 uint64_t p = getThunkTargetSym()->getVA();
554 int64_t offset = s - p - 4;
555 const uint8_t data[] = {
556 0x00, 0xf0, 0x00, 0xb0, // b.w S
557 };
558 memcpy(buf, data, sizeof(data));
559 target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
560 }
561
isCompatibleWith(const InputSection & isec,const Relocation & rel) const562 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
563 const Relocation &rel) const {
564 // ARM branch relocations can't use BLX
565 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
566 }
567
writeLong(uint8_t * buf)568 void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
569 const uint8_t data[] = {
570 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
571 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
572 0x1c, 0xff, 0x2f, 0xe1, // bx ip
573 };
574 uint64_t s = getARMThunkDestVA(destination);
575 memcpy(buf, data, sizeof(data));
576 target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
577 target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
578 }
579
addSymbols(ThunkSection & isec)580 void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
581 addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
582 STT_FUNC, 0, isec);
583 addSymbol("$a", STT_NOTYPE, 0, isec);
584 }
585
writeLong(uint8_t * buf)586 void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
587 const uint8_t data[] = {
588 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
589 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
590 0x60, 0x47, // bx ip
591 };
592 uint64_t s = getARMThunkDestVA(destination);
593 memcpy(buf, data, sizeof(data));
594 target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
595 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
596 }
597
addSymbols(ThunkSection & isec)598 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
599 addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
600 STT_FUNC, 1, isec);
601 addSymbol("$t", STT_NOTYPE, 0, isec);
602 }
603
writeLong(uint8_t * buf)604 void ARMV7PILongThunk::writeLong(uint8_t *buf) {
605 const uint8_t data[] = {
606 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
607 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
608 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
609 0x1c, 0xff, 0x2f, 0xe1, // bx ip
610 };
611 uint64_t s = getARMThunkDestVA(destination);
612 uint64_t p = getThunkTargetSym()->getVA();
613 int64_t offset = s - p - 16;
614 memcpy(buf, data, sizeof(data));
615 target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
616 target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
617 }
618
addSymbols(ThunkSection & isec)619 void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
620 addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
621 0, isec);
622 addSymbol("$a", STT_NOTYPE, 0, isec);
623 }
624
writeLong(uint8_t * buf)625 void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
626 const uint8_t data[] = {
627 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
628 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
629 0xfc, 0x44, // L1: add ip, pc
630 0x60, 0x47, // bx ip
631 };
632 uint64_t s = getARMThunkDestVA(destination);
633 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
634 int64_t offset = s - p - 12;
635 memcpy(buf, data, sizeof(data));
636 target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
637 target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
638 }
639
addSymbols(ThunkSection & isec)640 void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
641 addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
642 STT_FUNC, 1, isec);
643 addSymbol("$t", STT_NOTYPE, 0, isec);
644 }
645
writeLong(uint8_t * buf)646 void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
647 const uint8_t data[] = {
648 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
649 0x00, 0x00, 0x00, 0x00, // L1: .word S
650 };
651 memcpy(buf, data, sizeof(data));
652 target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
653 }
654
addSymbols(ThunkSection & isec)655 void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
656 addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
657 STT_FUNC, 0, isec);
658 addSymbol("$a", STT_NOTYPE, 0, isec);
659 addSymbol("$d", STT_NOTYPE, 4, isec);
660 }
661
isCompatibleWith(const InputSection & isec,const Relocation & rel) const662 bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec,
663 const Relocation &rel) const {
664 // Thumb branch relocations can't use BLX
665 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
666 }
667
writeLong(uint8_t * buf)668 void ARMV5PILongThunk::writeLong(uint8_t *buf) {
669 const uint8_t data[] = {
670 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
671 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
672 0x1c, 0xff, 0x2f, 0xe1, // bx ip
673 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
674 };
675 uint64_t s = getARMThunkDestVA(destination);
676 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
677 memcpy(buf, data, sizeof(data));
678 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
679 }
680
addSymbols(ThunkSection & isec)681 void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
682 addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
683 0, isec);
684 addSymbol("$a", STT_NOTYPE, 0, isec);
685 addSymbol("$d", STT_NOTYPE, 12, isec);
686 }
687
isCompatibleWith(const InputSection & isec,const Relocation & rel) const688 bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec,
689 const Relocation &rel) const {
690 // Thumb branch relocations can't use BLX
691 return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
692 }
693
writeLong(uint8_t * buf)694 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
695 // Most Thumb instructions cannot access the high registers r8 - r15. As the
696 // only register we can corrupt is r12 we must instead spill a low register
697 // to the stack to use as a scratch register. We push r1 even though we
698 // don't need to get some space to use for the return address.
699 const uint8_t data[] = {
700 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
701 0x01, 0x48, // ldr r0, [pc, #4] ; L1
702 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
703 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
704 0x00, 0x00, 0x00, 0x00 // L1: .word S
705 };
706 uint64_t s = getARMThunkDestVA(destination);
707 memcpy(buf, data, sizeof(data));
708 target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
709 }
710
addSymbols(ThunkSection & isec)711 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
712 addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
713 STT_FUNC, 1, isec);
714 addSymbol("$t", STT_NOTYPE, 0, isec);
715 addSymbol("$d", STT_NOTYPE, 8, isec);
716 }
717
writeLong(uint8_t * buf)718 void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
719 // Most Thumb instructions cannot access the high registers r8 - r15. As the
720 // only register we can corrupt is ip (r12) we must instead spill a low
721 // register to the stack to use as a scratch register.
722 const uint8_t data[] = {
723 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
724 0x02, 0x48, // ldr r0, [pc, #8] ; L2
725 0x84, 0x46, // mov ip, r0 ; high to low register
726 0x01, 0xbc, // pop {r0} ; restore scratch register
727 0xe7, 0x44, // L1: add pc, ip ; transfer control
728 0xc0, 0x46, // nop ; pad to 4-byte boundary
729 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
730 };
731 uint64_t s = getARMThunkDestVA(destination);
732 uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
733 memcpy(buf, data, sizeof(data));
734 target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
735 }
736
addSymbols(ThunkSection & isec)737 void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
738 addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
739 STT_FUNC, 1, isec);
740 addSymbol("$t", STT_NOTYPE, 0, isec);
741 addSymbol("$d", STT_NOTYPE, 12, isec);
742 }
743
744 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
writeTo(uint8_t * buf)745 void MipsThunk::writeTo(uint8_t *buf) {
746 uint64_t s = destination.getVA();
747 write32(buf, 0x3c190000); // lui $25, %hi(func)
748 write32(buf + 4, 0x08000000 | (s >> 2)); // j func
749 write32(buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
750 write32(buf + 12, 0x00000000); // nop
751 target->relocateNoSym(buf, R_MIPS_HI16, s);
752 target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
753 }
754
addSymbols(ThunkSection & isec)755 void MipsThunk::addSymbols(ThunkSection &isec) {
756 addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
757 isec);
758 }
759
getTargetInputSection() const760 InputSection *MipsThunk::getTargetInputSection() const {
761 auto &dr = cast<Defined>(destination);
762 return dyn_cast<InputSection>(dr.section);
763 }
764
765 // Write microMIPS R2-R5 LA25 thunk code
766 // to call PIC function from the non-PIC one.
writeTo(uint8_t * buf)767 void MicroMipsThunk::writeTo(uint8_t *buf) {
768 uint64_t s = destination.getVA();
769 write16(buf, 0x41b9); // lui $25, %hi(func)
770 write16(buf + 4, 0xd400); // j func
771 write16(buf + 8, 0x3339); // addiu $25, $25, %lo(func)
772 write16(buf + 12, 0x0c00); // nop
773 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
774 target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
775 target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
776 }
777
addSymbols(ThunkSection & isec)778 void MicroMipsThunk::addSymbols(ThunkSection &isec) {
779 Defined *d = addSymbol(
780 saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
781 d->stOther |= STO_MIPS_MICROMIPS;
782 }
783
getTargetInputSection() const784 InputSection *MicroMipsThunk::getTargetInputSection() const {
785 auto &dr = cast<Defined>(destination);
786 return dyn_cast<InputSection>(dr.section);
787 }
788
789 // Write microMIPS R6 LA25 thunk code
790 // to call PIC function from the non-PIC one.
writeTo(uint8_t * buf)791 void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
792 uint64_t s = destination.getVA();
793 uint64_t p = getThunkTargetSym()->getVA();
794 write16(buf, 0x1320); // lui $25, %hi(func)
795 write16(buf + 4, 0x3339); // addiu $25, $25, %lo(func)
796 write16(buf + 8, 0x9400); // bc func
797 target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
798 target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
799 target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
800 }
801
addSymbols(ThunkSection & isec)802 void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
803 Defined *d = addSymbol(
804 saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
805 d->stOther |= STO_MIPS_MICROMIPS;
806 }
807
getTargetInputSection() const808 InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
809 auto &dr = cast<Defined>(destination);
810 return dyn_cast<InputSection>(dr.section);
811 }
812
writePPC32PltCallStub(uint8_t * buf,uint64_t gotPltVA,const InputFile * file,int64_t addend)813 void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
814 const InputFile *file, int64_t addend) {
815 if (!config->isPic) {
816 write32(buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
817 write32(buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
818 write32(buf + 8, 0x7d6903a6); // mtctr r11
819 write32(buf + 12, 0x4e800420); // bctr
820 return;
821 }
822 uint32_t offset;
823 if (addend >= 0x8000) {
824 // The stub loads an address relative to r30 (.got2+Addend). Addend is
825 // almost always 0x8000. The address of .got2 is different in another object
826 // file, so a stub cannot be shared.
827 offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
828 file->ppc32Got2OutSecOff + addend);
829 } else {
830 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
831 // currently the address of .got).
832 offset = gotPltVA - in.got->getVA();
833 }
834 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
835 if (ha == 0) {
836 write32(buf + 0, 0x817e0000 | l); // lwz r11,l(r30)
837 write32(buf + 4, 0x7d6903a6); // mtctr r11
838 write32(buf + 8, 0x4e800420); // bctr
839 write32(buf + 12, 0x60000000); // nop
840 } else {
841 write32(buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha
842 write32(buf + 4, 0x816b0000 | l); // lwz r11,l(r11)
843 write32(buf + 8, 0x7d6903a6); // mtctr r11
844 write32(buf + 12, 0x4e800420); // bctr
845 }
846 }
847
writeTo(uint8_t * buf)848 void PPC32PltCallStub::writeTo(uint8_t *buf) {
849 writePPC32PltCallStub(buf, destination.getGotPltVA(), file, addend);
850 }
851
addSymbols(ThunkSection & isec)852 void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
853 std::string buf;
854 raw_string_ostream os(buf);
855 os << format_hex_no_prefix(addend, 8);
856 if (!config->isPic)
857 os << ".plt_call32.";
858 else if (addend >= 0x8000)
859 os << ".got2.plt_pic32.";
860 else
861 os << ".plt_pic32.";
862 os << destination.getName();
863 addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
864 }
865
isCompatibleWith(const InputSection & isec,const Relocation & rel) const866 bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
867 const Relocation &rel) const {
868 return !config->isPic || (isec.file == file && rel.addend == addend);
869 }
870
addSymbols(ThunkSection & isec)871 void PPC32LongThunk::addSymbols(ThunkSection &isec) {
872 addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
873 isec);
874 }
875
writeTo(uint8_t * buf)876 void PPC32LongThunk::writeTo(uint8_t *buf) {
877 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
878 auto lo = [](uint32_t v) -> uint16_t { return v; };
879 uint32_t d = destination.getVA(addend);
880 if (config->isPic) {
881 uint32_t off = d - (getThunkTargetSym()->getVA() + 8);
882 write32(buf + 0, 0x7c0802a6); // mflr r12,0
883 write32(buf + 4, 0x429f0005); // bcl r20,r31,.+4
884 write32(buf + 8, 0x7d8802a6); // mtctr r12
885 write32(buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
886 write32(buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
887 write32(buf + 20, 0x7c0803a6); // mtlr r0
888 buf += 24;
889 } else {
890 write32(buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
891 write32(buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
892 buf += 8;
893 }
894 write32(buf + 0, 0x7d8903a6); // mtctr r12
895 write32(buf + 4, 0x4e800420); // bctr
896 }
897
writePPC64LoadAndBranch(uint8_t * buf,int64_t offset)898 void elf::writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
899 uint16_t offHa = (offset + 0x8000) >> 16;
900 uint16_t offLo = offset & 0xffff;
901
902 write32(buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa
903 write32(buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)
904 write32(buf + 8, 0x7d8903a6); // mtctr r12
905 write32(buf + 12, 0x4e800420); // bctr
906 }
907
writeTo(uint8_t * buf)908 void PPC64PltCallStub::writeTo(uint8_t *buf) {
909 int64_t offset = destination.getGotPltVA() - getPPC64TocBase();
910 // Save the TOC pointer to the save-slot reserved in the call frame.
911 write32(buf + 0, 0xf8410018); // std r2,24(r1)
912 writePPC64LoadAndBranch(buf + 4, offset);
913 }
914
addSymbols(ThunkSection & isec)915 void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
916 Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
917 0, isec);
918 s->needsTocRestore = true;
919 s->file = destination.file;
920 }
921
isCompatibleWith(const InputSection & isec,const Relocation & rel) const922 bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
923 const Relocation &rel) const {
924 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
925 }
926
writeTo(uint8_t * buf)927 void PPC64R2SaveStub::writeTo(uint8_t *buf) {
928 const int64_t offset = computeOffset();
929 write32(buf + 0, 0xf8410018); // std r2,24(r1)
930 // The branch offset needs to fit in 26 bits.
931 if (getMayUseShortThunk()) {
932 write32(buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
933 } else if (isInt<34>(offset)) {
934 int nextInstOffset;
935 if (!config->Power10Stub) {
936 uint64_t tocOffset = destination.getVA() - getPPC64TocBase();
937 if (tocOffset >> 16 > 0) {
938 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
939 const uint64_t addis = ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
940 write32(buf + 4, addis); // addis r12, r2 , top of offset
941 write32(buf + 8, addi); // addi r12, r12, bottom of offset
942 nextInstOffset = 12;
943 } else {
944 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
945 write32(buf + 4, addi); // addi r12, r2, offset
946 nextInstOffset = 8;
947 }
948 } else {
949 const uint64_t paddi = PADDI_R12_NO_DISP |
950 (((offset >> 16) & 0x3ffff) << 32) |
951 (offset & 0xffff);
952 writePrefixedInstruction(buf + 4, paddi); // paddi r12, 0, func@pcrel, 1
953 nextInstOffset = 12;
954 }
955 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
956 write32(buf + nextInstOffset + 4, BCTR); // bctr
957 } else {
958 in.ppc64LongBranchTarget->addEntry(&destination, addend);
959 const int64_t offsetFromTOC =
960 in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
961 getPPC64TocBase();
962 writePPC64LoadAndBranch(buf + 4, offsetFromTOC);
963 }
964 }
965
addSymbols(ThunkSection & isec)966 void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
967 Defined *s = addSymbol(saver.save("__toc_save_" + destination.getName()),
968 STT_FUNC, 0, isec);
969 s->needsTocRestore = true;
970 }
971
isCompatibleWith(const InputSection & isec,const Relocation & rel) const972 bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
973 const Relocation &rel) const {
974 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
975 }
976
writeTo(uint8_t * buf)977 void PPC64R12SetupStub::writeTo(uint8_t *buf) {
978 int64_t offset = destination.getVA() - getThunkTargetSym()->getVA();
979 if (!isInt<34>(offset))
980 reportRangeError(buf, offset, 34, destination, "R12 setup stub offset");
981
982 int nextInstOffset;
983 if (!config->Power10Stub) {
984 uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
985 write32(buf + 0, 0x7c0802a6); // mflr r12
986 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
987 write32(buf + 8, 0x7d6802a6); // mflr r11
988 write32(buf + 12, 0x7d8803a6); // mtlr r12
989 write32(buf + 16, 0x3d8b0000 | computeHiBits(off));// addis r12,r11,off@ha
990 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
991 nextInstOffset = 24;
992 } else {
993 uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
994 (offset & 0xffff);
995 writePrefixedInstruction(buf + 0, paddi); // paddi r12, 0, func@pcrel, 1
996 nextInstOffset = 8;
997 }
998 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
999 write32(buf + nextInstOffset + 4, BCTR); // bctr
1000 }
1001
addSymbols(ThunkSection & isec)1002 void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
1003 addSymbol(saver.save("__gep_setup_" + destination.getName()), STT_FUNC, 0,
1004 isec);
1005 }
1006
isCompatibleWith(const InputSection & isec,const Relocation & rel) const1007 bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
1008 const Relocation &rel) const {
1009 return rel.type == R_PPC64_REL24_NOTOC;
1010 }
1011
writeTo(uint8_t * buf)1012 void PPC64PCRelPLTStub::writeTo(uint8_t *buf) {
1013 int nextInstOffset = 0;
1014 int64_t offset = destination.getGotPltVA() - getThunkTargetSym()->getVA();
1015
1016 if (config->Power10Stub) {
1017 if (!isInt<34>(offset))
1018 reportRangeError(buf, offset, 34, destination,
1019 "PC-relative PLT stub offset");
1020 const uint64_t pld = PLD_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
1021 (offset & 0xffff);
1022 writePrefixedInstruction(buf + 0, pld); // pld r12, func@plt@pcrel
1023 nextInstOffset = 8;
1024 } else {
1025 uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
1026 write32(buf + 0, 0x7c0802a6); // mflr r12
1027 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
1028 write32(buf + 8, 0x7d6802a6); // mflr r11
1029 write32(buf + 12, 0x7d8803a6); // mtlr r12
1030 write32(buf + 16, 0x3d8b0000 | computeHiBits(off)); // addis r12,r11,off@ha
1031 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
1032 nextInstOffset = 24;
1033 }
1034 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
1035 write32(buf + nextInstOffset + 4, BCTR); // bctr
1036 }
1037
addSymbols(ThunkSection & isec)1038 void PPC64PCRelPLTStub::addSymbols(ThunkSection &isec) {
1039 addSymbol(saver.save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0,
1040 isec);
1041 }
1042
isCompatibleWith(const InputSection & isec,const Relocation & rel) const1043 bool PPC64PCRelPLTStub::isCompatibleWith(const InputSection &isec,
1044 const Relocation &rel) const {
1045 return rel.type == R_PPC64_REL24_NOTOC;
1046 }
1047
writeTo(uint8_t * buf)1048 void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
1049 int64_t offset = in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
1050 getPPC64TocBase();
1051 writePPC64LoadAndBranch(buf, offset);
1052 }
1053
addSymbols(ThunkSection & isec)1054 void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
1055 addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
1056 isec);
1057 }
1058
isCompatibleWith(const InputSection & isec,const Relocation & rel) const1059 bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
1060 const Relocation &rel) const {
1061 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
1062 }
1063
writeTo(uint8_t * buf)1064 void PPC64PCRelLongBranchThunk::writeTo(uint8_t *buf) {
1065 int64_t offset = destination.getVA() - getThunkTargetSym()->getVA();
1066 if (!isInt<34>(offset))
1067 reportRangeError(buf, offset, 34, destination,
1068 "PC-relative long branch stub offset");
1069
1070 int nextInstOffset;
1071 if (!config->Power10Stub) {
1072 uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
1073 write32(buf + 0, 0x7c0802a6); // mflr r12
1074 write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
1075 write32(buf + 8, 0x7d6802a6); // mflr r11
1076 write32(buf + 12, 0x7d8803a6); // mtlr r12
1077 write32(buf + 16, 0x3d8b0000 | computeHiBits(off)); // addis r12,r11,off@ha
1078 write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
1079 nextInstOffset = 24;
1080 } else {
1081 uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
1082 (offset & 0xffff);
1083 writePrefixedInstruction(buf + 0, paddi); // paddi r12, 0, func@pcrel, 1
1084 nextInstOffset = 8;
1085 }
1086 write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
1087 write32(buf + nextInstOffset + 4, BCTR); // bctr
1088 }
1089
addSymbols(ThunkSection & isec)1090 void PPC64PCRelLongBranchThunk::addSymbols(ThunkSection &isec) {
1091 addSymbol(saver.save("__long_branch_pcrel_" + destination.getName()),
1092 STT_FUNC, 0, isec);
1093 }
1094
isCompatibleWith(const InputSection & isec,const Relocation & rel) const1095 bool PPC64PCRelLongBranchThunk::isCompatibleWith(const InputSection &isec,
1096 const Relocation &rel) const {
1097 return rel.type == R_PPC64_REL24_NOTOC;
1098 }
1099
Thunk(Symbol & d,int64_t a)1100 Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {}
1101
1102 Thunk::~Thunk() = default;
1103
addThunkAArch64(RelType type,Symbol & s,int64_t a)1104 static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
1105 if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
1106 type != R_AARCH64_PLT32)
1107 fatal("unrecognized relocation type");
1108 if (config->picThunk)
1109 return make<AArch64ADRPThunk>(s, a);
1110 return make<AArch64ABSLongThunk>(s, a);
1111 }
1112
1113 // Creates a thunk for Thumb-ARM interworking.
1114 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means
1115 // - MOVT and MOVW instructions cannot be used
1116 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
1117 // be transformed into a BLX
addThunkPreArmv7(RelType reloc,Symbol & s,int64_t a)1118 static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s, int64_t a) {
1119 switch (reloc) {
1120 case R_ARM_PC24:
1121 case R_ARM_PLT32:
1122 case R_ARM_JUMP24:
1123 case R_ARM_CALL:
1124 case R_ARM_THM_CALL:
1125 if (config->picThunk)
1126 return make<ARMV5PILongThunk>(s, a);
1127 return make<ARMV5ABSLongThunk>(s, a);
1128 }
1129 fatal("relocation " + toString(reloc) + " to " + toString(s) +
1130 " not supported for Armv5 or Armv6 targets");
1131 }
1132
1133 // Create a thunk for Thumb long branch on V6-M.
1134 // Arm Architecture v6-M only supports Thumb instructions. This means
1135 // - MOVT and MOVW instructions cannot be used.
1136 // - Only a limited number of instructions can access registers r8 and above
1137 // - No interworking support is needed (all Thumb).
addThunkV6M(RelType reloc,Symbol & s,int64_t a)1138 static Thunk *addThunkV6M(RelType reloc, Symbol &s, int64_t a) {
1139 switch (reloc) {
1140 case R_ARM_THM_JUMP19:
1141 case R_ARM_THM_JUMP24:
1142 case R_ARM_THM_CALL:
1143 if (config->isPic)
1144 return make<ThumbV6MPILongThunk>(s, a);
1145 return make<ThumbV6MABSLongThunk>(s, a);
1146 }
1147 fatal("relocation " + toString(reloc) + " to " + toString(s) +
1148 " not supported for Armv6-M targets");
1149 }
1150
1151 // Creates a thunk for Thumb-ARM interworking or branch range extension.
addThunkArm(RelType reloc,Symbol & s,int64_t a)1152 static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
1153 // Decide which Thunk is needed based on:
1154 // Available instruction set
1155 // - An Arm Thunk can only be used if Arm state is available.
1156 // - A Thumb Thunk can only be used if Thumb state is available.
1157 // - Can only use a Thunk if it uses instructions that the Target supports.
1158 // Relocation is branch or branch and link
1159 // - Branch instructions cannot change state, can only select Thunk that
1160 // starts in the same state as the caller.
1161 // - Branch and link relocations can change state, can select Thunks from
1162 // either Arm or Thumb.
1163 // Position independent Thunks if we require position independent code.
1164
1165 // Handle architectures that have restrictions on the instructions that they
1166 // can use in Thunks. The flags below are set by reading the BuildAttributes
1167 // of the input objects. InputFiles.cpp contains the mapping from ARM
1168 // architecture to flag.
1169 if (!config->armHasMovtMovw) {
1170 if (!config->armJ1J2BranchEncoding)
1171 return addThunkPreArmv7(reloc, s, a);
1172 return addThunkV6M(reloc, s, a);
1173 }
1174
1175 switch (reloc) {
1176 case R_ARM_PC24:
1177 case R_ARM_PLT32:
1178 case R_ARM_JUMP24:
1179 case R_ARM_CALL:
1180 if (config->picThunk)
1181 return make<ARMV7PILongThunk>(s, a);
1182 return make<ARMV7ABSLongThunk>(s, a);
1183 case R_ARM_THM_JUMP19:
1184 case R_ARM_THM_JUMP24:
1185 case R_ARM_THM_CALL:
1186 if (config->picThunk)
1187 return make<ThumbV7PILongThunk>(s, a);
1188 return make<ThumbV7ABSLongThunk>(s, a);
1189 }
1190 fatal("unrecognized relocation type");
1191 }
1192
addThunkMips(RelType type,Symbol & s)1193 static Thunk *addThunkMips(RelType type, Symbol &s) {
1194 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6())
1195 return make<MicroMipsR6Thunk>(s);
1196 if (s.stOther & STO_MIPS_MICROMIPS)
1197 return make<MicroMipsThunk>(s);
1198 return make<MipsThunk>(s);
1199 }
1200
addThunkPPC32(const InputSection & isec,const Relocation & rel,Symbol & s)1201 static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
1202 Symbol &s) {
1203 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
1204 rel.type == R_PPC_PLTREL24) &&
1205 "unexpected relocation type for thunk");
1206 if (s.isInPlt())
1207 return make<PPC32PltCallStub>(isec, rel, s);
1208 return make<PPC32LongThunk>(s, rel.addend);
1209 }
1210
addThunkPPC64(RelType type,Symbol & s,int64_t a)1211 static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
1212 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
1213 type == R_PPC64_REL24_NOTOC) &&
1214 "unexpected relocation type for thunk");
1215 if (s.isInPlt())
1216 return type == R_PPC64_REL24_NOTOC ? (Thunk *)make<PPC64PCRelPLTStub>(s)
1217 : (Thunk *)make<PPC64PltCallStub>(s);
1218
1219 // This check looks at the st_other bits of the callee. If the value is 1
1220 // then the callee clobbers the TOC and we need an R2 save stub when RelType
1221 // is R_PPC64_REL14 or R_PPC64_REL24.
1222 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
1223 return make<PPC64R2SaveStub>(s, a);
1224
1225 if (type == R_PPC64_REL24_NOTOC)
1226 return (s.stOther >> 5) > 1
1227 ? (Thunk *)make<PPC64R12SetupStub>(s)
1228 : (Thunk *)make<PPC64PCRelLongBranchThunk>(s, a);
1229
1230 if (config->picThunk)
1231 return make<PPC64PILongBranchThunk>(s, a);
1232
1233 return make<PPC64PDLongBranchThunk>(s, a);
1234 }
1235
addThunk(const InputSection & isec,Relocation & rel)1236 Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
1237 Symbol &s = *rel.sym;
1238 int64_t a = rel.addend;
1239
1240 if (config->emachine == EM_AARCH64)
1241 return addThunkAArch64(rel.type, s, a);
1242
1243 if (config->emachine == EM_ARM)
1244 return addThunkArm(rel.type, s, a);
1245
1246 if (config->emachine == EM_MIPS)
1247 return addThunkMips(rel.type, s);
1248
1249 if (config->emachine == EM_PPC)
1250 return addThunkPPC32(isec, rel, s);
1251
1252 if (config->emachine == EM_PPC64)
1253 return addThunkPPC64(rel.type, s, a);
1254
1255 llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
1256 }
1257