| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 1 | //===- Relocations.cpp ----------------------------------------------------===// | 
|  | 2 | // | 
|  | 3 | //                             The LLVM Linker | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
| George Rimar | 95912d0 | 2016-06-08 12:29:29 +0000 | [diff] [blame] | 10 | // This file contains platform-independent functions to process relocations. | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 11 | // I'll describe the overview of this file here. | 
|  | 12 | // | 
|  | 13 | // Simple relocations are easy to handle for the linker. For example, | 
|  | 14 | // for R_X86_64_PC64 relocs, the linker just has to fix up locations | 
|  | 15 | // with the relative offsets to the target symbols. It would just be | 
|  | 16 | // reading records from relocation sections and applying them to output. | 
|  | 17 | // | 
|  | 18 | // But not all relocations are that easy to handle. For example, for | 
|  | 19 | // R_386_GOTOFF relocs, the linker has to create new GOT entries for | 
|  | 20 | // symbols if they don't exist, and fix up locations with GOT entry | 
|  | 21 | // offsets from the beginning of GOT section. So there is more than | 
|  | 22 | // fixing addresses in relocation processing. | 
|  | 23 | // | 
|  | 24 | // ELF defines a large number of complex relocations. | 
|  | 25 | // | 
|  | 26 | // The functions in this file analyze relocations and do whatever needs | 
|  | 27 | // to be done. It includes, but not limited to, the following. | 
|  | 28 | // | 
|  | 29 | //  - create GOT/PLT entries | 
|  | 30 | //  - create new relocations in .dynsym to let the dynamic linker resolve | 
|  | 31 | //    them at runtime (since ELF supports dynamic linking, not all | 
|  | 32 | //    relocations can be resolved at link-time) | 
|  | 33 | //  - create COPY relocs and reserve space in .bss | 
|  | 34 | //  - replace expensive relocs (in terms of runtime cost) with cheap ones | 
|  | 35 | //  - error out infeasible combinations such as PIC and non-relative relocs | 
|  | 36 | // | 
|  | 37 | // Note that the functions in this file don't actually apply relocations | 
|  | 38 | // because it doesn't know about the output file nor the output file buffer. | 
|  | 39 | // It instead stores Relocation objects to InputSection's Relocations | 
|  | 40 | // vector to let it apply later in InputSection::writeTo. | 
|  | 41 | // | 
|  | 42 | //===----------------------------------------------------------------------===// | 
|  | 43 |  | 
|  | 44 | #include "Relocations.h" | 
|  | 45 | #include "Config.h" | 
|  | 46 | #include "OutputSections.h" | 
|  | 47 | #include "SymbolTable.h" | 
|  | 48 | #include "Target.h" | 
| Peter Smith | fb05cd9 | 2016-07-08 16:10:27 +0000 | [diff] [blame] | 49 | #include "Thunks.h" | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 50 |  | 
|  | 51 | #include "llvm/Support/Endian.h" | 
|  | 52 | #include "llvm/Support/raw_ostream.h" | 
|  | 53 |  | 
|  | 54 | using namespace llvm; | 
|  | 55 | using namespace llvm::ELF; | 
|  | 56 | using namespace llvm::object; | 
|  | 57 | using namespace llvm::support::endian; | 
|  | 58 |  | 
|  | 59 | namespace lld { | 
|  | 60 | namespace elf { | 
|  | 61 |  | 
|  | 62 | static bool refersToGotEntry(RelExpr Expr) { | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 63 | return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE || | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 64 | Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD || | 
|  | 65 | Expr == R_MIPS_TLSLD || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC || | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 66 | Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC || | 
|  | 67 | Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 68 | } | 
|  | 69 |  | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 70 | static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { | 
|  | 71 | // In case of MIPS GP-relative relocations always resolve to a definition | 
|  | 72 | // in a regular input file, ignoring the one-definition rule. So we, | 
|  | 73 | // for example, should not attempt to create a dynamic relocation even | 
|  | 74 | // if the target symbol is preemptible. There are two two MIPS GP-relative | 
|  | 75 | // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 | 
|  | 76 | // can be against a preemptible symbol. | 
| Simon Atanasyan | a26a157 | 2016-06-10 12:26:09 +0000 | [diff] [blame] | 77 | // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 78 | // relocation types occupy eight bit. In case of N64 ABI we extract first | 
|  | 79 | // relocation from 3-in-1 packet because only the first relocation can | 
|  | 80 | // be against a real symbol. | 
| Simon Atanasyan | a26a157 | 2016-06-10 12:26:09 +0000 | [diff] [blame] | 81 | if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16) | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 82 | return false; | 
|  | 83 | return Body.isPreemptible(); | 
|  | 84 | } | 
|  | 85 |  | 
| Peter Smith | fde6213 | 2016-09-23 13:54:48 +0000 | [diff] [blame] | 86 | // This function is similar to the `handleTlsRelocation`. ARM and MIPS do not | 
|  | 87 | // support any relaxations for TLS relocations so by factoring out ARM and MIPS | 
|  | 88 | // handling in to the separate function we can simplify the code and do not | 
|  | 89 | // pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements. | 
|  | 90 | // FIXME: The ARM implementation always adds the module index dynamic | 
|  | 91 | // relocation even for non-preemptible symbols in applications. For static | 
|  | 92 | // linking support we must either resolve the module index relocation at static | 
|  | 93 | // link time, or hard code the module index (1) for the application in the GOT. | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 94 | template <class ELFT> | 
| Peter Smith | fde6213 | 2016-09-23 13:54:48 +0000 | [diff] [blame] | 95 | static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body, | 
|  | 96 | InputSectionBase<ELFT> &C, | 
|  | 97 | typename ELFT::uint Offset, | 
|  | 98 | typename ELFT::uint Addend, | 
|  | 99 | RelExpr Expr) { | 
|  | 100 | if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { | 
|  | 101 | if (Out<ELFT>::Got->addTlsIndex() && | 
|  | 102 | (Config->Pic || Config->EMachine == EM_ARM)) | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 103 | Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got, | 
|  | 104 | Out<ELFT>::Got->getTlsIndexOff(), false, | 
|  | 105 | nullptr, 0}); | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 106 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 107 | return 1; | 
|  | 108 | } | 
| Peter Smith | fde6213 | 2016-09-23 13:54:48 +0000 | [diff] [blame] | 109 | typedef typename ELFT::uint uintX_t; | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 110 | if (Target->isTlsGlobalDynamicRel(Type)) { | 
| Peter Smith | fde6213 | 2016-09-23 13:54:48 +0000 | [diff] [blame] | 111 | if (Out<ELFT>::Got->addDynTlsEntry(Body) && | 
|  | 112 | (Body.isPreemptible() || Config->EMachine == EM_ARM)) { | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 113 | uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); | 
|  | 114 | Out<ELFT>::RelaDyn->addReloc( | 
|  | 115 | {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0}); | 
| Peter Smith | fde6213 | 2016-09-23 13:54:48 +0000 | [diff] [blame] | 116 | if (Body.isPreemptible()) | 
|  | 117 | Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got, | 
|  | 118 | Off + (uintX_t)sizeof(uintX_t), false, | 
|  | 119 | &Body, 0}); | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 120 | } | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 121 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 122 | return 1; | 
|  | 123 | } | 
|  | 124 | return 0; | 
|  | 125 | } | 
|  | 126 |  | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 127 | // Returns the number of relocations processed. | 
|  | 128 | template <class ELFT> | 
|  | 129 | static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, | 
|  | 130 | InputSectionBase<ELFT> &C, | 
|  | 131 | typename ELFT::uint Offset, | 
|  | 132 | typename ELFT::uint Addend, RelExpr Expr) { | 
|  | 133 | if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC)) | 
|  | 134 | return 0; | 
|  | 135 |  | 
|  | 136 | if (!Body.isTls()) | 
|  | 137 | return 0; | 
|  | 138 |  | 
|  | 139 | typedef typename ELFT::uint uintX_t; | 
| Rafael Espindola | e37d13b | 2016-06-02 19:49:53 +0000 | [diff] [blame] | 140 |  | 
| Peter Smith | fde6213 | 2016-09-23 13:54:48 +0000 | [diff] [blame] | 141 | if (Config->EMachine == EM_MIPS || Config->EMachine == EM_ARM) | 
|  | 142 | return handleNoRelaxTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, | 
|  | 143 | Expr); | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 144 |  | 
| Rafael Espindola | e37d13b | 2016-06-02 19:49:53 +0000 | [diff] [blame] | 145 | if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) && | 
|  | 146 | Config->Shared) { | 
|  | 147 | if (Out<ELFT>::Got->addDynTlsEntry(Body)) { | 
|  | 148 | uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); | 
|  | 149 | Out<ELFT>::RelaDyn->addReloc( | 
|  | 150 | {Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0}); | 
|  | 151 | } | 
|  | 152 | if (Expr != R_HINT) | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 153 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); | 
| Rafael Espindola | e37d13b | 2016-06-02 19:49:53 +0000 | [diff] [blame] | 154 | return 1; | 
|  | 155 | } | 
|  | 156 |  | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 157 | if (Expr == R_TLSLD_PC || Expr == R_TLSLD) { | 
|  | 158 | // Local-Dynamic relocs can be relaxed to Local-Exec. | 
|  | 159 | if (!Config->Shared) { | 
|  | 160 | C.Relocations.push_back( | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 161 | {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 162 | return 2; | 
|  | 163 | } | 
|  | 164 | if (Out<ELFT>::Got->addTlsIndex()) | 
|  | 165 | Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got, | 
|  | 166 | Out<ELFT>::Got->getTlsIndexOff(), false, | 
|  | 167 | nullptr, 0}); | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 168 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 169 | return 1; | 
|  | 170 | } | 
|  | 171 |  | 
|  | 172 | // Local-Dynamic relocs can be relaxed to Local-Exec. | 
|  | 173 | if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) { | 
|  | 174 | C.Relocations.push_back( | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 175 | {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 176 | return 1; | 
|  | 177 | } | 
|  | 178 |  | 
| Rafael Espindola | e37d13b | 2016-06-02 19:49:53 +0000 | [diff] [blame] | 179 | if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_HINT || | 
|  | 180 | Target->isTlsGlobalDynamicRel(Type)) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 181 | if (Config->Shared) { | 
|  | 182 | if (Out<ELFT>::Got->addDynTlsEntry(Body)) { | 
|  | 183 | uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); | 
|  | 184 | Out<ELFT>::RelaDyn->addReloc( | 
|  | 185 | {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0}); | 
| Rafael Espindola | a8777c2 | 2016-06-08 21:31:59 +0000 | [diff] [blame] | 186 |  | 
|  | 187 | // If the symbol is preemptible we need the dynamic linker to write | 
|  | 188 | // the offset too. | 
| Simon Atanasyan | 9b86118 | 2016-06-10 12:26:39 +0000 | [diff] [blame] | 189 | if (isPreemptible(Body, Type)) | 
| Rafael Espindola | a8777c2 | 2016-06-08 21:31:59 +0000 | [diff] [blame] | 190 | Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got, | 
|  | 191 | Off + (uintX_t)sizeof(uintX_t), false, | 
|  | 192 | &Body, 0}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 193 | } | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 194 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 195 | return 1; | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec | 
|  | 199 | // depending on the symbol being locally defined or not. | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 200 | if (isPreemptible(Body, Type)) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 201 | C.Relocations.push_back( | 
| Rafael Espindola | 69f5402 | 2016-06-04 23:22:34 +0000 | [diff] [blame] | 202 | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 203 | Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 204 | if (!Body.isInGot()) { | 
|  | 205 | Out<ELFT>::Got->addEntry(Body); | 
|  | 206 | Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got, | 
|  | 207 | Body.getGotOffset<ELFT>(), false, &Body, | 
|  | 208 | 0}); | 
|  | 209 | } | 
| Rafael Espindola | e1979ae | 2016-06-04 23:33:31 +0000 | [diff] [blame] | 210 | return Target->TlsGdRelaxSkip; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 211 | } | 
|  | 212 | C.Relocations.push_back( | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 213 | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, | 
| Rafael Espindola | 69f5402 | 2016-06-04 23:22:34 +0000 | [diff] [blame] | 214 | Offset, Addend, &Body}); | 
| Rafael Espindola | f807d47 | 2016-06-04 23:04:39 +0000 | [diff] [blame] | 215 | return Target->TlsGdRelaxSkip; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 216 | } | 
|  | 217 |  | 
|  | 218 | // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally | 
|  | 219 | // defined. | 
|  | 220 | if (Target->isTlsInitialExecRel(Type) && !Config->Shared && | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 221 | !isPreemptible(Body, Type)) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 222 | C.Relocations.push_back( | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 223 | {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 224 | return 1; | 
|  | 225 | } | 
|  | 226 | return 0; | 
|  | 227 | } | 
|  | 228 |  | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 229 | template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) { | 
|  | 230 | return read32<E>(Loc) & 0xffff; | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | template <class RelTy> | 
|  | 234 | static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) { | 
|  | 235 | switch (Rel->getType(Config->Mips64EL)) { | 
|  | 236 | case R_MIPS_HI16: | 
|  | 237 | return R_MIPS_LO16; | 
|  | 238 | case R_MIPS_GOT16: | 
|  | 239 | return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE; | 
|  | 240 | case R_MIPS_PCHI16: | 
|  | 241 | return R_MIPS_PCLO16; | 
|  | 242 | case R_MICROMIPS_HI16: | 
|  | 243 | return R_MICROMIPS_LO16; | 
|  | 244 | default: | 
|  | 245 | return R_MIPS_NONE; | 
|  | 246 | } | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | template <class ELFT, class RelTy> | 
|  | 250 | static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc, | 
|  | 251 | SymbolBody &Sym, const RelTy *Rel, | 
|  | 252 | const RelTy *End) { | 
|  | 253 | uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL); | 
|  | 254 | uint32_t Type = getMipsPairType(Rel, Sym); | 
|  | 255 |  | 
|  | 256 | // Some MIPS relocations use addend calculated from addend of the relocation | 
|  | 257 | // itself and addend of paired relocation. ABI requires to compute such | 
|  | 258 | // combined addend in case of REL relocation record format only. | 
|  | 259 | // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | 
|  | 260 | if (RelTy::IsRela || Type == R_MIPS_NONE) | 
|  | 261 | return 0; | 
|  | 262 |  | 
|  | 263 | for (const RelTy *RI = Rel; RI != End; ++RI) { | 
|  | 264 | if (RI->getType(Config->Mips64EL) != Type) | 
|  | 265 | continue; | 
|  | 266 | if (RI->getSymbol(Config->Mips64EL) != SymIndex) | 
|  | 267 | continue; | 
|  | 268 | const endianness E = ELFT::TargetEndianness; | 
|  | 269 | return ((read32<E>(BufLoc) & 0xffff) << 16) + | 
|  | 270 | readSignedLo16<E>(Buf + RI->r_offset); | 
|  | 271 | } | 
| Rui Ueyama | d31e13f | 2016-09-29 21:00:23 +0000 | [diff] [blame] | 272 | warn("can't find matching " + getRelName(Type) + " relocation for " + | 
| George Rimar | e6389d1 | 2016-06-08 12:22:26 +0000 | [diff] [blame] | 273 | getRelName(Rel->getType(Config->Mips64EL))); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 274 | return 0; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | // True if non-preemptable symbol always has the same value regardless of where | 
|  | 278 | // the DSO is loaded. | 
|  | 279 | template <class ELFT> static bool isAbsolute(const SymbolBody &Body) { | 
|  | 280 | if (Body.isUndefined()) | 
|  | 281 | return !Body.isLocal() && Body.symbol()->isWeak(); | 
|  | 282 | if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body)) | 
|  | 283 | return DR->Section == nullptr; // Absolute symbol. | 
|  | 284 | return false; | 
|  | 285 | } | 
|  | 286 |  | 
|  | 287 | static bool needsPlt(RelExpr Expr) { | 
| Rafael Espindola | 12dc446 | 2016-06-04 19:11:14 +0000 | [diff] [blame] | 288 | return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT || | 
| Peter Smith | fb05cd9 | 2016-07-08 16:10:27 +0000 | [diff] [blame] | 289 | Expr == R_PLT_PAGE_PC || Expr == R_THUNK_PLT_PC; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 290 | } | 
|  | 291 |  | 
|  | 292 | // True if this expression is of the form Sym - X, where X is a position in the | 
|  | 293 | // file (PC, or GOT for example). | 
|  | 294 | static bool isRelExpr(RelExpr Expr) { | 
| Rafael Espindola | 719f55d | 2016-09-06 13:57:15 +0000 | [diff] [blame] | 295 | return Expr == R_PC || Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || | 
|  | 296 | Expr == R_PAGE_PC || Expr == R_RELAX_GOT_PC || Expr == R_THUNK_PC || | 
|  | 297 | Expr == R_THUNK_PLT_PC; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 298 | } | 
|  | 299 |  | 
|  | 300 | template <class ELFT> | 
|  | 301 | static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, | 
|  | 302 | const SymbolBody &Body) { | 
|  | 303 | // These expressions always compute a constant | 
|  | 304 | if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 305 | E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD || | 
|  | 306 | E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || | 
| Peter Smith | fb05cd9 | 2016-07-08 16:10:27 +0000 | [diff] [blame] | 307 | E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || | 
|  | 308 | E == R_HINT || E == R_THUNK_PC || E == R_THUNK_PLT_PC) | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 309 | return true; | 
|  | 310 |  | 
|  | 311 | // These never do, except if the entire file is position dependent or if | 
|  | 312 | // only the low bits are used. | 
| Rafael Espindola | e37d13b | 2016-06-02 19:49:53 +0000 | [diff] [blame] | 313 | if (E == R_GOT || E == R_PLT || E == R_TLSDESC) | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 314 | return Target->usesOnlyLowPageBits(Type) || !Config->Pic; | 
|  | 315 |  | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 316 | if (isPreemptible(Body, Type)) | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 317 | return false; | 
|  | 318 |  | 
|  | 319 | if (!Config->Pic) | 
|  | 320 | return true; | 
|  | 321 |  | 
|  | 322 | bool AbsVal = isAbsolute<ELFT>(Body) || Body.isTls(); | 
|  | 323 | bool RelE = isRelExpr(E); | 
|  | 324 | if (AbsVal && !RelE) | 
|  | 325 | return true; | 
|  | 326 | if (!AbsVal && RelE) | 
|  | 327 | return true; | 
|  | 328 |  | 
|  | 329 | // Relative relocation to an absolute value. This is normally unrepresentable, | 
|  | 330 | // but if the relocation refers to a weak undefined symbol, we allow it to | 
|  | 331 | // resolve to the image base. This is a little strange, but it allows us to | 
|  | 332 | // link function calls to such symbols. Normally such a call will be guarded | 
|  | 333 | // with a comparison, which will load a zero from the GOT. | 
|  | 334 | if (AbsVal && RelE) { | 
|  | 335 | if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) | 
|  | 336 | return true; | 
| George Rimar | e6389d1 | 2016-06-08 12:22:26 +0000 | [diff] [blame] | 337 | error("relocation " + getRelName(Type) + | 
|  | 338 | " cannot refer to absolute symbol " + Body.getName()); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 339 | return true; | 
|  | 340 | } | 
|  | 341 |  | 
|  | 342 | return Target->usesOnlyLowPageBits(Type); | 
|  | 343 | } | 
|  | 344 |  | 
|  | 345 | static RelExpr toPlt(RelExpr Expr) { | 
|  | 346 | if (Expr == R_PPC_OPD) | 
|  | 347 | return R_PPC_PLT_OPD; | 
|  | 348 | if (Expr == R_PC) | 
|  | 349 | return R_PLT_PC; | 
| Rafael Espindola | 12dc446 | 2016-06-04 19:11:14 +0000 | [diff] [blame] | 350 | if (Expr == R_PAGE_PC) | 
|  | 351 | return R_PLT_PAGE_PC; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 352 | if (Expr == R_ABS) | 
|  | 353 | return R_PLT; | 
|  | 354 | return Expr; | 
|  | 355 | } | 
|  | 356 |  | 
|  | 357 | static RelExpr fromPlt(RelExpr Expr) { | 
|  | 358 | // We decided not to use a plt. Optimize a reference to the plt to a | 
|  | 359 | // reference to the symbol itself. | 
|  | 360 | if (Expr == R_PLT_PC) | 
|  | 361 | return R_PC; | 
|  | 362 | if (Expr == R_PPC_PLT_OPD) | 
|  | 363 | return R_PPC_OPD; | 
|  | 364 | if (Expr == R_PLT) | 
|  | 365 | return R_ABS; | 
|  | 366 | return Expr; | 
|  | 367 | } | 
|  | 368 |  | 
|  | 369 | template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) { | 
|  | 370 | typedef typename ELFT::uint uintX_t; | 
|  | 371 |  | 
| Rui Ueyama | 434b561 | 2016-07-17 03:11:46 +0000 | [diff] [blame] | 372 | uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 373 | uintX_t SymValue = SS->Sym.st_value; | 
|  | 374 | int TrailingZeros = | 
|  | 375 | std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue)); | 
|  | 376 | return 1 << TrailingZeros; | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | // Reserve space in .bss for copy relocation. | 
|  | 380 | template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { | 
|  | 381 | typedef typename ELFT::uint uintX_t; | 
|  | 382 | typedef typename ELFT::Sym Elf_Sym; | 
|  | 383 |  | 
|  | 384 | // Copy relocation against zero-sized symbol doesn't make sense. | 
|  | 385 | uintX_t SymSize = SS->template getSize<ELFT>(); | 
|  | 386 | if (SymSize == 0) | 
| Petr Hosek | 4071b1b | 2016-08-18 21:55:23 +0000 | [diff] [blame] | 387 | fatal("cannot create a copy relocation for symbol " + SS->getName()); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 388 |  | 
| Rui Ueyama | 424b408 | 2016-06-17 01:18:46 +0000 | [diff] [blame] | 389 | uintX_t Alignment = getAlignment(SS); | 
|  | 390 | uintX_t Off = alignTo(Out<ELFT>::Bss->getSize(), Alignment); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 391 | Out<ELFT>::Bss->setSize(Off + SymSize); | 
| Rui Ueyama | 424b408 | 2016-06-17 01:18:46 +0000 | [diff] [blame] | 392 | Out<ELFT>::Bss->updateAlignment(Alignment); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 393 | uintX_t Shndx = SS->Sym.st_shndx; | 
|  | 394 | uintX_t Value = SS->Sym.st_value; | 
|  | 395 | // Look through the DSO's dynamic symbol table for aliases and create a | 
|  | 396 | // dynamic symbol for each one. This causes the copy relocation to correctly | 
|  | 397 | // interpose any aliases. | 
| Rui Ueyama | 434b561 | 2016-07-17 03:11:46 +0000 | [diff] [blame] | 398 | for (const Elf_Sym &S : SS->file()->getElfSymbols(true)) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 399 | if (S.st_shndx != Shndx || S.st_value != Value) | 
|  | 400 | continue; | 
|  | 401 | auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>( | 
| Rui Ueyama | 434b561 | 2016-07-17 03:11:46 +0000 | [diff] [blame] | 402 | Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable())))); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 403 | if (!Alias) | 
|  | 404 | continue; | 
|  | 405 | Alias->OffsetInBss = Off; | 
|  | 406 | Alias->NeedsCopyOrPltAddr = true; | 
|  | 407 | Alias->symbol()->IsUsedInRegularObj = true; | 
|  | 408 | } | 
|  | 409 | Out<ELFT>::RelaDyn->addReloc( | 
|  | 410 | {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0}); | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | template <class ELFT> | 
| Petr Hosek | 5b4f6c6 | 2016-08-22 19:01:53 +0000 | [diff] [blame] | 414 | static StringRef getSymbolName(const elf::ObjectFile<ELFT> &File, | 
|  | 415 | SymbolBody &Body) { | 
|  | 416 | if (Body.isLocal() && Body.getNameOffset()) | 
|  | 417 | return File.getStringTable().data() + Body.getNameOffset(); | 
|  | 418 | if (!Body.isLocal()) | 
|  | 419 | return Body.getName(); | 
|  | 420 | return ""; | 
| Petr Hosek | 4071b1b | 2016-08-18 21:55:23 +0000 | [diff] [blame] | 421 | } | 
|  | 422 |  | 
|  | 423 | template <class ELFT> | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 424 | static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body, | 
| George Rimar | 5c33b91 | 2016-05-25 14:31:37 +0000 | [diff] [blame] | 425 | bool IsWrite, RelExpr Expr, uint32_t Type, | 
| Rafael Espindola | f2956a3 | 2016-06-17 15:01:50 +0000 | [diff] [blame] | 426 | const uint8_t *Data) { | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 427 | bool Preemptible = isPreemptible(Body, Type); | 
| George Rimar | 5c33b91 | 2016-05-25 14:31:37 +0000 | [diff] [blame] | 428 | if (Body.isGnuIFunc()) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 429 | Expr = toPlt(Expr); | 
| George Rimar | 5c33b91 | 2016-05-25 14:31:37 +0000 | [diff] [blame] | 430 | } else if (!Preemptible) { | 
|  | 431 | if (needsPlt(Expr)) | 
|  | 432 | Expr = fromPlt(Expr); | 
| George Rimar | f10c829 | 2016-06-01 16:45:30 +0000 | [diff] [blame] | 433 | if (Expr == R_GOT_PC) | 
| Rafael Espindola | f2956a3 | 2016-06-17 15:01:50 +0000 | [diff] [blame] | 434 | Expr = Target->adjustRelaxExpr(Type, Data, Expr); | 
| George Rimar | 5c33b91 | 2016-05-25 14:31:37 +0000 | [diff] [blame] | 435 | } | 
| Peter Smith | fb05cd9 | 2016-07-08 16:10:27 +0000 | [diff] [blame] | 436 | Expr = Target->getThunkExpr(Expr, Type, File, Body); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 437 |  | 
|  | 438 | if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body)) | 
|  | 439 | return Expr; | 
|  | 440 |  | 
|  | 441 | // This relocation would require the dynamic linker to write a value to read | 
|  | 442 | // only memory. We can hack around it if we are producing an executable and | 
|  | 443 | // the refered symbol can be preemepted to refer to the executable. | 
|  | 444 | if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { | 
| Petr Hosek | 5b4f6c6 | 2016-08-22 19:01:53 +0000 | [diff] [blame] | 445 | StringRef Name = getSymbolName(File, Body); | 
| George Rimar | 3ed2b08 | 2016-06-10 08:00:01 +0000 | [diff] [blame] | 446 | error("can't create dynamic relocation " + getRelName(Type) + | 
| Petr Hosek | 5b4f6c6 | 2016-08-22 19:01:53 +0000 | [diff] [blame] | 447 | " against " + (Name.empty() ? "readonly segment" : "symbol " + Name)); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 448 | return Expr; | 
|  | 449 | } | 
|  | 450 | if (Body.getVisibility() != STV_DEFAULT) { | 
| Petr Hosek | 4071b1b | 2016-08-18 21:55:23 +0000 | [diff] [blame] | 451 | error("cannot preempt symbol " + Body.getName()); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 452 | return Expr; | 
|  | 453 | } | 
|  | 454 | if (Body.isObject()) { | 
|  | 455 | // Produce a copy relocation. | 
|  | 456 | auto *B = cast<SharedSymbol<ELFT>>(&Body); | 
|  | 457 | if (!B->needsCopy()) | 
|  | 458 | addCopyRelSymbol(B); | 
|  | 459 | return Expr; | 
|  | 460 | } | 
|  | 461 | if (Body.isFunc()) { | 
|  | 462 | // This handles a non PIC program call to function in a shared library. In | 
|  | 463 | // an ideal world, we could just report an error saying the relocation can | 
|  | 464 | // overflow at runtime. In the real world with glibc, crt1.o has a | 
|  | 465 | // R_X86_64_PC32 pointing to libc.so. | 
|  | 466 | // | 
|  | 467 | // The general idea on how to handle such cases is to create a PLT entry and | 
|  | 468 | // use that as the function value. | 
|  | 469 | // | 
|  | 470 | // For the static linking part, we just return a plt expr and everything | 
|  | 471 | // else will use the the PLT entry as the address. | 
|  | 472 | // | 
|  | 473 | // The remaining problem is making sure pointer equality still works. We | 
|  | 474 | // need the help of the dynamic linker for that. We let it know that we have | 
|  | 475 | // a direct reference to a so symbol by creating an undefined symbol with a | 
|  | 476 | // non zero st_value. Seeing that, the dynamic linker resolves the symbol to | 
|  | 477 | // the value of the symbol we created. This is true even for got entries, so | 
|  | 478 | // pointer equality is maintained. To avoid an infinite loop, the only entry | 
|  | 479 | // that points to the real function is a dedicated got entry used by the | 
|  | 480 | // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, | 
|  | 481 | // R_386_JMP_SLOT, etc). | 
|  | 482 | Body.NeedsCopyOrPltAddr = true; | 
|  | 483 | return toPlt(Expr); | 
|  | 484 | } | 
| Petr Hosek | 4071b1b | 2016-08-18 21:55:23 +0000 | [diff] [blame] | 485 | error("symbol " + Body.getName() + " is missing type"); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 486 |  | 
|  | 487 | return Expr; | 
|  | 488 | } | 
|  | 489 |  | 
|  | 490 | template <class ELFT, class RelTy> | 
|  | 491 | static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File, | 
|  | 492 | const uint8_t *SectionData, | 
|  | 493 | const RelTy *End, const RelTy &RI, | 
|  | 494 | RelExpr Expr, SymbolBody &Body) { | 
|  | 495 | typedef typename ELFT::uint uintX_t; | 
|  | 496 |  | 
|  | 497 | uint32_t Type = RI.getType(Config->Mips64EL); | 
|  | 498 | uintX_t Addend = getAddend<ELFT>(RI); | 
|  | 499 | const uint8_t *BufLoc = SectionData + RI.r_offset; | 
|  | 500 | if (!RelTy::IsRela) | 
|  | 501 | Addend += Target->getImplicitAddend(BufLoc, Type); | 
|  | 502 | if (Config->EMachine == EM_MIPS) { | 
|  | 503 | Addend += findMipsPairedAddend<ELFT>(SectionData, BufLoc, Body, &RI, End); | 
|  | 504 | if (Type == R_MIPS_LO16 && Expr == R_PC) | 
|  | 505 | // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp | 
|  | 506 | // symbol. In that case we should use the following formula for | 
|  | 507 | // calculation "AHL + GP - P + 4". Let's add 4 right here. | 
|  | 508 | // For details see p. 4-19 at | 
|  | 509 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | 
|  | 510 | Addend += 4; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 511 | if (Expr == R_GOTREL) { | 
|  | 512 | Addend -= MipsGPOffset; | 
|  | 513 | if (Body.isLocal()) | 
|  | 514 | Addend += File.getMipsGp0(); | 
|  | 515 | } | 
|  | 516 | } | 
|  | 517 | if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC) | 
|  | 518 | Addend += getPPC64TocBase(); | 
|  | 519 | return Addend; | 
|  | 520 | } | 
|  | 521 |  | 
|  | 522 | // The reason we have to do this early scan is as follows | 
|  | 523 | // * To mmap the output file, we need to know the size | 
|  | 524 | // * For that, we need to know how many dynamic relocs we will have. | 
|  | 525 | // It might be possible to avoid this by outputting the file with write: | 
|  | 526 | // * Write the allocated output sections, computing addresses. | 
|  | 527 | // * Apply relocations, recording which ones require a dynamic reloc. | 
|  | 528 | // * Write the dynamic relocations. | 
|  | 529 | // * Write the rest of the file. | 
|  | 530 | // This would have some drawbacks. For example, we would only know if .rela.dyn | 
|  | 531 | // is needed after applying relocations. If it is, it will go after rw and rx | 
|  | 532 | // sections. Given that it is ro, we will need an extra PT_LOAD. This | 
|  | 533 | // complicates things for the dynamic linker and means we would have to reserve | 
|  | 534 | // space for the extra PT_LOAD even if we end up not using it. | 
|  | 535 | template <class ELFT, class RelTy> | 
| Rui Ueyama | 2487f19 | 2016-05-25 03:40:02 +0000 | [diff] [blame] | 536 | static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 537 | typedef typename ELFT::uint uintX_t; | 
|  | 538 |  | 
| George Rimar | db0168d | 2016-06-09 15:17:29 +0000 | [diff] [blame] | 539 | bool IsWrite = C.getSectionHdr()->sh_flags & SHF_WRITE; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 540 |  | 
|  | 541 | auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) { | 
|  | 542 | Out<ELFT>::RelaDyn->addReloc(Reloc); | 
|  | 543 | }; | 
|  | 544 |  | 
|  | 545 | const elf::ObjectFile<ELFT> &File = *C.getFile(); | 
| Rafael Espindola | c7e1e03 | 2016-09-12 13:13:53 +0000 | [diff] [blame] | 546 | ArrayRef<uint8_t> SectionData = C.Data; | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 547 | const uint8_t *Buf = SectionData.begin(); | 
| Rafael Espindola | 5b7a79f | 2016-07-20 11:47:50 +0000 | [diff] [blame] | 548 |  | 
| Rafael Espindola | 3abe3aa | 2016-07-21 21:15:32 +0000 | [diff] [blame] | 549 | ArrayRef<EhSectionPiece> Pieces; | 
|  | 550 | if (auto *Eh = dyn_cast<EhInputSection<ELFT>>(&C)) | 
|  | 551 | Pieces = Eh->Pieces; | 
|  | 552 |  | 
|  | 553 | ArrayRef<EhSectionPiece>::iterator PieceI = Pieces.begin(); | 
|  | 554 | ArrayRef<EhSectionPiece>::iterator PieceE = Pieces.end(); | 
| Rafael Espindola | 5b7a79f | 2016-07-20 11:47:50 +0000 | [diff] [blame] | 555 |  | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 556 | for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) { | 
|  | 557 | const RelTy &RI = *I; | 
|  | 558 | SymbolBody &Body = File.getRelocTargetSym(RI); | 
|  | 559 | uint32_t Type = RI.getType(Config->Mips64EL); | 
|  | 560 |  | 
|  | 561 | RelExpr Expr = Target->getRelExpr(Type, Body); | 
| Rafael Espindola | 678844e | 2016-06-17 15:42:36 +0000 | [diff] [blame] | 562 | bool Preemptible = isPreemptible(Body, Type); | 
|  | 563 | Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf + RI.r_offset); | 
|  | 564 | if (HasError) | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 565 | continue; | 
|  | 566 |  | 
| Rui Ueyama | 809d8e2 | 2016-06-23 04:33:42 +0000 | [diff] [blame] | 567 | // Skip a relocation that points to a dead piece | 
| Rafael Espindola | 5b7a79f | 2016-07-20 11:47:50 +0000 | [diff] [blame] | 568 | // in a eh_frame section. | 
|  | 569 | while (PieceI != PieceE && | 
|  | 570 | (PieceI->InputOff + PieceI->size() <= RI.r_offset)) | 
|  | 571 | ++PieceI; | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 572 |  | 
|  | 573 | // Compute the offset of this section in the output section. We do it here | 
|  | 574 | // to try to compute it only once. | 
|  | 575 | uintX_t Offset; | 
|  | 576 | if (PieceI != PieceE) { | 
|  | 577 | assert(PieceI->InputOff <= RI.r_offset && "Relocation not in any piece"); | 
| George Rimar | e37dde8 | 2016-07-21 15:35:06 +0000 | [diff] [blame] | 578 | if (PieceI->OutputOff == (size_t)-1) | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 579 | continue; | 
|  | 580 | Offset = PieceI->OutputOff + RI.r_offset - PieceI->InputOff; | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 581 | } else { | 
| George Rimar | 3e6833b | 2016-08-19 15:46:28 +0000 | [diff] [blame] | 582 | Offset = RI.r_offset; | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 583 | } | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 584 |  | 
|  | 585 | // This relocation does not require got entry, but it is relative to got and | 
|  | 586 | // needs it to be created. Here we request for that. | 
| Rafael Espindola | 79202c3 | 2016-08-31 23:24:11 +0000 | [diff] [blame] | 587 | if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END || | 
|  | 588 | Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC) | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 589 | Out<ELFT>::Got->HasGotOffRel = true; | 
|  | 590 |  | 
|  | 591 | uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body); | 
|  | 592 |  | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 593 | if (unsigned Processed = | 
|  | 594 | handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 595 | I += (Processed - 1); | 
|  | 596 | continue; | 
|  | 597 | } | 
|  | 598 |  | 
| Rafael Espindola | e37d13b | 2016-06-02 19:49:53 +0000 | [diff] [blame] | 599 | // Ignore "hint" relocation because it is for optional code optimization. | 
|  | 600 | if (Expr == R_HINT) | 
|  | 601 | continue; | 
|  | 602 |  | 
| Peter Smith | fb05cd9 | 2016-07-08 16:10:27 +0000 | [diff] [blame] | 603 | if (needsPlt(Expr) || Expr == R_THUNK_ABS || Expr == R_THUNK_PC || | 
|  | 604 | Expr == R_THUNK_PLT_PC || refersToGotEntry(Expr) || | 
| Simon Atanasyan | 9a9a316 | 2016-05-28 04:49:57 +0000 | [diff] [blame] | 605 | !isPreemptible(Body, Type)) { | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 606 | // If the relocation points to something in the file, we can process it. | 
|  | 607 | bool Constant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body); | 
|  | 608 |  | 
|  | 609 | // If the output being produced is position independent, the final value | 
|  | 610 | // is still not known. In that case we still need some help from the | 
|  | 611 | // dynamic linker. We can however do better than just copying the incoming | 
|  | 612 | // relocation. We can process some of it and and just ask the dynamic | 
|  | 613 | // linker to add the load address. | 
|  | 614 | if (!Constant) | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 615 | AddDyn({Target->RelativeRel, &C, Offset, true, &Body, Addend}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 616 |  | 
|  | 617 | // If the produced value is a constant, we just remember to write it | 
|  | 618 | // when outputting this section. We also have to do it if the format | 
|  | 619 | // uses Elf_Rel, since in that case the written value is the addend. | 
|  | 620 | if (Constant || !RelTy::IsRela) | 
| Rafael Espindola | 664c652 | 2016-09-07 20:37:34 +0000 | [diff] [blame] | 621 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 622 | } else { | 
|  | 623 | // We don't know anything about the finaly symbol. Just ask the dynamic | 
|  | 624 | // linker to handle the relocation for us. | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 625 | AddDyn({Target->getDynRel(Type), &C, Offset, false, &Body, Addend}); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 626 | // MIPS ABI turns using of GOT and dynamic relocations inside out. | 
|  | 627 | // While regular ABI uses dynamic relocations to fill up GOT entries | 
|  | 628 | // MIPS ABI requires dynamic linker to fills up GOT entries using | 
|  | 629 | // specially sorted dynamic symbol table. This affects even dynamic | 
|  | 630 | // relocations against symbols which do not require GOT entries | 
|  | 631 | // creation explicitly, i.e. do not have any GOT-relocations. So if | 
|  | 632 | // a preemptible symbol has a dynamic relocation we anyway have | 
|  | 633 | // to create a GOT entry for it. | 
|  | 634 | // If a non-preemptible symbol has a dynamic relocation against it, | 
|  | 635 | // dynamic linker takes it st_value, adds offset and writes down | 
|  | 636 | // result of the dynamic relocation. In case of preemptible symbol | 
|  | 637 | // dynamic linker performs symbol resolution, writes the symbol value | 
|  | 638 | // to the GOT entry and reads the GOT entry when it needs to perform | 
|  | 639 | // a dynamic relocation. | 
|  | 640 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 641 | if (Config->EMachine == EM_MIPS) | 
|  | 642 | Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 643 | continue; | 
|  | 644 | } | 
|  | 645 |  | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 646 | // At this point we are done with the relocated position. Some relocations | 
|  | 647 | // also require us to create a got or plt entry. | 
|  | 648 |  | 
|  | 649 | // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol. | 
|  | 650 | if (needsPlt(Expr)) { | 
|  | 651 | if (Body.isInPlt()) | 
|  | 652 | continue; | 
|  | 653 | Out<ELFT>::Plt->addEntry(Body); | 
|  | 654 |  | 
|  | 655 | uint32_t Rel; | 
|  | 656 | if (Body.isGnuIFunc() && !Preemptible) | 
|  | 657 | Rel = Target->IRelativeRel; | 
|  | 658 | else | 
|  | 659 | Rel = Target->PltRel; | 
|  | 660 |  | 
|  | 661 | Out<ELFT>::GotPlt->addEntry(Body); | 
|  | 662 | Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt, | 
|  | 663 | Body.getGotPltOffset<ELFT>(), !Preemptible, | 
|  | 664 | &Body, 0}); | 
|  | 665 | continue; | 
|  | 666 | } | 
|  | 667 |  | 
|  | 668 | if (refersToGotEntry(Expr)) { | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 669 | if (Config->EMachine == EM_MIPS) { | 
| Simon Atanasyan | af52f6a | 2016-09-08 09:07:12 +0000 | [diff] [blame] | 670 | // MIPS ABI has special rules to process GOT entries and doesn't | 
|  | 671 | // require relocation entries for them. A special case is TLS | 
|  | 672 | // relocations. In that case dynamic loader applies dynamic | 
|  | 673 | // relocations to initialize TLS GOT entries. | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 674 | // See "Global Offset Table" in Chapter 5 in the following document | 
|  | 675 | // for detailed description: | 
|  | 676 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 677 | Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr); | 
| Simon Atanasyan | 919a58c | 2016-09-08 09:07:19 +0000 | [diff] [blame] | 678 | if (Body.isTls() && Body.isPreemptible()) | 
| Simon Atanasyan | 002e244 | 2016-06-23 15:26:31 +0000 | [diff] [blame] | 679 | AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), | 
| Simon Atanasyan | 919a58c | 2016-09-08 09:07:19 +0000 | [diff] [blame] | 680 | false, &Body, 0}); | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 681 | continue; | 
|  | 682 | } | 
|  | 683 |  | 
|  | 684 | if (Body.isInGot()) | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 685 | continue; | 
|  | 686 |  | 
| Simon Atanasyan | 4132511 | 2016-06-19 21:39:37 +0000 | [diff] [blame] | 687 | Out<ELFT>::Got->addEntry(Body); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 688 | if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) { | 
|  | 689 | uint32_t DynType; | 
|  | 690 | if (Body.isTls()) | 
|  | 691 | DynType = Target->TlsGotRel; | 
|  | 692 | else if (Preemptible) | 
|  | 693 | DynType = Target->GotRel; | 
|  | 694 | else | 
|  | 695 | DynType = Target->RelativeRel; | 
|  | 696 | AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), | 
|  | 697 | !Preemptible, &Body, 0}); | 
|  | 698 | } | 
|  | 699 | continue; | 
|  | 700 | } | 
|  | 701 | } | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 702 | } | 
|  | 703 |  | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 704 | template <class ELFT> | 
|  | 705 | void scanRelocations(InputSectionBase<ELFT> &S, | 
|  | 706 | const typename ELFT::Shdr &RelSec) { | 
|  | 707 | ELFFile<ELFT> &EObj = S.getFile()->getObj(); | 
|  | 708 | if (RelSec.sh_type == SHT_RELA) | 
|  | 709 | scanRelocs(S, EObj.relas(&RelSec)); | 
|  | 710 | else | 
|  | 711 | scanRelocs(S, EObj.rels(&RelSec)); | 
|  | 712 | } | 
|  | 713 |  | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 714 | template <class ELFT, class RelTy> | 
|  | 715 | static void createThunks(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) { | 
|  | 716 | const elf::ObjectFile<ELFT> &File = *C.getFile(); | 
|  | 717 | for (const RelTy &Rel : Rels) { | 
|  | 718 | SymbolBody &Body = File.getRelocTargetSym(Rel); | 
|  | 719 | uint32_t Type = Rel.getType(Config->Mips64EL); | 
|  | 720 | RelExpr Expr = Target->getRelExpr(Type, Body); | 
|  | 721 | if (!isPreemptible(Body, Type) && needsPlt(Expr)) | 
|  | 722 | Expr = fromPlt(Expr); | 
|  | 723 | Expr = Target->getThunkExpr(Expr, Type, File, Body); | 
|  | 724 | // Some targets might require creation of thunks for relocations. | 
|  | 725 | // Now we support only MIPS which requires LA25 thunk to call PIC | 
|  | 726 | // code from non-PIC one, and ARM which requires interworking. | 
|  | 727 | if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) { | 
|  | 728 | auto *Sec = cast<InputSection<ELFT>>(&C); | 
|  | 729 | addThunk<ELFT>(Type, Body, *Sec); | 
|  | 730 | } | 
|  | 731 | } | 
|  | 732 | } | 
|  | 733 |  | 
|  | 734 | template <class ELFT> | 
|  | 735 | void createThunks(InputSectionBase<ELFT> &S, | 
|  | 736 | const typename ELFT::Shdr &RelSec) { | 
|  | 737 | ELFFile<ELFT> &EObj = S.getFile()->getObj(); | 
|  | 738 | if (RelSec.sh_type == SHT_RELA) | 
|  | 739 | createThunks(S, EObj.relas(&RelSec)); | 
|  | 740 | else | 
|  | 741 | createThunks(S, EObj.rels(&RelSec)); | 
|  | 742 | } | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 743 |  | 
|  | 744 | template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &, | 
|  | 745 | const ELF32LE::Shdr &); | 
|  | 746 | template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &, | 
|  | 747 | const ELF32BE::Shdr &); | 
|  | 748 | template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &, | 
|  | 749 | const ELF64LE::Shdr &); | 
|  | 750 | template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &, | 
|  | 751 | const ELF64BE::Shdr &); | 
| Rafael Espindola | 0f7ceda | 2016-07-20 17:58:07 +0000 | [diff] [blame] | 752 |  | 
|  | 753 | template void createThunks<ELF32LE>(InputSectionBase<ELF32LE> &, | 
|  | 754 | const ELF32LE::Shdr &); | 
|  | 755 | template void createThunks<ELF32BE>(InputSectionBase<ELF32BE> &, | 
|  | 756 | const ELF32BE::Shdr &); | 
|  | 757 | template void createThunks<ELF64LE>(InputSectionBase<ELF64LE> &, | 
|  | 758 | const ELF64LE::Shdr &); | 
|  | 759 | template void createThunks<ELF64BE>(InputSectionBase<ELF64BE> &, | 
|  | 760 | const ELF64BE::Shdr &); | 
| Rui Ueyama | 0fcdc73 | 2016-05-24 20:24:43 +0000 | [diff] [blame] | 761 | } | 
|  | 762 | } |