Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 1 | //===- Target.h -------------------------------------------------*- C++ -*-===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 | [diff] [blame] | 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 |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLD_ELF_TARGET_H |
| 10 | #define LLD_ELF_TARGET_H |
| 11 | |
Fangrui Song | 27bb799 | 2022-02-08 05:53:34 | [diff] [blame] | 12 | #include "Config.h" |
Rafael Espindola | 22ef956 | 2016-04-13 01:40:19 | [diff] [blame] | 13 | #include "InputSection.h" |
Bob Haarman | b8a59c8 | 2017-10-25 22:28:38 | [diff] [blame] | 14 | #include "lld/Common/ErrorHandler.h" |
Elliot Goodrich | b0abd48 | 2023-06-17 12:18:23 | [diff] [blame] | 15 | #include "llvm/ADT/StringExtras.h" |
Igor Kudrin | 15cd9ff | 2015-11-06 07:43:03 | [diff] [blame] | 16 | #include "llvm/Object/ELF.h" |
Mitch Phillips | ca35a19 | 2023-07-31 15:07:26 | [diff] [blame] | 17 | #include "llvm/Object/ELFTypes.h" |
Fangrui Song | 961439c | 2022-10-02 20:23:52 | [diff] [blame] | 18 | #include "llvm/Support/Compiler.h" |
Fangrui Song | f66d0ce | 2018-08-06 23:50:26 | [diff] [blame] | 19 | #include "llvm/Support/MathExtras.h" |
Simon Atanasyan | b048605 | 2018-11-14 21:05:20 | [diff] [blame] | 20 | #include <array> |
Simon Atanasyan | 49829a1 | 2015-09-29 05:34:03 | [diff] [blame] | 21 | |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 22 | namespace lld { |
Rafael Espindola | e0df00b | 2016-02-28 00:25:54 | [diff] [blame] | 23 | namespace elf { |
Rui Ueyama | 7957b08 | 2017-11-07 00:04:22 | [diff] [blame] | 24 | class Defined; |
Simon Atanasyan | 13f6da1 | 2016-03-31 21:26:23 | [diff] [blame] | 25 | class InputFile; |
Rui Ueyama | f52496e | 2017-11-03 21:21:47 | [diff] [blame] | 26 | class Symbol; |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 27 | |
Fangrui Song | 58a971f | 2024-11-16 19:58:10 | [diff] [blame] | 28 | std::string toStr(Ctx &, RelType type); |
| 29 | |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 30 | class TargetInfo { |
| 31 | public: |
Fangrui Song | c3e4998 | 2024-09-29 04:48:26 | [diff] [blame] | 32 | TargetInfo(Ctx &ctx) : ctx(ctx) {} |
Konstantin Zhuravlyov | e7f1734 | 2017-10-24 17:01:40 | [diff] [blame] | 33 | virtual uint32_t calcEFlags() const { return 0; } |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 34 | virtual RelExpr getRelExpr(RelType type, const Symbol &s, |
| 35 | const uint8_t *loc) const = 0; |
| 36 | virtual RelType getDynRel(RelType type) const { return 0; } |
| 37 | virtual void writeGotPltHeader(uint8_t *buf) const {} |
| 38 | virtual void writeGotHeader(uint8_t *buf) const {} |
| 39 | virtual void writeGotPlt(uint8_t *buf, const Symbol &s) const {}; |
Fangrui Song | 2d077d6 | 2020-01-09 19:59:28 | [diff] [blame] | 40 | virtual void writeIgotPlt(uint8_t *buf, const Symbol &s) const {} |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 41 | virtual int64_t getImplicitAddend(const uint8_t *buf, RelType type) const; |
| 42 | virtual int getTlsGdRelaxSkip(RelType type) const { return 1; } |
Rui Ueyama | 69c30ed | 2016-01-29 03:00:30 | [diff] [blame] | 43 | |
| 44 | // If lazy binding is supported, the first entry of the PLT has code |
| 45 | // to call the dynamic linker to resolve PLT entries the first time |
| 46 | // they are called. This function writes that code. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 47 | virtual void writePltHeader(uint8_t *buf) const {} |
Rui Ueyama | 69c30ed | 2016-01-29 03:00:30 | [diff] [blame] | 48 | |
Fangrui Song | 37b2808 | 2019-12-17 21:43:04 | [diff] [blame] | 49 | virtual void writePlt(uint8_t *buf, const Symbol &sym, |
| 50 | uint64_t pltEntryAddr) const {} |
| 51 | virtual void writeIplt(uint8_t *buf, const Symbol &sym, |
| 52 | uint64_t pltEntryAddr) const { |
| 53 | // All but PPC32 and PPC64 use the same format for .plt and .iplt entries. |
| 54 | writePlt(buf, sym, pltEntryAddr); |
Fangrui Song | 891a865 | 2019-12-14 22:17:35 | [diff] [blame] | 55 | } |
Fangrui Song | 7cd429f | 2019-12-11 02:05:36 | [diff] [blame] | 56 | virtual void writeIBTPlt(uint8_t *buf, size_t numEntries) const {} |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 57 | virtual void addPltHeaderSymbols(InputSection &isec) const {} |
| 58 | virtual void addPltSymbols(InputSection &isec, uint64_t off) const {} |
Rui Ueyama | 67533a2 | 2017-10-11 22:49:24 | [diff] [blame] | 59 | |
Rafael Espindola | b8ff59a | 2016-04-28 14:34:39 | [diff] [blame] | 60 | // Returns true if a relocation only uses the low bits of a value such that |
Fangrui Song | 1f3e2b2 | 2018-04-27 05:50:40 | [diff] [blame] | 61 | // all those bits are in the same page. For example, if the relocation |
Rafael Espindola | b8ff59a | 2016-04-28 14:34:39 | [diff] [blame] | 62 | // only uses the low 12 bits in a system with 4k pages. If this is true, the |
| 63 | // bits will always have the same value at runtime and we don't have to emit |
| 64 | // a dynamic relocation. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 65 | virtual bool usesOnlyLowPageBits(RelType type) const; |
Rui Ueyama | 2b0edc2 | 2016-01-08 02:41:35 | [diff] [blame] | 66 | |
Peter Smith | fb05cd9 | 2016-07-08 16:10:27 | [diff] [blame] | 67 | // Decide whether a Thunk is needed for the relocation from File |
Peter Smith | 3a52eb0 | 2017-02-01 10:26:03 | [diff] [blame] | 68 | // targeting S. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 69 | virtual bool needsThunk(RelExpr expr, RelType relocType, |
| 70 | const InputFile *file, uint64_t branchAddr, |
Fangrui Song | bf535ac | 2019-11-23 08:57:54 | [diff] [blame] | 71 | const Symbol &s, int64_t a) const; |
Sterling Augustine | 4fd84c18 | 2018-07-17 23:16:02 | [diff] [blame] | 72 | |
Peter Smith | a8656c62 | 2018-08-20 09:37:50 | [diff] [blame] | 73 | // On systems with range extensions we place collections of Thunks at |
| 74 | // regular spacings that enable the majority of branches reach the Thunks. |
| 75 | // a value of 0 means range extension thunks are not supported. |
| 76 | virtual uint32_t getThunkSectionSpacing() const { return 0; } |
| 77 | |
Sterling Augustine | 4fd84c18 | 2018-07-17 23:16:02 | [diff] [blame] | 78 | // The function with a prologue starting at Loc was compiled with |
| 79 | // -fsplit-stack and it calls a function compiled without. Adjust the prologue |
| 80 | // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks. |
Sean Fertile | 4b5ec7f | 2018-10-16 17:13:01 | [diff] [blame] | 81 | // The symbols st_other flags are needed on PowerPC64 for determining the |
| 82 | // offset to the split-stack prologue. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 83 | virtual bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, |
| 84 | uint8_t stOther) const; |
Sterling Augustine | 4fd84c18 | 2018-07-17 23:16:02 | [diff] [blame] | 85 | |
Fangrui Song | 47cfe8f | 2019-07-16 05:50:45 | [diff] [blame] | 86 | // Return true if we can reach dst from src with RelType type. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 87 | virtual bool inBranchRange(RelType type, uint64_t src, |
| 88 | uint64_t dst) const; |
Rui Ueyama | 67533a2 | 2017-10-11 22:49:24 | [diff] [blame] | 89 | |
Fangrui Song | deb5819 | 2020-01-23 05:39:16 | [diff] [blame] | 90 | virtual void relocate(uint8_t *loc, const Relocation &rel, |
| 91 | uint64_t val) const = 0; |
| 92 | void relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const { |
| 93 | relocate(loc, Relocation{R_NONE, type, 0, 0, nullptr}, val); |
| 94 | } |
Fangrui Song | 685b212 | 2022-10-17 18:01:10 | [diff] [blame] | 95 | virtual void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const; |
Rui Ueyama | 67533a2 | 2017-10-11 22:49:24 | [diff] [blame] | 96 | |
Fangrui Song | 6611d58 | 2022-07-07 17:16:09 | [diff] [blame] | 97 | // Do a linker relaxation pass and return true if we changed something. |
| 98 | virtual bool relaxOnce(int pass) const { return false; } |
Jinyang He | 06a728f | 2024-02-06 01:09:13 | [diff] [blame] | 99 | // Do finalize relaxation after collecting relaxation infos. |
| 100 | virtual void finalizeRelax(int passes) const {} |
Fangrui Song | 6611d58 | 2022-07-07 17:16:09 | [diff] [blame] | 101 | |
Sriraman Tallam | 9431787 | 2020-04-07 13:48:18 | [diff] [blame] | 102 | virtual void applyJumpInstrMod(uint8_t *loc, JumpModType type, |
| 103 | JumpModType val) const {} |
| 104 | |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 105 | virtual ~TargetInfo(); |
| 106 | |
Sriraman Tallam | 9431787 | 2020-04-07 13:48:18 | [diff] [blame] | 107 | // This deletes a jump insn at the end of the section if it is a fall thru to |
| 108 | // the next section. Further, if there is a conditional jump and a direct |
| 109 | // jump consecutively, it tries to flip the conditional jump to convert the |
| 110 | // direct jump into a fall thru and delete it. Returns true if a jump |
| 111 | // instruction can be deleted. |
| 112 | virtual bool deleteFallThruJmpInsn(InputSection &is, InputFile *file, |
| 113 | InputSection *nextIS) const { |
| 114 | return false; |
| 115 | } |
| 116 | |
Fangrui Song | c3e4998 | 2024-09-29 04:48:26 | [diff] [blame] | 117 | Ctx &ctx; |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 118 | unsigned defaultCommonPageSize = 4096; |
| 119 | unsigned defaultMaxPageSize = 4096; |
Hal Finkel | 736c741 | 2015-10-15 07:49:07 | [diff] [blame] | 120 | |
Rui Ueyama | c694633 | 2019-03-28 17:05:09 | [diff] [blame] | 121 | uint64_t getImageBase() const; |
Hal Finkel | 736c741 | 2015-10-15 07:49:07 | [diff] [blame] | 122 | |
Peter Smith | 3d044f5 | 2018-03-19 06:52:51 | [diff] [blame] | 123 | // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. |
Fangrui Song | 40cd4db | 2021-09-25 22:06:09 | [diff] [blame] | 124 | bool gotBaseSymInGotPlt = false; |
Peter Smith | 113a59e | 2017-06-26 10:22:17 | [diff] [blame] | 125 | |
Fangrui Song | d23fd8a | 2021-09-25 22:16:44 | [diff] [blame] | 126 | static constexpr RelType noneRel = 0; |
Fangrui Song | c35214c | 2024-10-08 06:07:50 | [diff] [blame] | 127 | RelType copyRel = 0; |
| 128 | RelType gotRel = 0; |
| 129 | RelType pltRel = 0; |
| 130 | RelType relativeRel = 0; |
| 131 | RelType iRelativeRel = 0; |
| 132 | RelType symbolicRel = 0; |
| 133 | RelType tlsDescRel = 0; |
| 134 | RelType tlsGotRel = 0; |
| 135 | RelType tlsModuleIndexRel = 0; |
| 136 | RelType tlsOffsetRel = 0; |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 137 | unsigned gotEntrySize = ctx.arg.wordsize; |
Fangrui Song | c35214c | 2024-10-08 06:07:50 | [diff] [blame] | 138 | unsigned pltEntrySize = 0; |
| 139 | unsigned pltHeaderSize = 0; |
| 140 | unsigned ipltEntrySize = 0; |
Rafael Espindola | 4ee6cb3 | 2016-05-09 18:12:15 | [diff] [blame] | 141 | |
| 142 | // At least on x86_64 positions 1 and 2 are used by the first plt entry |
| 143 | // to support lazy loading. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 144 | unsigned gotPltHeaderEntriesNum = 3; |
Rafael Espindola | 4ee6cb3 | 2016-05-09 18:12:15 | [diff] [blame] | 145 | |
Zaara Syeda | 52ed6eb | 2018-03-19 17:40:14 | [diff] [blame] | 146 | // On PPC ELF V2 abi, the first entry in the .got is the .TOC. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 147 | unsigned gotHeaderEntriesNum = 0; |
Zaara Syeda | 52ed6eb | 2018-03-19 17:40:14 | [diff] [blame] | 148 | |
Stefan Pintilie | 658f23f | 2023-06-02 18:46:25 | [diff] [blame] | 149 | // On PPC ELF V2 abi, the dynamic section needs DT_PPC64_OPT (DT_LOPROC + 3) |
| 150 | // to be set to 0x2 if there can be multiple TOC's. Although we do not emit |
| 151 | // multiple TOC's, there can be a mix of TOC and NOTOC addressing which |
| 152 | // is functionally equivalent. |
| 153 | int ppc64DynamicSectionOpt = 0; |
| 154 | |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 155 | bool needsThunks = false; |
Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 | [diff] [blame] | 156 | |
James Henderson | 9d9a663 | 2017-04-07 10:36:42 | [diff] [blame] | 157 | // A 4-byte field corresponding to one or more trap instructions, used to pad |
| 158 | // executable OutputSections. |
Fangrui Song | c35214c | 2024-10-08 06:07:50 | [diff] [blame] | 159 | std::array<uint8_t, 4> trapInstr = {}; |
James Henderson | 9d9a663 | 2017-04-07 10:36:42 | [diff] [blame] | 160 | |
Sriraman Tallam | 9431787 | 2020-04-07 13:48:18 | [diff] [blame] | 161 | // Stores the NOP instructions of different sizes for the target and is used |
| 162 | // to pad sections that are relaxed. |
Fangrui Song | 4191fda | 2022-11-27 03:19:15 | [diff] [blame] | 163 | std::optional<std::vector<std::vector<uint8_t>>> nopInstrs; |
Sriraman Tallam | 9431787 | 2020-04-07 13:48:18 | [diff] [blame] | 164 | |
Sean Fertile | 4b5ec7f | 2018-10-16 17:13:01 | [diff] [blame] | 165 | // If a target needs to rewrite calls to __morestack to instead call |
| 166 | // __morestack_non_split when a split-stack enabled caller calls a |
| 167 | // non-split-stack callee this will return true. Otherwise returns false. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 168 | bool needsMoreStackNonSplit = true; |
Sean Fertile | 4b5ec7f | 2018-10-16 17:13:01 | [diff] [blame] | 169 | |
Fangrui Song | 50564ca | 2020-11-25 17:00:55 | [diff] [blame] | 170 | virtual RelExpr adjustTlsExpr(RelType type, RelExpr expr) const; |
Fangrui Song | 572d183 | 2020-11-25 16:43:26 | [diff] [blame] | 171 | virtual RelExpr adjustGotPcExpr(RelType type, int64_t addend, |
| 172 | const uint8_t *loc) const; |
James Henderson | b5ca92e | 2017-10-10 10:09:35 | [diff] [blame] | 173 | |
| 174 | protected: |
| 175 | // On FreeBSD x86_64 the first page cannot be mmaped. |
Nico Weber | 4138fc9 | 2019-10-31 02:17:52 | [diff] [blame] | 176 | // On Linux this is controlled by vm.mmap_min_addr. At least on some x86_64 |
| 177 | // installs this is set to 65536, so the first 15 pages cannot be used. |
James Henderson | b5ca92e | 2017-10-10 10:09:35 | [diff] [blame] | 178 | // Given that, the smallest value that can be used in here is 0x10000. |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 179 | uint64_t defaultImageBase = 0x10000; |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 180 | }; |
| 181 | |
Fangrui Song | e1a073c | 2024-10-08 06:14:02 | [diff] [blame] | 182 | void setAArch64TargetInfo(Ctx &); |
| 183 | void setAMDGPUTargetInfo(Ctx &); |
| 184 | void setARMTargetInfo(Ctx &); |
| 185 | void setAVRTargetInfo(Ctx &); |
| 186 | void setHexagonTargetInfo(Ctx &); |
| 187 | void setLoongArchTargetInfo(Ctx &); |
| 188 | void setMSP430TargetInfo(Ctx &); |
| 189 | void setMipsTargetInfo(Ctx &); |
| 190 | void setPPC64TargetInfo(Ctx &); |
| 191 | void setPPCTargetInfo(Ctx &); |
| 192 | void setRISCVTargetInfo(Ctx &); |
| 193 | void setSPARCV9TargetInfo(Ctx &); |
| 194 | void setSystemZTargetInfo(Ctx &); |
| 195 | void setX86TargetInfo(Ctx &); |
| 196 | void setX86_64TargetInfo(Ctx &); |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 197 | |
George Rimar | 89481f3 | 2018-03-21 09:19:34 | [diff] [blame] | 198 | struct ErrorPlace { |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 199 | InputSectionBase *isec; |
| 200 | std::string loc; |
Fangrui Song | 2b1e324 | 2021-10-28 16:38:45 | [diff] [blame] | 201 | std::string srcLoc; |
George Rimar | 89481f3 | 2018-03-21 09:19:34 | [diff] [blame] | 202 | }; |
| 203 | |
| 204 | // Returns input section and corresponding source string for the given location. |
Fangrui Song | a522516 | 2024-09-29 02:23:56 | [diff] [blame] | 205 | ErrorPlace getErrorPlace(Ctx &ctx, const uint8_t *loc); |
George Rimar | 89481f3 | 2018-03-21 09:19:34 | [diff] [blame] | 206 | |
Fangrui Song | cfd3289 | 2024-10-07 02:36:21 | [diff] [blame] | 207 | static inline std::string getErrorLoc(Ctx &ctx, const uint8_t *loc) { |
Fangrui Song | a522516 | 2024-09-29 02:23:56 | [diff] [blame] | 208 | return getErrorPlace(ctx, loc).loc; |
George Rimar | 89481f3 | 2018-03-21 09:19:34 | [diff] [blame] | 209 | } |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 210 | |
Fangrui Song | 079b832 | 2024-09-29 23:06:47 | [diff] [blame] | 211 | void processArmCmseSymbols(Ctx &); |
Amilendra Kodithuwakku | 9acbab6 | 2023-07-06 09:45:10 | [diff] [blame] | 212 | |
Fangrui Song | b3e0bd3 | 2024-10-06 07:31:51 | [diff] [blame] | 213 | template <class ELFT> uint32_t calcMipsEFlags(Ctx &); |
Fangrui Song | c4dc5ed | 2024-11-24 19:43:40 | [diff] [blame] | 214 | uint8_t getMipsFpAbiFlag(Ctx &, InputFile *file, uint8_t oldFlag, |
| 215 | uint8_t newFlag); |
Fangrui Song | b3e0bd3 | 2024-10-06 07:31:51 | [diff] [blame] | 216 | bool isMipsN32Abi(Ctx &, const InputFile &f); |
| 217 | bool isMicroMips(Ctx &); |
| 218 | bool isMipsR6(Ctx &); |
| 219 | |
Fangrui Song | 6d03a69 | 2024-10-06 07:14:12 | [diff] [blame] | 220 | void writePPC32GlinkSection(Ctx &, uint8_t *buf, size_t numEntries); |
Fangrui Song | 82442ad | 2019-06-06 17:03:00 | [diff] [blame] | 221 | |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 222 | unsigned getPPCDFormOp(unsigned secondaryOp); |
Amy Kwan | 698b45a | 2023-08-30 16:54:12 | [diff] [blame] | 223 | unsigned getPPCDSFormOp(unsigned secondaryOp); |
Fangrui Song | 912251e | 2019-05-07 04:26:05 | [diff] [blame] | 224 | |
| 225 | // In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first |
| 226 | // is a global entry point (GEP) which typically is used to initialize the TOC |
Sean Fertile | e0e586b | 2018-09-20 00:26:47 | [diff] [blame] | 227 | // pointer in general purpose register 2. The second is a local entry |
| 228 | // point (LEP) which bypasses the TOC pointer initialization code. The |
| 229 | // offset between GEP and LEP is encoded in a function's st_other flags. |
| 230 | // This function will return the offset (in bytes) from the global entry-point |
| 231 | // to the local entry-point. |
Fangrui Song | d69cc05 | 2024-11-15 06:30:29 | [diff] [blame] | 232 | unsigned getPPC64GlobalEntryToLocalEntryOffset(Ctx &, uint8_t stOther); |
Sean Fertile | e0e586b | 2018-09-20 00:26:47 | [diff] [blame] | 233 | |
Victor Huang | 91cce1a | 2020-07-20 17:40:41 | [diff] [blame] | 234 | // Write a prefixed instruction, which is a 4-byte prefix followed by a 4-byte |
| 235 | // instruction (regardless of endianness). Therefore, the prefix is always in |
| 236 | // lower memory than the instruction. |
Fangrui Song | 6d03a69 | 2024-10-06 07:14:12 | [diff] [blame] | 237 | void writePrefixedInst(Ctx &, uint8_t *loc, uint64_t insn); |
Victor Huang | 91cce1a | 2020-07-20 17:40:41 | [diff] [blame] | 238 | |
Fangrui Song | 6d03a69 | 2024-10-06 07:14:12 | [diff] [blame] | 239 | void addPPC64SaveRestore(Ctx &); |
| 240 | uint64_t getPPC64TocBase(Ctx &ctx); |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 241 | uint64_t getAArch64Page(uint64_t expr); |
Fangrui Song | 4fadf41 | 2024-10-08 06:29:11 | [diff] [blame] | 242 | bool isAArch64BTILandingPad(Ctx &, Symbol &s, int64_t a); |
Fangrui Song | 6d03a69 | 2024-10-06 07:14:12 | [diff] [blame] | 243 | template <typename ELFT> void writeARMCmseImportLib(Ctx &); |
Lu Weining | 38394a3 | 2024-01-10 10:03:52 | [diff] [blame] | 244 | uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type); |
Fangrui Song | 6611d58 | 2022-07-07 17:16:09 | [diff] [blame] | 245 | void riscvFinalizeRelax(int passes); |
Fangrui Song | 079b832 | 2024-09-29 23:06:47 | [diff] [blame] | 246 | void mergeRISCVAttributesSections(Ctx &); |
Fangrui Song | 6d03a69 | 2024-10-06 07:14:12 | [diff] [blame] | 247 | void addArmInputSectionMappingSymbols(Ctx &); |
Simi Pallipurath | f146763 | 2023-06-22 12:55:59 | [diff] [blame] | 248 | void addArmSyntheticSectionMappingSymbol(Defined *); |
Fangrui Song | 4092c0d | 2024-11-18 17:08:29 | [diff] [blame] | 249 | void sortArmMappingSymbols(Ctx &); |
| 250 | void convertArmInstructionstoBE8(Ctx &, InputSection *sec, uint8_t *buf); |
Fangrui Song | 6d03a69 | 2024-10-06 07:14:12 | [diff] [blame] | 251 | void createTaggedSymbols(Ctx &); |
| 252 | void initSymbolAnchors(Ctx &); |
Hal Finkel | 6f97c2b | 2015-10-16 21:55:40 | [diff] [blame] | 253 | |
Fangrui Song | e1a073c | 2024-10-08 06:14:02 | [diff] [blame] | 254 | void setTarget(Ctx &); |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 255 | |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 256 | template <class ELFT> bool isMipsPIC(const Defined *sym); |
Rui Ueyama | 7957b08 | 2017-11-07 00:04:22 | [diff] [blame] | 257 | |
Fangrui Song | 47e6673 | 2024-11-16 18:12:08 | [diff] [blame] | 258 | const ELFSyncStream &operator<<(const ELFSyncStream &, RelType); |
| 259 | |
Fangrui Song | c490d34 | 2024-09-29 23:15:32 | [diff] [blame] | 260 | void reportRangeError(Ctx &, uint8_t *loc, const Relocation &rel, |
| 261 | const Twine &v, int64_t min, uint64_t max); |
Fangrui Song | 29783f7 | 2024-09-29 02:17:18 | [diff] [blame] | 262 | void reportRangeError(Ctx &ctx, uint8_t *loc, int64_t v, int n, |
| 263 | const Symbol &sym, const Twine &msg); |
Alexander Richardson | d2481be | 2017-12-11 20:47:21 | [diff] [blame] | 264 | |
Rui Ueyama | f001ead | 2018-03-29 22:40:52 | [diff] [blame] | 265 | // Make sure that V can be represented as an N bit signed integer. |
Fangrui Song | 2c5dd03 | 2024-10-13 18:14:40 | [diff] [blame] | 266 | inline void checkInt(Ctx &ctx, uint8_t *loc, int64_t v, int n, |
| 267 | const Relocation &rel) { |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 268 | if (v != llvm::SignExtend64(v, n)) |
Fangrui Song | c490d34 | 2024-09-29 23:15:32 | [diff] [blame] | 269 | reportRangeError(ctx, loc, rel, Twine(v), llvm::minIntN(n), |
| 270 | llvm::maxIntN(n)); |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 271 | } |
Rui Ueyama | ce03926 | 2017-01-06 10:04:08 | [diff] [blame] | 272 | |
Rui Ueyama | f001ead | 2018-03-29 22:40:52 | [diff] [blame] | 273 | // Make sure that V can be represented as an N bit unsigned integer. |
Fangrui Song | 2c5dd03 | 2024-10-13 18:14:40 | [diff] [blame] | 274 | inline void checkUInt(Ctx &ctx, uint8_t *loc, uint64_t v, int n, |
| 275 | const Relocation &rel) { |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 276 | if ((v >> n) != 0) |
Fangrui Song | c490d34 | 2024-09-29 23:15:32 | [diff] [blame] | 277 | reportRangeError(ctx, loc, rel, Twine(v), 0, llvm::maxUIntN(n)); |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 278 | } |
| 279 | |
Rui Ueyama | f001ead | 2018-03-29 22:40:52 | [diff] [blame] | 280 | // Make sure that V can be represented as an N bit signed or unsigned integer. |
Fangrui Song | 2c5dd03 | 2024-10-13 18:14:40 | [diff] [blame] | 281 | inline void checkIntUInt(Ctx &ctx, uint8_t *loc, uint64_t v, int n, |
Fangrui Song | deb5819 | 2020-01-23 05:39:16 | [diff] [blame] | 282 | const Relocation &rel) { |
Rui Ueyama | f001ead | 2018-03-29 22:40:52 | [diff] [blame] | 283 | // For the error message we should cast V to a signed integer so that error |
| 284 | // messages show a small negative value rather than an extremely large one |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 285 | if (v != (uint64_t)llvm::SignExtend64(v, n) && (v >> n) != 0) |
Fangrui Song | c490d34 | 2024-09-29 23:15:32 | [diff] [blame] | 286 | reportRangeError(ctx, loc, rel, Twine((int64_t)v), llvm::minIntN(n), |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 287 | llvm::maxUIntN(n)); |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 288 | } |
| 289 | |
Fangrui Song | 2c5dd03 | 2024-10-13 18:14:40 | [diff] [blame] | 290 | inline void checkAlignment(Ctx &ctx, uint8_t *loc, uint64_t v, int n, |
Fangrui Song | deb5819 | 2020-01-23 05:39:16 | [diff] [blame] | 291 | const Relocation &rel) { |
Rui Ueyama | 3837f42 | 2019-07-10 05:00:37 | [diff] [blame] | 292 | if ((v & (n - 1)) != 0) |
Fangrui Song | 47e6673 | 2024-11-16 18:12:08 | [diff] [blame] | 293 | Err(ctx) << getErrorLoc(ctx, loc) << "improper alignment for relocation " |
| 294 | << rel.type << ": 0x" << llvm::utohexstr(v) |
Fangrui Song | 1cd6275 | 2024-11-24 20:13:01 | [diff] [blame] | 295 | << " is not aligned to " << n << " bytes"; |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 296 | } |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 297 | |
| 298 | // Endianness-aware read/write. |
Fangrui Song | 002ca63 | 2024-10-13 17:47:18 | [diff] [blame] | 299 | inline uint16_t read16(Ctx &ctx, const void *p) { |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 300 | return llvm::support::endian::read16(p, ctx.arg.endianness); |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 301 | } |
| 302 | |
Fangrui Song | 38dfcd9 | 2024-10-13 17:37:47 | [diff] [blame] | 303 | inline uint32_t read32(Ctx &ctx, const void *p) { |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 304 | return llvm::support::endian::read32(p, ctx.arg.endianness); |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 305 | } |
| 306 | |
Fangrui Song | 002ca63 | 2024-10-13 17:47:18 | [diff] [blame] | 307 | inline uint64_t read64(Ctx &ctx, const void *p) { |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 308 | return llvm::support::endian::read64(p, ctx.arg.endianness); |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 309 | } |
| 310 | |
Fangrui Song | 002ca63 | 2024-10-13 17:47:18 | [diff] [blame] | 311 | inline void write16(Ctx &ctx, void *p, uint16_t v) { |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 312 | llvm::support::endian::write16(p, v, ctx.arg.endianness); |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 313 | } |
| 314 | |
Fangrui Song | 38dfcd9 | 2024-10-13 17:37:47 | [diff] [blame] | 315 | inline void write32(Ctx &ctx, void *p, uint32_t v) { |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 316 | llvm::support::endian::write32(p, v, ctx.arg.endianness); |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 317 | } |
| 318 | |
Fangrui Song | 002ca63 | 2024-10-13 17:47:18 | [diff] [blame] | 319 | inline void write64(Ctx &ctx, void *p, uint64_t v) { |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 320 | llvm::support::endian::write64(p, v, ctx.arg.endianness); |
Fangrui Song | 0c48302 | 2018-03-09 18:03:22 | [diff] [blame] | 321 | } |
Fangrui Song | 3fa1795 | 2024-01-09 04:24:00 | [diff] [blame] | 322 | |
| 323 | // Overwrite a ULEB128 value and keep the original length. |
| 324 | inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) { |
| 325 | while (*bufLoc & 0x80) { |
| 326 | *bufLoc++ = 0x80 | (val & 0x7f); |
| 327 | val >>= 7; |
| 328 | } |
| 329 | *bufLoc = val; |
| 330 | return val; |
| 331 | } |
Rui Ueyama | 21c0a9c | 2017-06-16 17:32:43 | [diff] [blame] | 332 | } // namespace elf |
George Rimar | 67c6072 | 2017-07-18 11:55:35 | [diff] [blame] | 333 | } // namespace lld |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 334 | |
Fangrui Song | 7518d38 | 2022-02-01 17:47:56 | [diff] [blame] | 335 | #ifdef __clang__ |
| 336 | #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" |
| 337 | #endif |
| 338 | #define invokeELFT(f, ...) \ |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 339 | switch (ctx.arg.ekind) { \ |
Mitch Phillips | ca35a19 | 2023-07-31 15:07:26 | [diff] [blame] | 340 | case lld::elf::ELF32LEKind: \ |
| 341 | f<llvm::object::ELF32LE>(__VA_ARGS__); \ |
Fangrui Song | 7518d38 | 2022-02-01 17:47:56 | [diff] [blame] | 342 | break; \ |
Mitch Phillips | ca35a19 | 2023-07-31 15:07:26 | [diff] [blame] | 343 | case lld::elf::ELF32BEKind: \ |
| 344 | f<llvm::object::ELF32BE>(__VA_ARGS__); \ |
Fangrui Song | 7518d38 | 2022-02-01 17:47:56 | [diff] [blame] | 345 | break; \ |
Mitch Phillips | ca35a19 | 2023-07-31 15:07:26 | [diff] [blame] | 346 | case lld::elf::ELF64LEKind: \ |
| 347 | f<llvm::object::ELF64LE>(__VA_ARGS__); \ |
Fangrui Song | 7518d38 | 2022-02-01 17:47:56 | [diff] [blame] | 348 | break; \ |
Mitch Phillips | ca35a19 | 2023-07-31 15:07:26 | [diff] [blame] | 349 | case lld::elf::ELF64BEKind: \ |
| 350 | f<llvm::object::ELF64BE>(__VA_ARGS__); \ |
Fangrui Song | 7518d38 | 2022-02-01 17:47:56 | [diff] [blame] | 351 | break; \ |
| 352 | default: \ |
Fangrui Song | 777329d | 2024-09-23 00:48:48 | [diff] [blame] | 353 | llvm_unreachable("unknown ctx.arg.ekind"); \ |
Fangrui Song | 7518d38 | 2022-02-01 17:47:56 | [diff] [blame] | 354 | } |
| 355 | |
Rafael Espindola | 01205f7 | 2015-09-22 18:19:46 | [diff] [blame] | 356 | #endif |