blob: cd9ecb2bedd0807985131ccea3e4e34bae064d52 [file] [log] [blame]
Rafael Espindola01205f72015-09-22 18:19:46 +00001//===- Target.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//===----------------------------------------------------------------------===//
Rui Ueyama34f29242015-10-13 19:51:57 +00009//
10// Machine-specific stuff, such as applying relocations, creation of
11// GOT or PLT entries, etc., are is handled in this file.
12//
13//===----------------------------------------------------------------------===//
Rafael Espindola01205f72015-09-22 18:19:46 +000014
15#include "Target.h"
Rafael Espindolac4010882015-09-22 20:54:08 +000016#include "Error.h"
Rui Ueyamaaf21d922015-10-08 20:06:07 +000017#include "OutputSections.h"
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000018#include "Symbols.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000019
20#include "llvm/ADT/ArrayRef.h"
Rafael Espindolac4010882015-09-22 20:54:08 +000021#include "llvm/Object/ELF.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000022#include "llvm/Support/Endian.h"
23#include "llvm/Support/ELF.h"
24
25using namespace llvm;
Rafael Espindolac4010882015-09-22 20:54:08 +000026using namespace llvm::object;
Rafael Espindola0872ea32015-09-24 14:16:02 +000027using namespace llvm::support::endian;
Rafael Espindola01205f72015-09-22 18:19:46 +000028using namespace llvm::ELF;
29
30namespace lld {
31namespace elf2 {
32
33std::unique_ptr<TargetInfo> Target;
34
Rui Ueyama91004392015-10-13 16:08:15 +000035TargetInfo *createTarget() {
36 switch (Config->EMachine) {
37 case EM_386:
38 return new X86TargetInfo();
39 case EM_AARCH64:
40 return new AArch64TargetInfo();
41 case EM_MIPS:
42 return new MipsTargetInfo();
43 case EM_PPC:
44 return new PPCTargetInfo();
45 case EM_PPC64:
46 return new PPC64TargetInfo();
47 case EM_X86_64:
48 return new X86_64TargetInfo();
49 }
50 error("Unknown target machine");
51}
52
Rafael Espindola01205f72015-09-22 18:19:46 +000053TargetInfo::~TargetInfo() {}
54
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000055bool TargetInfo::relocPointsToGot(uint32_t Type) const { return false; }
56
Rafael Espindolaae244002015-10-05 19:30:12 +000057bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
58
Rafael Espindola7f074422015-09-22 21:35:51 +000059X86TargetInfo::X86TargetInfo() {
60 PCRelReloc = R_386_PC32;
61 GotReloc = R_386_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +000062 GotRefReloc = R_386_GOT32;
Rafael Espindola7f074422015-09-22 21:35:51 +000063}
Rafael Espindola01205f72015-09-22 18:19:46 +000064
65void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac58656c2015-10-13 16:59:30 +000066 uint64_t PltEntryAddr) const {
67 // jmpl *val; nop; nop
68 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
Rui Ueyama1500a902015-09-29 23:00:47 +000069 memcpy(Buf, Inst, sizeof(Inst));
Rui Ueyamac58656c2015-10-13 16:59:30 +000070 assert(isUInt<32>(GotEntryAddr));
71 write32le(Buf + 2, GotEntryAddr);
Rafael Espindola01205f72015-09-22 18:19:46 +000072}
73
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000074bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +000075 return Type == R_386_GOT32 || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +000076}
77
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000078bool X86TargetInfo::relocPointsToGot(uint32_t Type) const {
79 return Type == R_386_GOTPC;
80}
81
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000082bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
George Rimar730c2782015-10-07 18:46:13 +000083 return Type == R_386_PLT32 || (Type == R_386_PC32 && S.isShared());
Rafael Espindola01205f72015-09-22 18:19:46 +000084}
85
Rui Ueyama87bc41b2015-10-06 18:54:43 +000086static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); }
Rui Ueyama87bc41b2015-10-06 18:54:43 +000087static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); }
Rafael Espindola0872ea32015-09-24 14:16:02 +000088
Hal Finkel87bbd5f2015-10-12 21:19:18 +000089void X86TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
90 uint32_t Type, uint64_t BaseAddr,
91 uint64_t SymVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +000092 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
93 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
94
95 uint32_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +000096 uint8_t *Loc = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +000097 switch (Type) {
Rafael Espindola8acb95c2015-09-29 14:42:37 +000098 case R_386_GOT32:
Rui Ueyamaaf21d922015-10-08 20:06:07 +000099 add32le(Loc, SymVA - Out<ELF32LE>::Got->getVA());
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000100 break;
Rafael Espindolac4010882015-09-22 20:54:08 +0000101 case R_386_PC32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000102 add32le(Loc, SymVA - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000103 break;
104 case R_386_32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000105 add32le(Loc, SymVA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000106 break;
107 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000108 error("unrecognized reloc " + Twine(Type));
Rafael Espindolac4010882015-09-22 20:54:08 +0000109 }
110}
111
Rafael Espindola7f074422015-09-22 21:35:51 +0000112X86_64TargetInfo::X86_64TargetInfo() {
113 PCRelReloc = R_X86_64_PC32;
114 GotReloc = R_X86_64_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000115 GotRefReloc = R_X86_64_PC32;
Rafael Espindolaae244002015-10-05 19:30:12 +0000116 RelativeReloc = R_X86_64_RELATIVE;
Rafael Espindola7f074422015-09-22 21:35:51 +0000117}
Rafael Espindola01205f72015-09-22 18:19:46 +0000118
119void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac58656c2015-10-13 16:59:30 +0000120 uint64_t PltEntryAddr) const {
121 // jmpq *val(%rip); nop; nop
122 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
Rui Ueyama1500a902015-09-29 23:00:47 +0000123 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +0000124
Rui Ueyamac58656c2015-10-13 16:59:30 +0000125 uint64_t NextPC = PltEntryAddr + 6;
126 int64_t Delta = GotEntryAddr - NextPC;
127 assert(isInt<32>(Delta));
128 write32le(Buf + 2, Delta);
Rafael Espindola01205f72015-09-22 18:19:46 +0000129}
130
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000131bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +0000132 return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +0000133}
134
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000135bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Rafael Espindola01205f72015-09-22 18:19:46 +0000136 switch (Type) {
137 default:
138 return false;
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000139 case R_X86_64_PC32:
140 // This relocation is defined to have a value of (S + A - P).
Rafael Espindola3c412e12015-09-30 12:30:58 +0000141 // The problems start when a non PIC program calls a function in a shared
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000142 // library.
Rafael Espindola9a0db7c2015-09-29 23:23:53 +0000143 // In an ideal world, we could just report an error saying the relocation
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000144 // can overflow at runtime.
Rafael Espindola3c412e12015-09-30 12:30:58 +0000145 // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
146 // libc.so.
147 //
148 // The general idea on how to handle such cases is to create a PLT entry
149 // and use that as the function value.
150 //
151 // For the static linking part, we just return true and everything else
152 // will use the the PLT entry as the address.
153 //
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000154 // The remaining (unimplemented) problem is making sure pointer equality
Rafael Espindola3c412e12015-09-30 12:30:58 +0000155 // still works. We need the help of the dynamic linker for that. We
156 // let it know that we have a direct reference to a so symbol by creating
157 // an undefined symbol with a non zero st_value. Seeing that, the
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000158 // dynamic linker resolves the symbol to the value of the symbol we created.
159 // This is true even for got entries, so pointer equality is maintained.
160 // To avoid an infinite loop, the only entry that points to the
Rafael Espindola3c412e12015-09-30 12:30:58 +0000161 // real function is a dedicated got entry used by the plt. That is
162 // identified by special relocation types (R_X86_64_JUMP_SLOT,
163 // R_386_JMP_SLOT, etc).
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000164 return S.isShared();
Rafael Espindola01205f72015-09-22 18:19:46 +0000165 case R_X86_64_PLT32:
166 return true;
167 }
168}
Rafael Espindolac4010882015-09-22 20:54:08 +0000169
Rafael Espindolaae244002015-10-05 19:30:12 +0000170bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
171 switch (Type) {
172 default:
173 return false;
174 case R_X86_64_PC64:
175 case R_X86_64_PC32:
176 case R_X86_64_PC16:
177 case R_X86_64_PC8:
178 return true;
179 }
180}
181
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000182void X86_64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
183 const void *RelP, uint32_t Type,
184 uint64_t BaseAddr, uint64_t SymVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +0000185 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
186 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
187
188 uint64_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000189 uint8_t *Loc = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +0000190 switch (Type) {
191 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000192 case R_X86_64_GOTPCREL:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000193 write32le(Loc, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000194 break;
195 case R_X86_64_64:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000196 write64le(Loc, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000197 break;
198 case R_X86_64_32: {
199 case R_X86_64_32S:
200 uint64_t VA = SymVA + Rel.r_addend;
201 if (Type == R_X86_64_32 && !isUInt<32>(VA))
202 error("R_X86_64_32 out of range");
203 else if (!isInt<32>(VA))
204 error("R_X86_64_32S out of range");
205
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000206 write32le(Loc, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000207 break;
208 }
209 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000210 error("unrecognized reloc " + Twine(Type));
Rafael Espindolac4010882015-09-22 20:54:08 +0000211 }
212}
213
Hal Finkel3c8cc672015-10-12 20:56:18 +0000214// Relocation masks following the #lo(value), #hi(value), #ha(value),
215// #higher(value), #highera(value), #highest(value), and #highesta(value)
216// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
217// document.
218
219static uint16_t applyPPCLo(uint64_t V) { return V & 0xffff; }
220
221static uint16_t applyPPCHi(uint64_t V) { return (V >> 16) & 0xffff; }
222
223static uint16_t applyPPCHa(uint64_t V) { return ((V + 0x8000) >> 16) & 0xffff; }
224
225static uint16_t applyPPCHigher(uint64_t V) { return (V >> 32) & 0xffff; }
226
227static uint16_t applyPPCHighera(uint64_t V) {
228 return ((V + 0x8000) >> 32) & 0xffff;
229}
230
231static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
232
233static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
234
Rafael Espindolac4010882015-09-22 20:54:08 +0000235PPC64TargetInfo::PPC64TargetInfo() {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000236 PCRelReloc = R_PPC64_REL24;
237 GotReloc = R_PPC64_GLOB_DAT;
238 GotRefReloc = R_PPC64_REL64;
Hal Finkelbe0823d2015-10-12 20:58:52 +0000239 RelativeReloc = R_PPC64_RELATIVE;
Hal Finkel6c2a3b82015-10-08 21:51:31 +0000240 PltEntrySize = 32;
Hal Finkelc848b322015-10-12 19:34:29 +0000241
242 // We need 64K pages (at least under glibc/Linux, the loader won't
243 // set different permissions on a finer granularity than that).
Hal Finkele3c26262015-10-08 22:23:54 +0000244 PageSize = 65536;
Rafael Espindolac4010882015-09-22 20:54:08 +0000245}
Hal Finkel3c8cc672015-10-12 20:56:18 +0000246
247static uint64_t getPPC64TocBase() {
248 // The TOC consists of sections .got, .toc, .tocbss, .plt in that
249 // order. The TOC starts where the first of these sections starts.
250
251 // FIXME: This obviously does not do the right thing when there is no .got
252 // section, but there is a .toc or .tocbss section.
253 uint64_t TocVA = Out<ELF64BE>::Got->getVA();
254 if (!TocVA)
255 TocVA = Out<ELF64BE>::Plt->getVA();
256
257 // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
258 // thus permitting a full 64 Kbytes segment. Note that the glibc startup
259 // code (crt1.o) assumes that you can get from the TOC base to the
260 // start of the .toc section with only a single (signed) 16-bit relocation.
261 return TocVA + 0x8000;
262}
263
Rafael Espindolac4010882015-09-22 20:54:08 +0000264void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac58656c2015-10-13 16:59:30 +0000265 uint64_t PltEntryAddr) const {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000266 uint64_t Off = GotEntryAddr - getPPC64TocBase();
267
268 // FIXME: What we should do, in theory, is get the offset of the function
269 // descriptor in the .opd section, and use that as the offset from %r2 (the
270 // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
271 // be a pointer to the function descriptor in the .opd section. Using
272 // this scheme is simpler, but requires an extra indirection per PLT dispatch.
273
Hal Finkelfa92f682015-10-13 21:47:34 +0000274 write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
Hal Finkel3c8cc672015-10-12 20:56:18 +0000275 write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
276 write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
277 write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
278 write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
279 write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
280 write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
281 write32be(Buf + 28, 0x4e800420); // bctr
282}
283
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000284bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000285 if (relocNeedsPlt(Type, S))
286 return true;
287
288 switch (Type) {
289 default: return false;
290 case R_PPC64_GOT16:
291 case R_PPC64_GOT16_LO:
292 case R_PPC64_GOT16_HI:
293 case R_PPC64_GOT16_HA:
294 case R_PPC64_GOT16_DS:
295 case R_PPC64_GOT16_LO_DS:
296 return true;
297 }
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000298}
Hal Finkel3c8cc672015-10-12 20:56:18 +0000299
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000300bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000301 if (Type != R_PPC64_REL24)
302 return false;
303
304 // These are function calls that need to be redirected through a PLT stub.
305 return S.isShared() || (S.isUndefined() && S.isWeak());
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000306}
Hal Finkel3c8cc672015-10-12 20:56:18 +0000307
Hal Finkelbe0823d2015-10-12 20:58:52 +0000308bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
309 switch (Type) {
310 default:
311 return false;
312 case R_PPC64_REL24:
313 case R_PPC64_REL14:
314 case R_PPC64_REL14_BRTAKEN:
315 case R_PPC64_REL14_BRNTAKEN:
316 case R_PPC64_REL32:
317 case R_PPC64_REL64:
318 return true;
319 }
320}
321
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000322void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
323 const void *RelP, uint32_t Type,
Rui Ueyamaaf21d922015-10-08 20:06:07 +0000324 uint64_t BaseAddr, uint64_t SymVA) const {
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000325 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
326 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
327
Hal Finkel3c8cc672015-10-12 20:56:18 +0000328 uint8_t *L = Buf + Rel.r_offset;
329 uint64_t S = SymVA;
330 int64_t A = Rel.r_addend;
331 uint64_t P = BaseAddr + Rel.r_offset;
332 uint64_t TB = getPPC64TocBase();
333
334 if (Type == R_PPC64_TOC) {
335 write64be(L, TB);
336 return;
337 }
338
339 // For a TOC-relative relocation, adjust the addend and proceed in terms of
340 // the corresponding ADDR16 relocation type.
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000341 switch (Type) {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000342 case R_PPC64_TOC16: Type = R_PPC64_ADDR16; A -= TB; break;
343 case R_PPC64_TOC16_DS: Type = R_PPC64_ADDR16_DS; A -= TB; break;
344 case R_PPC64_TOC16_LO: Type = R_PPC64_ADDR16_LO; A -= TB; break;
345 case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; A -= TB; break;
346 case R_PPC64_TOC16_HI: Type = R_PPC64_ADDR16_HI; A -= TB; break;
347 case R_PPC64_TOC16_HA: Type = R_PPC64_ADDR16_HA; A -= TB; break;
348 default: break;
349 }
350
351 uint64_t R = S + A;
352
353 switch (Type) {
354 case R_PPC64_ADDR16:
355 write16be(L, applyPPCLo(R));
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000356 break;
Hal Finkel3c8cc672015-10-12 20:56:18 +0000357 case R_PPC64_ADDR16_DS:
358 if (!isInt<16>(R))
359 error("Relocation R_PPC64_ADDR16_DS overflow");
360 write16be(L, (read16be(L) & 3) | (R & ~3));
361 break;
362 case R_PPC64_ADDR16_LO:
363 write16be(L, applyPPCLo(R));
364 break;
365 case R_PPC64_ADDR16_LO_DS:
366 write16be(L, (read16be(L) & 3) | (applyPPCLo(R) & ~3));
367 break;
368 case R_PPC64_ADDR16_HI:
369 write16be(L, applyPPCHi(R));
370 break;
371 case R_PPC64_ADDR16_HA:
372 write16be(L, applyPPCHa(R));
373 break;
374 case R_PPC64_ADDR16_HIGHER:
375 write16be(L, applyPPCHigher(R));
376 break;
377 case R_PPC64_ADDR16_HIGHERA:
378 write16be(L, applyPPCHighera(R));
379 break;
380 case R_PPC64_ADDR16_HIGHEST:
381 write16be(L, applyPPCHighest(R));
382 break;
383 case R_PPC64_ADDR16_HIGHESTA:
384 write16be(L, applyPPCHighesta(R));
385 break;
386 case R_PPC64_ADDR14: {
387 if ((R & 3) != 0)
388 error("Improper alignment for relocation R_PPC64_ADDR14");
389
390 // Preserve the AA/LK bits in the branch instruction
391 uint8_t AALK = L[3];
392 write16be(L + 2, (AALK & 3) | (R & 0xfffc));
393 break;
394 }
395 case R_PPC64_REL16_LO:
396 write16be(L, applyPPCLo(R - P));
397 break;
398 case R_PPC64_REL16_HI:
399 write16be(L, applyPPCHi(R - P));
400 break;
401 case R_PPC64_REL16_HA:
402 write16be(L, applyPPCHa(R - P));
403 break;
404 case R_PPC64_ADDR32:
405 if (!isInt<32>(R))
406 error("Relocation R_PPC64_ADDR32 overflow");
407 write32be(L, R);
408 break;
409 case R_PPC64_REL24: {
Hal Finkeldaedc122015-10-12 23:16:53 +0000410 uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
411 uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
Hal Finkel4e961dd2015-10-13 22:54:24 +0000412 bool InPlt = PltStart <= R && R < PltEnd;
Hal Finkeldaedc122015-10-12 23:16:53 +0000413
414 if (!InPlt && Out<ELF64BE>::Opd) {
415 // If this is a local call, and we currently have the address of a
416 // function-descriptor, get the underlying code address instead.
417 uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
418 uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
Hal Finkel4e961dd2015-10-13 22:54:24 +0000419 bool InOpd = OpdStart <= R && R < OpdEnd;
Hal Finkeldaedc122015-10-12 23:16:53 +0000420
421 if (InOpd)
Hal Finkel4e961dd2015-10-13 22:54:24 +0000422 R = read64be(&Out<ELF64BE>::OpdBuf[R - OpdStart]);
Hal Finkeldaedc122015-10-12 23:16:53 +0000423 }
424
Hal Finkel3c8cc672015-10-12 20:56:18 +0000425 uint32_t Mask = 0x03FFFFFC;
426 if (!isInt<24>(R - P))
427 error("Relocation R_PPC64_REL24 overflow");
428 write32be(L, (read32be(L) & ~Mask) | ((R - P) & Mask));
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000429
Hal Finkel515ed442015-10-13 20:31:33 +0000430 if (InPlt && L + 8 <= BufEnd &&
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000431 read32be(L + 4) == 0x60000000 /* nop */)
432 write32be(L + 4, 0xe8410028); // ld %r2, 40(%r1)
Hal Finkel3c8cc672015-10-12 20:56:18 +0000433 break;
434 }
435 case R_PPC64_REL32:
436 if (!isInt<32>(R - P))
437 error("Relocation R_PPC64_REL32 overflow");
438 write32be(L, R - P);
439 break;
440 case R_PPC64_REL64:
441 write64be(L, R - P);
442 break;
443 case R_PPC64_ADDR64:
444 write64be(L, R);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000445 break;
446 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000447 error("unrecognized reloc " + Twine(Type));
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000448 }
449}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000450
451PPCTargetInfo::PPCTargetInfo() {
452 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000453 // GotReloc = FIXME
Hal Finkele3c26262015-10-08 22:23:54 +0000454 PageSize = 65536;
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000455}
456void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac58656c2015-10-13 16:59:30 +0000457 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000458bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
459 return false;
460}
461bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
462 return false;
463}
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000464void PPCTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
465 const void *RelP, uint32_t Type,
Rui Ueyamaaf21d922015-10-08 20:06:07 +0000466 uint64_t BaseAddr, uint64_t SymVA) const {}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000467
Davide Italianocde93362015-09-26 00:32:04 +0000468AArch64TargetInfo::AArch64TargetInfo() {
469 // PCRelReloc = FIXME
470 // GotReloc = FIXME
471}
472void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac58656c2015-10-13 16:59:30 +0000473 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000474bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
475 const SymbolBody &S) const {
476 return false;
477}
478bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
479 const SymbolBody &S) const {
480 return false;
481}
Davide Italiano1d750a62015-09-27 08:45:38 +0000482
Davide Italianoef4be6b2015-10-06 19:01:32 +0000483static void updateAArch64Adr(uint8_t *L, uint64_t Imm) {
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000484 uint32_t ImmLo = (Imm & 0x3) << 29;
485 uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
486 uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000487 write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000488}
489
Davide Italiano318ca222015-10-02 22:13:51 +0000490// Page(Expr) is the page address of the expression Expr, defined
491// as (Expr & ~0xFFF). (This applies even if the machine page size
Davide Italianod9b5be42015-10-02 22:17:09 +0000492// supported by the platform has a different value.)
Davide Italianoef4be6b2015-10-06 19:01:32 +0000493static uint64_t getAArch64Page(uint64_t Expr) {
Davide Italiano318ca222015-10-02 22:13:51 +0000494 return Expr & (~static_cast<uint64_t>(0xFFF));
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000495}
496
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000497void AArch64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
498 const void *RelP, uint32_t Type,
499 uint64_t BaseAddr, uint64_t SymVA) const {
Davide Italiano1d750a62015-09-27 08:45:38 +0000500 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
501 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
502
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000503 uint8_t *L = Buf + Rel.r_offset;
Davide Italiano1d750a62015-09-27 08:45:38 +0000504 uint64_t S = SymVA;
505 int64_t A = Rel.r_addend;
506 uint64_t P = BaseAddr + Rel.r_offset;
507 switch (Type) {
Davide Italianodf88f962015-10-04 00:59:16 +0000508 case R_AARCH64_ABS16:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000509 if (!isInt<16>(S + A))
510 error("Relocation R_AARCH64_ABS16 out of range");
Davide Italiano06d84322015-10-07 22:10:02 +0000511 write16le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000512 break;
513 case R_AARCH64_ABS32:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000514 if (!isInt<32>(S + A))
515 error("Relocation R_AARCH64_ABS32 out of range");
Davide Italiano06d84322015-10-07 22:10:02 +0000516 write32le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000517 break;
518 case R_AARCH64_ABS64:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000519 // No overflow check needed.
Davide Italiano06d84322015-10-07 22:10:02 +0000520 write64le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000521 break;
Davide Italiano0b6974b2015-10-03 19:56:07 +0000522 case R_AARCH64_ADD_ABS_LO12_NC:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000523 // No overflow check needed.
524 or32le(L, ((S + A) & 0xFFF) << 10);
Davide Italiano0b6974b2015-10-03 19:56:07 +0000525 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000526 case R_AARCH64_ADR_PREL_LO21: {
527 uint64_t X = S + A - P;
528 if (!isInt<21>(X))
529 error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
530 updateAArch64Adr(L, X & 0x1FFFFF);
Davide Italiano1d750a62015-09-27 08:45:38 +0000531 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000532 }
533 case R_AARCH64_ADR_PREL_PG_HI21: {
534 uint64_t X = getAArch64Page(S + A) - getAArch64Page(P);
535 if (!isInt<33>(X))
536 error("Relocation R_AARCH64_ADR_PREL_PG_HI21 out of range");
537 updateAArch64Adr(L, (X >> 12) & 0x1FFFFF); // X[32:12]
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000538 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000539 }
Davide Italiano1d750a62015-09-27 08:45:38 +0000540 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000541 error("unrecognized reloc " + Twine(Type));
Davide Italiano1d750a62015-09-27 08:45:38 +0000542 }
543}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000544
545MipsTargetInfo::MipsTargetInfo() {
546 // PCRelReloc = FIXME
547 // GotReloc = FIXME
Hal Finkele3c26262015-10-08 22:23:54 +0000548 PageSize = 65536;
Simon Atanasyan49829a12015-09-29 05:34:03 +0000549}
550
551void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac58656c2015-10-13 16:59:30 +0000552 uint64_t PltEntryAddr) const {}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000553
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000554bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
555 return false;
556}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000557
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000558bool MipsTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
559 return false;
560}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000561
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000562void MipsTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
563 const void *RelP, uint32_t Type,
Simon Atanasyan3b732ac2015-10-12 15:10:02 +0000564 uint64_t BaseAddr, uint64_t SymVA) const {
565 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
566 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
567
568 switch (Type) {
569 case R_MIPS_32:
570 add32le(Buf + Rel.r_offset, SymVA);
571 break;
572 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000573 error("unrecognized reloc " + Twine(Type));
Simon Atanasyan3b732ac2015-10-12 15:10:02 +0000574 }
575}
Rafael Espindola01205f72015-09-22 18:19:46 +0000576}
577}