brintos

brintos / llvm-project-archived public Read only

0
0
Text · 67.0 KiB · 65d0f09 Raw
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 &section) {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