1847 lines · cpp
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-exception6//7//===---------------------------------------------------------------------===//8//9// This file contains Thunk subclasses.10//11// A thunk is a small piece of code written after an input section12// which is used to jump between "incompatible" functions13// 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 a16// short jump instruction, we need to create a thunk too, but we17// haven't supported it yet.18//19// i386 and x86-64 don't need thunks.20//21//===---------------------------------------------------------------------===//22 23#include "Thunks.h"24#include "Config.h"25#include "InputFiles.h"26#include "InputSection.h"27#include "OutputSections.h"28#include "Symbols.h"29#include "SyntheticSections.h"30#include "Target.h"31#include "lld/Common/CommonLinkerContext.h"32#include "llvm/BinaryFormat/ELF.h"33#include "llvm/Support/Casting.h"34#include "llvm/Support/ErrorHandling.h"35#include "llvm/Support/MathExtras.h"36#include <cstdint>37#include <cstring>38 39using namespace llvm;40using namespace llvm::object;41using namespace llvm::ELF;42using namespace lld;43using namespace lld::elf;44 45namespace {46 47// Base class for AArch64 thunks.48//49// An AArch64 thunk may be either short or long. A short thunk is simply a50// branch (B) instruction, and it may be used to call AArch64 functions when the51// distance from the thunk to the target is less than 128MB. Long thunks can52// branch to any virtual address and they are implemented in the derived53// 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 branches55// must land on a BTI instruction. If the destination does not have a BTI56// instruction mayNeedLandingPad is set to true and Thunk::landingPad points57// to an alternative entry point with a BTI.58class AArch64Thunk : public Thunk {59public:60 AArch64Thunk(Ctx &ctx, Symbol &dest, int64_t addend, bool mayNeedLandingPad)61 : Thunk(ctx, dest, addend), mayNeedLandingPad(mayNeedLandingPad) {}62 bool getMayUseShortThunk();63 void writeTo(uint8_t *buf) override;64 bool needsSyntheticLandingPad() override;65 66protected:67 bool mayNeedLandingPad;68 69private:70 bool mayUseShortThunk = true;71 virtual void writeLong(uint8_t *buf) = 0;72 // A thunk may be written out as a short or long, and we may not know which73 // type at thunk creation time. In some thunk implementations the long thunk74 // has additional mapping symbols. Thus function can be overridden to add75 // these additional mapping symbols.76 virtual void addLongMapSyms() {}77};78 79// AArch64 long range Thunks.80class AArch64ABSLongThunk final : public AArch64Thunk {81public:82 AArch64ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,83 bool mayNeedLandingPad)84 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}85 uint32_t size() override { return getMayUseShortThunk() ? 4 : 16; }86 void addSymbols(ThunkSection &isec) override;87 88private:89 void writeLong(uint8_t *buf) override;90 void addLongMapSyms() override;91 ThunkSection *tsec = nullptr;92};93 94// AArch64 long range Thunks compatible with execute-only code.95class AArch64ABSXOLongThunk final : public AArch64Thunk {96public:97 AArch64ABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,98 bool mayNeedLandingPad)99 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}100 uint32_t size() override { return getMayUseShortThunk() ? 4 : 20; }101 void addSymbols(ThunkSection &sec) override;102 103private:104 void writeLong(uint8_t *buf) override;105};106 107class AArch64ADRPThunk final : public AArch64Thunk {108public:109 AArch64ADRPThunk(Ctx &ctx, Symbol &dest, int64_t addend,110 bool mayNeedLandingPad)111 : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}112 uint32_t size() override { return getMayUseShortThunk() ? 4 : 12; }113 void addSymbols(ThunkSection &isec) override;114 115private:116 void writeLong(uint8_t *buf) override;117};118 119// AArch64 BTI Landing Pad120// When BTI is enabled indirect branches must land on a BTI121// compatible instruction. When the destination does not have a122// BTI compatible instruction a Thunk doing an indirect branch123// targets a Landing Pad Thunk that direct branches to the target.124class AArch64BTILandingPadThunk final : public Thunk {125public:126 AArch64BTILandingPadThunk(Ctx &ctx, Symbol &dest, int64_t addend)127 : Thunk(ctx, dest, addend) {}128 129 uint32_t size() override { return getMayUseShortThunk() ? 4 : 8; }130 void addSymbols(ThunkSection &isec) override;131 void writeTo(uint8_t *buf) override;132 133private:134 bool getMayUseShortThunk();135 void writeLong(uint8_t *buf);136 bool mayUseShortThunk = true;137};138 139// Base class for ARM thunks.140//141// An ARM thunk may be either short or long. A short thunk is simply a branch142// (B) instruction, and it may be used to call ARM functions when the distance143// from the thunk to the target is less than 32MB. Long thunks can branch to any144// virtual address and can switch between ARM and Thumb, and they are145// implemented in the derived classes. This class tries to create a short thunk146// if the target is in range, otherwise it creates a long thunk.147class ARMThunk : public Thunk {148public:149 ARMThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}150 151 bool getMayUseShortThunk();152 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }153 void writeTo(uint8_t *buf) override;154 bool isCompatibleWith(const InputSection &isec,155 const Relocation &rel) const override;156 157 // Returns the size of a long thunk.158 virtual uint32_t sizeLong() = 0;159 160 // Writes a long thunk to Buf.161 virtual void writeLong(uint8_t *buf) = 0;162 163private:164 // This field tracks whether all previously considered layouts would allow165 // this thunk to be short. If we have ever needed a long thunk, we always166 // create a long thunk, even if the thunk may be short given the current167 // distance to the target. We do this because transitioning from long to short168 // can create layout oscillations in certain corner cases which would prevent169 // the layout from converging.170 bool mayUseShortThunk = true;171 // See comment in AArch64Thunk.172 virtual void addLongMapSyms() {}173};174 175// Base class for Thumb-2 thunks.176//177// This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction178// which has a range of 16MB.179class ThumbThunk : public Thunk {180public:181 ThumbThunk(Ctx &ctx, Symbol &dest, int64_t addend)182 : Thunk(ctx, dest, addend) {183 alignment = 2;184 }185 186 bool getMayUseShortThunk();187 uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }188 void writeTo(uint8_t *buf) override;189 bool isCompatibleWith(const InputSection &isec,190 const Relocation &rel) const override;191 192 // Returns the size of a long thunk.193 virtual uint32_t sizeLong() = 0;194 195 // Writes a long thunk to Buf.196 virtual void writeLong(uint8_t *buf) = 0;197 198private:199 // See comment in ARMThunk above.200 bool mayUseShortThunk = true;201 // See comment in AArch64Thunk.202 virtual void addLongMapSyms() {}203};204 205// Specific ARM Thunk implementations. The naming convention is:206// Source State, TargetState, Target Requirement, ABS or PI, Range207class ARMV7ABSLongThunk final : public ARMThunk {208public:209 ARMV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)210 : ARMThunk(ctx, dest, addend) {}211 212 uint32_t sizeLong() override { return 12; }213 void writeLong(uint8_t *buf) override;214 void addSymbols(ThunkSection &isec) override;215};216 217class ARMV7PILongThunk final : public ARMThunk {218public:219 ARMV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)220 : ARMThunk(ctx, dest, addend) {}221 222 uint32_t sizeLong() override { return 16; }223 void writeLong(uint8_t *buf) override;224 void addSymbols(ThunkSection &isec) override;225};226 227class ThumbV7ABSLongThunk final : public ThumbThunk {228public:229 ThumbV7ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)230 : ThumbThunk(ctx, dest, addend) {}231 232 uint32_t sizeLong() override { return 10; }233 void writeLong(uint8_t *buf) override;234 void addSymbols(ThunkSection &isec) override;235};236 237class ThumbV7PILongThunk final : public ThumbThunk {238public:239 ThumbV7PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)240 : ThumbThunk(ctx, dest, addend) {}241 242 uint32_t sizeLong() override { return 12; }243 void writeLong(uint8_t *buf) override;244 void addSymbols(ThunkSection &isec) override;245};246 247// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted248class ThumbV6MABSLongThunk final : public ThumbThunk {249public:250 ThumbV6MABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)251 : ThumbThunk(ctx, dest, addend) {}252 253 uint32_t sizeLong() override { return 12; }254 void writeLong(uint8_t *buf) override;255 void addSymbols(ThunkSection &isec) override;256 257private:258 void addLongMapSyms() override;259 ThunkSection *tsec = nullptr;260};261 262class ThumbV6MABSXOLongThunk final : public ThumbThunk {263public:264 ThumbV6MABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)265 : ThumbThunk(ctx, dest, addend) {}266 267 uint32_t sizeLong() override { return 20; }268 void writeLong(uint8_t *buf) override;269 void addSymbols(ThunkSection &isec) override;270};271 272class ThumbV6MPILongThunk final : public ThumbThunk {273public:274 ThumbV6MPILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)275 : ThumbThunk(ctx, dest, addend) {}276 277 uint32_t sizeLong() override { return 16; }278 void writeLong(uint8_t *buf) override;279 void addSymbols(ThunkSection &isec) override;280 281private:282 void addLongMapSyms() override;283 ThunkSection *tsec = nullptr;284};285 286// Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and287// v6 support BLX to which BL instructions can be rewritten inline. There are no288// Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on289// 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. v4293// can also use this thunk, but only for Arm->Arm calls.294class ARMV5LongLdrPcThunk final : public ARMThunk {295public:296 ARMV5LongLdrPcThunk(Ctx &ctx, Symbol &dest, int64_t addend)297 : ARMThunk(ctx, dest, addend) {}298 299 uint32_t sizeLong() override { return 8; }300 void writeLong(uint8_t *buf) override;301 void addSymbols(ThunkSection &isec) override;302 303private:304 void addLongMapSyms() override;305 ThunkSection *tsec = nullptr;306};307 308// Implementations of Thunks for v4. BLX is not supported, and loads309// will not invoke Arm/Thumb state changes.310class ARMV4PILongBXThunk final : public ARMThunk {311public:312 ARMV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)313 : ARMThunk(ctx, dest, addend) {}314 315 uint32_t sizeLong() override { return 16; }316 void writeLong(uint8_t *buf) override;317 void addSymbols(ThunkSection &isec) override;318 319private:320 void addLongMapSyms() override;321 ThunkSection *tsec = nullptr;322};323 324class ARMV4PILongThunk final : public ARMThunk {325public:326 ARMV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)327 : ARMThunk(ctx, dest, addend) {}328 329 uint32_t sizeLong() override { return 12; }330 void writeLong(uint8_t *buf) override;331 void addSymbols(ThunkSection &isec) override;332 333private:334 void addLongMapSyms() override;335 ThunkSection *tsec = nullptr;336};337 338class ThumbV4PILongBXThunk final : public ThumbThunk {339public:340 ThumbV4PILongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)341 : ThumbThunk(ctx, dest, addend) {}342 343 uint32_t sizeLong() override { return 16; }344 void writeLong(uint8_t *buf) override;345 void addSymbols(ThunkSection &isec) override;346 347private:348 void addLongMapSyms() override;349 ThunkSection *tsec = nullptr;350};351 352class ThumbV4PILongThunk final : public ThumbThunk {353public:354 ThumbV4PILongThunk(Ctx &ctx, Symbol &dest, int64_t addend)355 : ThumbThunk(ctx, dest, addend) {}356 357 uint32_t sizeLong() override { return 20; }358 void writeLong(uint8_t *buf) override;359 void addSymbols(ThunkSection &isec) override;360 361private:362 void addLongMapSyms() override;363 ThunkSection *tsec = nullptr;364};365 366class ARMV4ABSLongBXThunk final : public ARMThunk {367public:368 ARMV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)369 : ARMThunk(ctx, dest, addend) {}370 371 uint32_t sizeLong() override { return 12; }372 void writeLong(uint8_t *buf) override;373 void addSymbols(ThunkSection &isec) override;374 375private:376 void addLongMapSyms() override;377 ThunkSection *tsec = nullptr;378};379 380class ThumbV4ABSLongBXThunk final : public ThumbThunk {381public:382 ThumbV4ABSLongBXThunk(Ctx &ctx, Symbol &dest, int64_t addend)383 : ThumbThunk(ctx, dest, addend) {}384 385 uint32_t sizeLong() override { return 12; }386 void writeLong(uint8_t *buf) override;387 void addSymbols(ThunkSection &isec) override;388 389private:390 void addLongMapSyms() override;391 ThunkSection *tsec = nullptr;392};393 394class ThumbV4ABSLongThunk final : public ThumbThunk {395public:396 ThumbV4ABSLongThunk(Ctx &ctx, Symbol &dest, int64_t addend)397 : ThumbThunk(ctx, dest, addend) {}398 399 uint32_t sizeLong() override { return 16; }400 void writeLong(uint8_t *buf) override;401 void addSymbols(ThunkSection &isec) override;402 403private:404 void addLongMapSyms() override;405 ThunkSection *tsec = nullptr;406};407 408// The AVR devices need thunks for R_AVR_LO8_LDI_GS/R_AVR_HI8_LDI_GS409// when their destination is out of range [0, 0x1ffff].410class AVRThunk : public Thunk {411public:412 AVRThunk(Ctx &ctx, Symbol &dest, int64_t addend) : Thunk(ctx, dest, addend) {}413 uint32_t size() override { return 4; }414 void writeTo(uint8_t *buf) override;415 void addSymbols(ThunkSection &isec) override;416};417 418// 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 of420// range.421class HexagonThunk : public Thunk {422public: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;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 thunk435class MipsThunk final : public Thunk {436public:437 MipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}438 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 thunk446class MicroMipsThunk final : public Thunk {447public:448 MicroMipsThunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}449 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 thunk457class MicroMipsR6Thunk final : public Thunk {458public:459 MicroMipsR6Thunk(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}460 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 467class PPC32PltCallStub final : public Thunk {468public:469 // For R_PPC_PLTREL24, Thunk::addend records the addend which will be used to470 // decide the offsets in the call stub.471 PPC32PltCallStub(Ctx &ctx, const InputSection &isec, const Relocation &rel,472 Symbol &dest)473 : Thunk(ctx, dest, rel.addend), file(isec.file) {}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 479private:480 // Records the call site of the call stub.481 const InputFile *file;482};483 484class PPC32LongThunk final : public Thunk {485public:486 PPC32LongThunk(Ctx &ctx, Symbol &dest, int64_t addend)487 : Thunk(ctx, dest, addend) {}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 in495// 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 into498// r12 for use by the target functions global entry point, and into the count499// register.500// 3) Transferring control to the target function through an indirect branch.501class PPC64PltCallStub final : public Thunk {502public:503 PPC64PltCallStub(Ctx &ctx, Symbol &dest) : Thunk(ctx, dest, 0) {}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 Stub512// When the caller requires a valid R2 TOC pointer but the callee does not513// require a TOC pointer and the callee cannot guarantee that it doesn't514// 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.517class PPC64R2SaveStub final : public Thunk {518public: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 thunks525 // we make sure that once a thunk has been set to long it cannot go back.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 }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 541private:542 // Transitioning from long to short can create layout oscillations in543 // certain corner cases which would prevent the layout from converging.544 // This is similar to the handling for ARMThunk.545 bool mayUseShortThunk = true;546 int64_t computeOffset() const {547 return destination.getVA(ctx) - (getThunkTargetSym()->getVA(ctx) + 4);548 }549};550 551// PPC64 R12 Setup Stub552// When a caller that does not maintain TOC calls a target which may possibly553// use TOC (either non-preemptible with localentry>1 or preemptible), we need to554// set r12 to satisfy the requirement of the global entry point.555class PPC64R12SetupStub final : public Thunk {556public:557 PPC64R12SetupStub(Ctx &ctx, Symbol &dest, bool gotPlt)558 : Thunk(ctx, dest, 0), gotPlt(gotPlt) {559 alignment = 16;560 }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 567private:568 bool gotPlt;569};570 571// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte572// alignment. This gives a possible 26 bits of 'reach'. If the call offset is573// larger than that we need to emit a long-branch thunk. The target address574// of the callee is stored in a table to be accessed TOC-relative. Since the575// call must be local (a non-local call will have a PltCallStub instead) the576// table stores the address of the callee's local entry point. For577// position-independent code a corresponding relative dynamic relocation is578// used.579class PPC64LongBranchThunk : public Thunk {580public: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 587protected:588 PPC64LongBranchThunk(Ctx &ctx, Symbol &dest, int64_t addend)589 : Thunk(ctx, dest, addend) {}590};591 592class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {593public: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 608class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {609public: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 namespace617 618Defined *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 626void 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.633static 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 638bool 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 649void 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 S657 ctx.target->relocateNoSym(buf, R_AARCH64_CALL26, s - p);658}659 660bool AArch64Thunk::needsSyntheticLandingPad() {661 // Short Thunks use a direct branch, no synthetic landing pad662 // required.663 return mayNeedLandingPad && !getMayUseShortThunk();664}665 666// AArch64 long range Thunks.667void AArch64ABSLongThunk::writeLong(uint8_t *buf) {668 const uint8_t data[] = {669 0x50, 0x00, 0x00, 0x58, // ldr x16, L0670 0x00, 0x02, 0x1f, 0xd6, // br x16671 0x00, 0x00, 0x00, 0x00, // L0: .xword S672 0x00, 0x00, 0x00, 0x00,673 };674 // If mayNeedLandingPad is true then destination is an675 // AArch64BTILandingPadThunk that defines landingPad.676 assert(!mayNeedLandingPad || landingPad != nullptr);677 uint64_t s = mayNeedLandingPad678 ? 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 684void 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 692void AArch64ABSLongThunk::addLongMapSyms() {693 addSymbol("$d", STT_NOTYPE, 8, *tsec);694 // The ldr in the long Thunk requires 8-byte alignment when695 // unaligned accesses are disabled.696 alignment = 8;697}698 699void AArch64ABSXOLongThunk::writeLong(uint8_t *buf) {700 const uint8_t data[] = {701 0x10, 0x00, 0x80, 0xd2, // movz x16, :abs_g0_nc:S, lsl #0702 0x10, 0x00, 0xa0, 0xf2, // movk x16, :abs_g1_nc:S, lsl #16703 0x10, 0x00, 0xc0, 0xf2, // movk x16, :abs_g2_nc:S, lsl #32704 0x10, 0x00, 0xe0, 0xf2, // movk x16, :abs_g3:S, lsl #48705 0x00, 0x02, 0x1f, 0xd6, // br x16706 };707 // If mayNeedLandingPad is true then destination is an708 // AArch64BTILandingPadThunk that defines landingPad.709 assert(!mayNeedLandingPad || landingPad != nullptr);710 uint64_t s = mayNeedLandingPad711 ? 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 720void 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 programs727// using the small code model, including pc-relative ones. At time of writing728// clang and gcc do not support the large code model for position independent729// code so it is safe to use this for position independent thunks without730// worrying about the destination being more than 4Gb away.731void 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 x16736 };737 // if mayNeedLandingPad is true then destination is an738 // AArch64BTILandingPadThunk that defines landingPad.739 assert(!mayNeedLandingPad || landingPad != nullptr);740 uint64_t s = mayNeedLandingPad741 ? 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 750void 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 756void 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 762void AArch64BTILandingPadThunk::writeTo(uint8_t *buf) {763 if (!getMayUseShortThunk()) {764 writeLong(buf);765 return;766 }767 write32(ctx, buf, 0xd503245f); // BTI c768 // Control falls through to target in following section.769}770 771bool AArch64BTILandingPadThunk::getMayUseShortThunk() {772 if (!mayUseShortThunk)773 return false;774 // If the target is the following instruction then we can fall775 // 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 to779 // work out the range from the thunk to the next section but the780 // address of the start of the next section depends on the size of781 // the thunks in the previous pass. s - p + offset == 0 represents782 // the first pass where the Thunk and following section are assigned783 // the same offset. s - p <= 4 is the last Thunk in the Thunk784 // Section.785 mayUseShortThunk = (s - p + offset == 0 || s - p <= 4);786 return mayUseShortThunk;787}788 789void 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 c793 write32(ctx, buf + 4, 0x14000000); // B S794 ctx.target->relocateNoSym(buf + 4, R_AARCH64_CALL26, s - p);795}796 797// ARM Target Thunks798static 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, and804// it has not previously returned false (see comment for mayUseShortThunk).805bool 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 822void 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 S832 ctx.target->relocateNoSym(buf, R_ARM_JUMP24, offset);833}834 835bool ARMThunk::isCompatibleWith(const InputSection &isec,836 const Relocation &rel) const {837 // v4T does not have BLX, so also deny R_ARM_THM_CALL838 if (!ctx.arg.armHasBlx && rel.type == R_ARM_THM_CALL)839 return false;840 841 // Thumb branch relocations can't use BLX842 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 Thumb847// && is within branch range848// && this function has not previously returned false849// (see comment for mayUseShortThunk)850// && the arch supports Thumb branch range extension.851bool 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 must856 // have the wide branch instruction B.w. This instruction is included when857 // Thumb 2 is present, or in v8-M (and above) baseline architectures.858 // armJ1J2BranchEncoding is available in all architectures with a profile and859 // 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 875void 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 S885 write16(ctx, buf + 2, 0xb000);886 ctx.target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);887}888 889bool ThumbThunk::isCompatibleWith(const InputSection &isec,890 const Relocation &rel) const {891 // v4T does not have BLX, so also deny R_ARM_CALL892 if (!ctx.arg.armHasBlx && rel.type == R_ARM_CALL)893 return false;894 895 // ARM branch relocations can't use BLX896 return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;897}898 899void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {900 write32(ctx, buf + 0, 0xe300c000); // movw ip,:lower16:S901 write32(ctx, buf + 4, 0xe340c000); // movt ip,:upper16:S902 write32(ctx, buf + 8, 0xe12fff1c); // bx ip903 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 908void 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 914void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {915 write16(ctx, buf + 0, 0xf240); // movw ip, :lower16:S916 write16(ctx, buf + 2, 0x0c00);917 write16(ctx, buf + 4, 0xf2c0); // movt ip, :upper16:S918 write16(ctx, buf + 6, 0x0c00);919 write16(ctx, buf + 8, 0x4760); // bx ip920 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 925void 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 931void 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, pc937 write32(ctx, buf + 12, 0xe12fff1c); // bx ip938 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 945void 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 951void 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, pc957 write16(ctx, buf + 10, 0x4760); // bx ip958 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 965void 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 971void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {972 // Most Thumb instructions cannot access the high registers r8 - r15. As the973 // only register we can corrupt is r12 we must instead spill a low register974 // to the stack to use as a scratch register. We push r1 even though we975 // don't need to get some space to use for the return address.976 write16(ctx, buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers977 write16(ctx, buf + 2, 0x4801); // ldr r0, [pc, #4] ; L1978 write16(ctx, buf + 4, 0x9001); // str r0, [sp, #4] ; SP + 4 = S979 write16(ctx, buf + 6, 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest980 write32(ctx, buf + 8, 0x00000000); // L1: .word S981 uint64_t s = getARMThunkDestVA(ctx, destination);982 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32, s);983}984 985void 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 993void ThumbV6MABSLongThunk::addLongMapSyms() {994 addSymbol("$d", STT_NOTYPE, 8, *tsec);995}996 997void ThumbV6MABSXOLongThunk::writeLong(uint8_t *buf) {998 // Most Thumb instructions cannot access the high registers r8 - r15. As the999 // only register we can corrupt is r12 we must instead spill a low register1000 // to the stack to use as a scratch register. We push r1 even though we1001 // don't need to get some space to use for the return address.1002 write16(ctx, buf + 0, 0xb403); // push {r0, r1} ; Obtain scratch registers1003 write16(ctx, buf + 2, 0x2000); // movs r0, :upper8_15:S1004 write16(ctx, buf + 4, 0x0200); // lsls r0, r0, #81005 write16(ctx, buf + 6, 0x3000); // adds r0, :upper0_7:S1006 write16(ctx, buf + 8, 0x0200); // lsls r0, r0, #81007 write16(ctx, buf + 10, 0x3000); // adds r0, :lower8_15:S1008 write16(ctx, buf + 12, 0x0200); // lsls r0, r0, #81009 write16(ctx, buf + 14, 0x3000); // adds r0, :lower0_7:S1010 write16(ctx, buf + 16, 0x9001); // str r0, [sp, #4] ; SP + 4 = S1011 write16(ctx, buf + 18,1012 0xbd01); // pop {r0, pc} ; restore r0 and branch to dest1013 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 1020void 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 1026void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {1027 // Most Thumb instructions cannot access the high registers r8 - r15. As the1028 // only register we can corrupt is ip (r12) we must instead spill a low1029 // register to the stack to use as a scratch register.1030 write16(ctx, buf + 0,1031 0xb401); // P: push {r0} ; Obtain scratch register1032 write16(ctx, buf + 2, 0x4802); // ldr r0, [pc, #8] ; L21033 write16(ctx, buf + 4, 0x4684); // mov ip, r0 ; high to low register1034 write16(ctx, buf + 6,1035 0xbc01); // pop {r0} ; restore scratch register1036 write16(ctx, buf + 8, 0x44e7); // L1: add pc, ip ; transfer control1037 write16(ctx, buf + 10,1038 0x46c0); // nop ; pad to 4-byte boundary1039 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 1045void 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 1053void ThumbV6MPILongThunk::addLongMapSyms() {1054 addSymbol("$d", STT_NOTYPE, 12, *tsec);1055}1056 1057void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {1058 write32(ctx, buf + 0, 0xe51ff004); // ldr pc, [pc,#-4] ; L11059 write32(ctx, buf + 4, 0x00000000); // L1: .word S1060 ctx.target->relocateNoSym(buf + 4, R_ARM_ABS32,1061 getARMThunkDestVA(ctx, destination));1062}1063 1064void 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 1072void ARMV5LongLdrPcThunk::addLongMapSyms() {1073 addSymbol("$d", STT_NOTYPE, 4, *tsec);1074}1075 1076void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {1077 write32(ctx, buf + 0, 0xe59fc000); // ldr r12, [pc] ; L11078 write32(ctx, buf + 4, 0xe12fff1c); // bx r121079 write32(ctx, buf + 8, 0x00000000); // L1: .word S1080 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32,1081 getARMThunkDestVA(ctx, destination));1082}1083 1084void 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 1092void ARMV4ABSLongBXThunk::addLongMapSyms() {1093 addSymbol("$d", STT_NOTYPE, 8, *tsec);1094}1095 1096void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {1097 write16(ctx, buf + 0, 0x4778); // bx pc1098 write16(ctx, buf + 2,1099 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc1100 write32(ctx, buf + 4, 0xe51ff004); // ldr pc, [pc, #-4] ; L11101 write32(ctx, buf + 8, 0x00000000); // L1: .word S1102 ctx.target->relocateNoSym(buf + 8, R_ARM_ABS32,1103 getARMThunkDestVA(ctx, destination));1104}1105 1106void 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 1114void ThumbV4ABSLongBXThunk::addLongMapSyms() {1115 addSymbol("$a", STT_NOTYPE, 4, *tsec);1116 addSymbol("$d", STT_NOTYPE, 8, *tsec);1117}1118 1119void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {1120 write16(ctx, buf + 0, 0x4778); // bx pc1121 write16(ctx, buf + 2,1122 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc1123 write32(ctx, buf + 4, 0xe59fc000); // ldr r12, [pc] ; L11124 write32(ctx, buf + 8, 0xe12fff1c); // bx r121125 write32(ctx, buf + 12, 0x00000000); // L1: .word S1126 ctx.target->relocateNoSym(buf + 12, R_ARM_ABS32,1127 getARMThunkDestVA(ctx, destination));1128}1129 1130void 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 1138void ThumbV4ABSLongThunk::addLongMapSyms() {1139 addSymbol("$a", STT_NOTYPE, 4, *tsec);1140 addSymbol("$d", STT_NOTYPE, 12, *tsec);1141}1142 1143void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {1144 write32(ctx, buf + 0, 0xe59fc004); // P: ldr ip, [pc,#4] ; L21145 write32(ctx, buf + 4, 0xe08fc00c); // L1: add ip, pc, ip1146 write32(ctx, buf + 8, 0xe12fff1c); // bx ip1147 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 1153void 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 1161void ARMV4PILongBXThunk::addLongMapSyms() {1162 addSymbol("$d", STT_NOTYPE, 12, *tsec);1163}1164 1165void ARMV4PILongThunk::writeLong(uint8_t *buf) {1166 write32(ctx, buf + 0, 0xe59fc000); // P: ldr ip, [pc] ; L21167 write32(ctx, buf + 4, 0xe08ff00c); // L1: add pc, pc, r121168 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 1174void 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 1182void ARMV4PILongThunk::addLongMapSyms() {1183 addSymbol("$d", STT_NOTYPE, 8, *tsec);1184}1185 1186void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {1187 write16(ctx, buf + 0, 0x4778); // P: bx pc1188 write16(ctx, buf + 2,1189 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc1190 write32(ctx, buf + 4, 0xe59fc000); // ldr r12, [pc] ; L21191 write32(ctx, buf + 8, 0xe08cf00f); // L1: add pc, r12, pc1192 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 1198void 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 1206void ThumbV4PILongBXThunk::addLongMapSyms() {1207 addSymbol("$a", STT_NOTYPE, 4, *tsec);1208 addSymbol("$d", STT_NOTYPE, 12, *tsec);1209}1210 1211void ThumbV4PILongThunk::writeLong(uint8_t *buf) {1212 write16(ctx, buf + 0, 0x4778); // P: bx pc1213 write16(ctx, buf + 2,1214 0xe7fd); // b #-6 ; Arm recommended sequence to follow bx pc1215 write32(ctx, buf + 4, 0xe59fc004); // ldr ip, [pc,#4] ; L21216 write32(ctx, buf + 8, 0xe08fc00c); // L1: add ip, pc, ip1217 write32(ctx, buf + 12, 0xe12fff1c); // bx ip1218 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 1224void 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 1232void 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.1238void AVRThunk::writeTo(uint8_t *buf) {1239 write32(ctx, buf, 0x940c); // jmp func1240 ctx.target->relocateNoSym(buf, R_AVR_CALL, destination.getVA(ctx));1241}1242 1243void 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.1249void 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 func1253 write32(ctx, buf + 8, 0x27390000); // addiu $25, $25, %lo(func)1254 write32(ctx, buf + 12, 0x00000000); // nop1255 ctx.target->relocateNoSym(buf, R_MIPS_HI16, s);1256 ctx.target->relocateNoSym(buf + 8, R_MIPS_LO16, s);1257}1258 1259void MipsThunk::addSymbols(ThunkSection &isec) {1260 addSymbol(ctx.saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,1261 isec);1262}1263 1264InputSection *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 code1270// to call PIC function from the non-PIC one.1271void 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 func1275 write16(ctx, buf + 8, 0x3339); // addiu $25, $25, %lo(func)1276 write16(ctx, buf + 12, 0x0c00); // nop1277 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 1282void 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 1289InputSection *MicroMipsThunk::getTargetInputSection() const {1290 auto &dr = cast<Defined>(destination);1291 return dyn_cast<InputSection>(dr.section);1292}1293 1294// Write microMIPS R6 LA25 thunk code1295// to call PIC function from the non-PIC one.1296void 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 func1302 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 1307void 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 1314InputSection *MicroMipsR6Thunk::getTargetInputSection() const {1315 auto &dr = cast<Defined>(destination);1316 return dyn_cast<InputSection>(dr.section);1317}1318 1319void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t gotPltVA,1320 const InputFile *file, int64_t addend) {1321 if (!ctx.arg.isPic) {1322 write32(ctx, buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha1323 write32(ctx, buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)1324 write32(ctx, buf + 8, 0x7d6903a6); // mtctr r111325 write32(ctx, buf + 12, 0x4e800420); // bctr1326 return;1327 }1328 uint32_t offset;1329 if (addend >= 0x8000) {1330 // The stub loads an address relative to r30 (.got2+Addend). Addend is1331 // almost always 0x8000. The address of .got2 is different in another object1332 // file, so a stub cannot be shared.1333 offset = gotPltVA -1334 (ctx.in.ppc32Got2->getParent()->getVA() +1335 (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);1336 } else {1337 // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is1338 // currently the address of .got).1339 offset = gotPltVA - ctx.in.got->getVA();1340 }1341 uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;1342 if (ha == 0) {1343 write32(ctx, buf + 0, 0x817e0000 | l); // lwz r11,l(r30)1344 write32(ctx, buf + 4, 0x7d6903a6); // mtctr r111345 write32(ctx, buf + 8, 0x4e800420); // bctr1346 write32(ctx, buf + 12, 0x60000000); // nop1347 } else {1348 write32(ctx, buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha1349 write32(ctx, buf + 4, 0x816b0000 | l); // lwz r11,l(r11)1350 write32(ctx, buf + 8, 0x7d6903a6); // mtctr r111351 write32(ctx, buf + 12, 0x4e800420); // bctr1352 }1353}1354 1355void PPC32PltCallStub::writeTo(uint8_t *buf) {1356 writePPC32PltCallStub(ctx, buf, destination.getGotPltVA(ctx), file, addend);1357}1358 1359void PPC32PltCallStub::addSymbols(ThunkSection &isec) {1360 std::string buf;1361 raw_string_ostream os(buf);1362 os << format_hex_no_prefix(addend, 8);1363 if (!ctx.arg.isPic)1364 os << ".plt_call32.";1365 else if (addend >= 0x8000)1366 os << ".got2.plt_pic32.";1367 else1368 os << ".plt_pic32.";1369 os << destination.getName();1370 addSymbol(ctx.saver.save(buf), STT_FUNC, 0, isec);1371}1372 1373bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,1374 const Relocation &rel) const {1375 return !ctx.arg.isPic || (isec.file == file && rel.addend == addend);1376}1377 1378void PPC32LongThunk::addSymbols(ThunkSection &isec) {1379 addSymbol(ctx.saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,1380 isec);1381}1382 1383void PPC32LongThunk::writeTo(uint8_t *buf) {1384 auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };1385 auto lo = [](uint32_t v) -> uint16_t { return v; };1386 uint32_t d = destination.getVA(ctx, addend);1387 if (ctx.arg.isPic) {1388 uint32_t off = d - (getThunkTargetSym()->getVA(ctx) + 8);1389 write32(ctx, buf + 0, 0x7c0802a6); // mflr r12,01390 write32(ctx, buf + 4, 0x429f0005); // bcl r20,r31,.+41391 write32(ctx, buf + 8, 0x7d8802a6); // mtctr r121392 write32(ctx, buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha1393 write32(ctx, buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l1394 write32(ctx, buf + 20, 0x7c0803a6); // mtlr r01395 buf += 24;1396 } else {1397 write32(ctx, buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha1398 write32(ctx, buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l1399 buf += 8;1400 }1401 write32(ctx, buf + 0, 0x7d8903a6); // mtctr r121402 write32(ctx, buf + 4, 0x4e800420); // bctr1403}1404 1405void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, int64_t offset) {1406 uint16_t offHa = (offset + 0x8000) >> 16;1407 uint16_t offLo = offset & 0xffff;1408 1409 write32(ctx, buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa1410 write32(ctx, buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12)1411 write32(ctx, buf + 8, 0x7d8903a6); // mtctr r121412 write32(ctx, buf + 12, 0x4e800420); // bctr1413}1414 1415void PPC64PltCallStub::writeTo(uint8_t *buf) {1416 int64_t offset = destination.getGotPltVA(ctx) - getPPC64TocBase(ctx);1417 // Save the TOC pointer to the save-slot reserved in the call frame.1418 write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1)1419 writePPC64LoadAndBranch(ctx, buf + 4, offset);1420}1421 1422void PPC64PltCallStub::addSymbols(ThunkSection &isec) {1423 Defined *s = addSymbol(ctx.saver.save("__plt_" + destination.getName()),1424 STT_FUNC, 0, isec);1425 s->setNeedsTocRestore(true);1426 s->file = destination.file;1427}1428 1429bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,1430 const Relocation &rel) const {1431 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;1432}1433 1434void PPC64R2SaveStub::writeTo(uint8_t *buf) {1435 const int64_t offset = computeOffset();1436 write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1)1437 // The branch offset needs to fit in 26 bits.1438 if (getMayUseShortThunk()) {1439 write32(ctx, buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>1440 } else if (isInt<34>(offset)) {1441 int nextInstOffset;1442 uint64_t tocOffset = destination.getVA(ctx) - getPPC64TocBase(ctx);1443 if (tocOffset >> 16 > 0) {1444 const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);1445 const uint64_t addis =1446 ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);1447 write32(ctx, buf + 4, addis); // addis r12, r2 , top of offset1448 write32(ctx, buf + 8, addi); // addi r12, r12, bottom of offset1449 nextInstOffset = 12;1450 } else {1451 const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);1452 write32(ctx, buf + 4, addi); // addi r12, r2, offset1453 nextInstOffset = 8;1454 }1455 write32(ctx, buf + nextInstOffset, MTCTR_R12); // mtctr r121456 write32(ctx, buf + nextInstOffset + 4, BCTR); // bctr1457 } else {1458 ctx.in.ppc64LongBranchTarget->addEntry(&destination, addend);1459 const int64_t offsetFromTOC =1460 ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -1461 getPPC64TocBase(ctx);1462 writePPC64LoadAndBranch(ctx, buf + 4, offsetFromTOC);1463 }1464}1465 1466void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {1467 Defined *s = addSymbol(ctx.saver.save("__toc_save_" + destination.getName()),1468 STT_FUNC, 0, isec);1469 s->setNeedsTocRestore(true);1470}1471 1472bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,1473 const Relocation &rel) const {1474 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;1475}1476 1477void PPC64R12SetupStub::writeTo(uint8_t *buf) {1478 int64_t offset =1479 (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA(ctx)) -1480 getThunkTargetSym()->getVA(ctx);1481 if (!isInt<34>(offset))1482 reportRangeError(ctx, buf, offset, 34, destination,1483 "R12 setup stub offset");1484 1485 int nextInstOffset;1486 if (ctx.arg.power10Stubs) {1487 const uint64_t imm = (((offset >> 16) & 0x3ffff) << 32) | (offset & 0xffff);1488 // pld 12, func@plt@pcrel or paddi r12, 0, func@pcrel1489 writePrefixedInst(ctx, buf,1490 (gotPlt ? PLD_R12_NO_DISP : PADDI_R12_NO_DISP) | imm);1491 nextInstOffset = 8;1492 } else {1493 uint32_t off = offset - 8;1494 write32(ctx, buf + 0, 0x7d8802a6); // mflr 121495 write32(ctx, buf + 4, 0x429f0005); // bcl 20,31,.+41496 write32(ctx, buf + 8, 0x7d6802a6); // mflr 111497 write32(ctx, buf + 12, 0x7d8803a6); // mtlr 121498 write32(ctx, buf + 16,1499 0x3d8b0000 | ((off + 0x8000) >> 16)); // addis 12,11,off@ha1500 if (gotPlt)1501 write32(ctx, buf + 20, 0xe98c0000 | (off & 0xffff)); // ld 12, off@l(12)1502 else1503 write32(ctx, buf + 20, 0x398c0000 | (off & 0xffff)); // addi 12,12,off@l1504 nextInstOffset = 24;1505 }1506 write32(ctx, buf + nextInstOffset, MTCTR_R12); // mtctr r121507 write32(ctx, buf + nextInstOffset + 4, BCTR); // bctr1508}1509 1510void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {1511 addSymbol(ctx.saver.save((gotPlt ? "__plt_pcrel_" : "__gep_setup_") +1512 destination.getName()),1513 STT_FUNC, 0, isec);1514}1515 1516bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,1517 const Relocation &rel) const {1518 return rel.type == R_PPC64_REL24_NOTOC;1519}1520 1521void PPC64LongBranchThunk::writeTo(uint8_t *buf) {1522 int64_t offset =1523 ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -1524 getPPC64TocBase(ctx);1525 writePPC64LoadAndBranch(ctx, buf, offset);1526}1527 1528void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {1529 addSymbol(ctx.saver.save("__long_branch_" + destination.getName()), STT_FUNC,1530 0, isec);1531}1532 1533bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,1534 const Relocation &rel) const {1535 return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;1536}1537 1538// Hexagon Target Thunks1539static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) {1540 uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a);1541 return SignExtend64<32>(v);1542}1543 1544void HexagonThunk::writeTo(uint8_t *buf) {1545 uint64_t s = getHexagonThunkDestVA(ctx, destination, addend);1546 uint64_t p = getThunkTargetSym()->getVA(ctx);1547 1548 if (ctx.arg.isPic) {1549 write32(ctx, buf + 0, 0x00004000); // { immext(#0)1550 ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p);1551 write32(ctx, buf + 4, 0x6a49c00e); // r14 = add(pc,##0) }1552 ctx.target->relocateNoSym(buf + 4, R_HEX_6_PCREL_X, s - p);1553 1554 write32(ctx, buf + 8, 0x528ec000); // { jumpr r14 }1555 } else {1556 write32(ctx, buf + 0, 0x00004000); // { immext1557 ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p);1558 write32(ctx, buf + 4, 0x5800c000); // jump <> }1559 ctx.target->relocateNoSym(buf + 4, R_HEX_B22_PCREL_X, s - p);1560 }1561}1562void HexagonThunk::addSymbols(ThunkSection &isec) {1563 Symbol *enclosing = isec.getEnclosingSymbol(relOffset);1564 StringRef src = enclosing ? enclosing->getName() : isec.name;1565 1566 addSymbol(1567 saver().save("__hexagon_thunk_" + destination.getName() + "_from_" + src),1568 STT_FUNC, 0, isec);1569}1570 1571Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)1572 : ctx(ctx), destination(d), addend(a), offset(0) {1573 destination.thunkAccessed = true;1574}1575 1576Thunk::~Thunk() = default;1577 1578static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, const InputSection &sec,1579 RelType type, Symbol &s,1580 int64_t a) {1581 assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},1582 type));1583 bool mayNeedLandingPad =1584 (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&1585 !isAArch64BTILandingPad(ctx, s, a);1586 if (ctx.arg.picThunk)1587 return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);1588 if (sec.getParent()->flags & SHF_AARCH64_PURECODE)1589 return std::make_unique<AArch64ABSXOLongThunk>(ctx, s, a,1590 mayNeedLandingPad);1591 return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);1592}1593 1594// Creates a thunk for long branches or Thumb-ARM interworking.1595// Arm Architectures v4t does not support Thumb2 technology, and does not1596// support BLX or LDR Arm/Thumb state switching. This means that1597// - MOVT and MOVW instructions cannot be used.1598// - We can't rewrite BL in place to BLX. We will need thunks.1599//1600// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for1601// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).1602static std::unique_ptr<Thunk> addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s,1603 int64_t a) {1604 bool thumb_target = s.getVA(ctx, a) & 1;1605 1606 switch (reloc) {1607 case R_ARM_PC24:1608 case R_ARM_PLT32:1609 case R_ARM_JUMP24:1610 case R_ARM_CALL:1611 if (ctx.arg.picThunk) {1612 if (thumb_target)1613 return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);1614 return std::make_unique<ARMV4PILongThunk>(ctx, s, a);1615 }1616 if (thumb_target)1617 return std::make_unique<ARMV4ABSLongBXThunk>(ctx, s, a);1618 return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);1619 case R_ARM_THM_CALL:1620 if (ctx.arg.picThunk) {1621 if (thumb_target)1622 return std::make_unique<ThumbV4PILongThunk>(ctx, s, a);1623 return std::make_unique<ThumbV4PILongBXThunk>(ctx, s, a);1624 }1625 if (thumb_target)1626 return std::make_unique<ThumbV4ABSLongThunk>(ctx, s, a);1627 return std::make_unique<ThumbV4ABSLongBXThunk>(ctx, s, a);1628 }1629 Fatal(ctx) << "relocation " << reloc << " to " << &s1630 << " not supported for Armv4 or Armv4T target";1631 llvm_unreachable("");1632}1633 1634// Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.1635// Arm Architectures v5 and v6 do not support Thumb2 technology. This means that1636// - MOVT and MOVW instructions cannot be used1637// - Only Thumb relocation that can generate a Thunk is a BL, this can always1638// be transformed into a BLX1639static std::unique_ptr<Thunk> addThunkArmv5v6(Ctx &ctx, RelType reloc,1640 Symbol &s, int64_t a) {1641 switch (reloc) {1642 case R_ARM_PC24:1643 case R_ARM_PLT32:1644 case R_ARM_JUMP24:1645 case R_ARM_CALL:1646 case R_ARM_THM_CALL:1647 if (ctx.arg.picThunk)1648 return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);1649 return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);1650 }1651 Fatal(ctx) << "relocation " << reloc << " to " << &s1652 << " not supported for Armv5 or Armv6 targets";1653 llvm_unreachable("");1654}1655 1656// Create a thunk for Thumb long branch on V6-M.1657// Arm Architecture v6-M only supports Thumb instructions. This means1658// - MOVT and MOVW instructions cannot be used.1659// - Only a limited number of instructions can access registers r8 and above1660// - No interworking support is needed (all Thumb).1661static std::unique_ptr<Thunk> addThunkV6M(Ctx &ctx, const InputSection &isec,1662 RelType reloc, Symbol &s, int64_t a) {1663 const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE;1664 switch (reloc) {1665 case R_ARM_THM_JUMP19:1666 case R_ARM_THM_JUMP24:1667 case R_ARM_THM_CALL:1668 if (ctx.arg.isPic) {1669 if (!isPureCode)1670 return std::make_unique<ThumbV6MPILongThunk>(ctx, s, a);1671 1672 Fatal(ctx)1673 << "relocation " << reloc << " to " << &s1674 << " not supported for Armv6-M targets for position independent"1675 " and execute only code";1676 llvm_unreachable("");1677 }1678 if (isPureCode)1679 return std::make_unique<ThumbV6MABSXOLongThunk>(ctx, s, a);1680 return std::make_unique<ThumbV6MABSLongThunk>(ctx, s, a);1681 }1682 Fatal(ctx) << "relocation " << reloc << " to " << &s1683 << " not supported for Armv6-M targets";1684 llvm_unreachable("");1685}1686 1687// Creates a thunk for Thumb-ARM interworking or branch range extension.1688static std::unique_ptr<Thunk> addThunkArm(Ctx &ctx, const InputSection &isec,1689 RelType reloc, Symbol &s, int64_t a) {1690 // Decide which Thunk is needed based on:1691 // Available instruction set1692 // - An Arm Thunk can only be used if Arm state is available.1693 // - A Thumb Thunk can only be used if Thumb state is available.1694 // - Can only use a Thunk if it uses instructions that the Target supports.1695 // Relocation is branch or branch and link1696 // - Branch instructions cannot change state, can only select Thunk that1697 // starts in the same state as the caller.1698 // - Branch and link relocations can change state, can select Thunks from1699 // either Arm or Thumb.1700 // Position independent Thunks if we require position independent code.1701 // Execute Only Thunks if the output section is execute only code.1702 1703 // Handle architectures that have restrictions on the instructions that they1704 // can use in Thunks. The flags below are set by reading the BuildAttributes1705 // of the input objects. InputFiles.cpp contains the mapping from ARM1706 // architecture to flag.1707 if (!ctx.arg.armHasMovtMovw) {1708 if (ctx.arg.armJ1J2BranchEncoding)1709 return addThunkV6M(ctx, isec, reloc, s, a);1710 if (ctx.arg.armHasBlx)1711 return addThunkArmv5v6(ctx, reloc, s, a);1712 return addThunkArmv4(ctx, reloc, s, a);1713 }1714 1715 switch (reloc) {1716 case R_ARM_PC24:1717 case R_ARM_PLT32:1718 case R_ARM_JUMP24:1719 case R_ARM_CALL:1720 if (ctx.arg.picThunk)1721 return std::make_unique<ARMV7PILongThunk>(ctx, s, a);1722 return std::make_unique<ARMV7ABSLongThunk>(ctx, s, a);1723 case R_ARM_THM_JUMP19:1724 case R_ARM_THM_JUMP24:1725 case R_ARM_THM_CALL:1726 if (ctx.arg.picThunk)1727 return std::make_unique<ThumbV7PILongThunk>(ctx, s, a);1728 return std::make_unique<ThumbV7ABSLongThunk>(ctx, s, a);1729 }1730 llvm_unreachable("");1731}1732 1733static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,1734 int64_t a) {1735 switch (type) {1736 case R_AVR_LO8_LDI_GS:1737 case R_AVR_HI8_LDI_GS:1738 return std::make_unique<AVRThunk>(ctx, s, a);1739 default:1740 llvm_unreachable("");1741 }1742}1743 1744static std::unique_ptr<Thunk> addThunkHexagon(Ctx &ctx,1745 const InputSection &isec,1746 Relocation &rel, Symbol &s) {1747 switch (rel.type) {1748 case R_HEX_B9_PCREL:1749 case R_HEX_B13_PCREL:1750 case R_HEX_B15_PCREL:1751 case R_HEX_B22_PCREL:1752 case R_HEX_PLT_B22_PCREL:1753 case R_HEX_GD_PLT_B22_PCREL:1754 return std::make_unique<HexagonThunk>(ctx, isec, rel, s);1755 default:1756 Fatal(ctx) << "unrecognized relocation " << rel.type << " to " << &s1757 << " for hexagon target";1758 llvm_unreachable("");1759 }1760}1761 1762static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {1763 if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))1764 return std::make_unique<MicroMipsR6Thunk>(ctx, s);1765 if (s.stOther & STO_MIPS_MICROMIPS)1766 return std::make_unique<MicroMipsThunk>(ctx, s);1767 return std::make_unique<MipsThunk>(ctx, s);1768}1769 1770static std::unique_ptr<Thunk> addThunkPPC32(Ctx &ctx, const InputSection &isec,1771 const Relocation &rel, Symbol &s) {1772 assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||1773 rel.type == R_PPC_PLTREL24) &&1774 "unexpected relocation type for thunk");1775 if (s.isInPlt(ctx))1776 return std::make_unique<PPC32PltCallStub>(ctx, isec, rel, s);1777 return std::make_unique<PPC32LongThunk>(ctx, s, rel.addend);1778}1779 1780static std::unique_ptr<Thunk> addThunkPPC64(Ctx &ctx, RelType type, Symbol &s,1781 int64_t a) {1782 assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||1783 type == R_PPC64_REL24_NOTOC) &&1784 "unexpected relocation type for thunk");1785 1786 // If we are emitting stubs for NOTOC relocations, we need to tell1787 // the PLT resolver that there can be multiple TOCs.1788 if (type == R_PPC64_REL24_NOTOC)1789 ctx.target->ppc64DynamicSectionOpt = 0x2;1790 1791 if (s.isInPlt(ctx)) {1792 if (type == R_PPC64_REL24_NOTOC)1793 return std::make_unique<PPC64R12SetupStub>(ctx, s,1794 /*gotPlt=*/true);1795 return std::make_unique<PPC64PltCallStub>(ctx, s);1796 }1797 1798 // This check looks at the st_other bits of the callee. If the value is 11799 // then the callee clobbers the TOC and we need an R2 save stub when RelType1800 // is R_PPC64_REL14 or R_PPC64_REL24.1801 if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)1802 return std::make_unique<PPC64R2SaveStub>(ctx, s, a);1803 1804 if (type == R_PPC64_REL24_NOTOC)1805 return std::make_unique<PPC64R12SetupStub>(ctx, s, /*gotPlt=*/false);1806 1807 if (ctx.arg.picThunk)1808 return std::make_unique<PPC64PILongBranchThunk>(ctx, s, a);1809 1810 return std::make_unique<PPC64PDLongBranchThunk>(ctx, s, a);1811}1812 1813std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,1814 Relocation &rel) {1815 Symbol &s = *rel.sym;1816 int64_t a = rel.addend;1817 1818 switch (ctx.arg.emachine) {1819 case EM_AARCH64:1820 return addThunkAArch64(ctx, isec, rel.type, s, a);1821 case EM_ARM:1822 return addThunkArm(ctx, isec, rel.type, s, a);1823 case EM_AVR:1824 return addThunkAVR(ctx, rel.type, s, a);1825 case EM_MIPS:1826 return addThunkMips(ctx, rel.type, s);1827 case EM_PPC:1828 return addThunkPPC32(ctx, isec, rel, s);1829 case EM_PPC64:1830 return addThunkPPC64(ctx, rel.type, s, a);1831 case EM_HEXAGON:1832 return addThunkHexagon(ctx, isec, rel, s);1833 default:1834 llvm_unreachable(1835 "add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC");1836 }1837}1838 1839std::unique_ptr<Thunk> elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) {1840 switch (ctx.arg.emachine) {1841 case EM_AARCH64:1842 return std::make_unique<AArch64BTILandingPadThunk>(ctx, s, a);1843 default:1844 llvm_unreachable("add landing pad only supported for AArch64");1845 }1846}1847