| 1 | //===- Thunks.h --------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLD_ELF_THUNKS_H |
| 10 | #define LLD_ELF_THUNKS_H |
| 11 | |
| 12 | #include "llvm/ADT/SmallVector.h" |
| 13 | #include "Relocations.h" |
| 14 | |
| 15 | namespace lld::elf { |
| 16 | struct Ctx; |
| 17 | class Defined; |
| 18 | class InputFile; |
| 19 | class Symbol; |
| 20 | class ThunkSection; |
| 21 | // Class to describe an instance of a Thunk. |
| 22 | // A Thunk is a code-sequence inserted by the linker in between a caller and |
| 23 | // the callee. The relocation to the callee is redirected to the Thunk, which |
| 24 | // after executing transfers control to the callee. Typical uses of Thunks |
| 25 | // include transferring control from non-pi to pi and changing state on |
| 26 | // targets like ARM. |
| 27 | // |
| 28 | // Thunks can be created for Defined, Shared and Undefined Symbols. |
| 29 | // Thunks are assigned to synthetic ThunkSections |
| 30 | class Thunk { |
| 31 | public: |
| 32 | Thunk(Ctx &, Symbol &destination, int64_t addend); |
| 33 | virtual ~Thunk(); |
| 34 | |
| 35 | virtual uint32_t size() = 0; |
| 36 | virtual void writeTo(uint8_t *buf) = 0; |
| 37 | |
| 38 | // All Thunks must define at least one symbol, known as the thunk target |
| 39 | // symbol, so that we can redirect relocations to it. The thunk may define |
| 40 | // additional symbols, but these are never targets for relocations. |
| 41 | virtual void addSymbols(ThunkSection &isec) = 0; |
| 42 | |
| 43 | void setOffset(uint64_t offset); |
| 44 | Defined *addSymbol(StringRef name, uint8_t type, uint64_t value, |
| 45 | InputSectionBase §ion); |
| 46 | |
| 47 | // Some Thunks must be placed immediately before their Target as they elide |
| 48 | // a branch and fall through to the first Symbol in the Target. |
| 49 | virtual InputSection *getTargetInputSection() const { return nullptr; } |
| 50 | |
| 51 | // To reuse a Thunk the InputSection and the relocation must be compatible |
| 52 | // with it. |
| 53 | virtual bool isCompatibleWith(const InputSection &, |
| 54 | const Relocation &) const { |
| 55 | return true; |
| 56 | } |
| 57 | |
| 58 | // Thunks that indirectly branch to targets may need a synthetic landing |
| 59 | // pad generated close to the target. For example AArch64 when BTI is |
| 60 | // enabled. |
| 61 | virtual bool needsSyntheticLandingPad() { return false; } |
| 62 | |
| 63 | Defined *getThunkTargetSym() const { return syms[0]; } |
| 64 | |
| 65 | Ctx &ctx; |
| 66 | Symbol &destination; |
| 67 | int64_t addend; |
| 68 | // Alternative target when indirect branch to destination can't be used. |
| 69 | Symbol *landingPad = nullptr; |
| 70 | llvm::SmallVector<Defined *, 3> syms; |
| 71 | uint64_t offset = 0; |
| 72 | // The alignment requirement for this Thunk, defaults to the size of the |
| 73 | // typical code section alignment. |
| 74 | uint32_t alignment = 4; |
| 75 | }; |
| 76 | |
| 77 | // For a Relocation to symbol S create a Thunk to be added to a synthetic |
| 78 | // ThunkSection. |
| 79 | std::unique_ptr<Thunk> addThunk(Ctx &, const InputSection &isec, |
| 80 | Relocation &rel); |
| 81 | |
| 82 | // Create a landing pad Thunk for use when indirect branches from Thunks |
| 83 | // are restricted. |
| 84 | std::unique_ptr<Thunk> addLandingPadThunk(Ctx &, Symbol &s, int64_t a); |
| 85 | |
| 86 | void writePPC32PltCallStub(Ctx &, uint8_t *buf, uint64_t gotPltVA, |
| 87 | const InputFile *file, int64_t addend); |
| 88 | void writePPC64LoadAndBranch(Ctx &, uint8_t *buf, int64_t offset); |
| 89 | |
| 90 | } // namespace lld::elf |
| 91 | |
| 92 | #endif |
| 93 | |