blob: 08d3a7b41d19ad750a4777bdf1b34450c153b578 [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//===----------------------------------------------------------------------===//
9
10#include "Target.h"
Rafael Espindolac4010882015-09-22 20:54:08 +000011#include "Error.h"
Rui Ueyamaaf21d922015-10-08 20:06:07 +000012#include "OutputSections.h"
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000013#include "Symbols.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000014
15#include "llvm/ADT/ArrayRef.h"
Rafael Espindolac4010882015-09-22 20:54:08 +000016#include "llvm/Object/ELF.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000017#include "llvm/Support/Endian.h"
18#include "llvm/Support/ELF.h"
19
20using namespace llvm;
Rafael Espindolac4010882015-09-22 20:54:08 +000021using namespace llvm::object;
Rafael Espindola0872ea32015-09-24 14:16:02 +000022using namespace llvm::support::endian;
Rafael Espindola01205f72015-09-22 18:19:46 +000023using namespace llvm::ELF;
24
25namespace lld {
26namespace elf2 {
27
28std::unique_ptr<TargetInfo> Target;
29
Rui Ueyama91004392015-10-13 16:08:15 +000030TargetInfo *createTarget() {
31 switch (Config->EMachine) {
32 case EM_386:
33 return new X86TargetInfo();
34 case EM_AARCH64:
35 return new AArch64TargetInfo();
36 case EM_MIPS:
37 return new MipsTargetInfo();
38 case EM_PPC:
39 return new PPCTargetInfo();
40 case EM_PPC64:
41 return new PPC64TargetInfo();
42 case EM_X86_64:
43 return new X86_64TargetInfo();
44 }
45 error("Unknown target machine");
46}
47
Rafael Espindola01205f72015-09-22 18:19:46 +000048TargetInfo::~TargetInfo() {}
49
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000050bool TargetInfo::relocPointsToGot(uint32_t Type) const { return false; }
51
Rafael Espindolaae244002015-10-05 19:30:12 +000052bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
53
Rafael Espindola7f074422015-09-22 21:35:51 +000054X86TargetInfo::X86TargetInfo() {
55 PCRelReloc = R_386_PC32;
56 GotReloc = R_386_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +000057 GotRefReloc = R_386_GOT32;
George Rimar9fd8fcb2015-10-13 16:09:55 +000058 PltReloc = R_386_JUMP_SLOT;
59 PltEntrySize = 16;
Hal Finkel47290642015-10-08 21:25:04 +000060 VAStart = 0x10000;
Rafael Espindola7f074422015-09-22 21:35:51 +000061}
Rafael Espindola01205f72015-09-22 18:19:46 +000062
George Rimar9fd8fcb2015-10-13 16:09:55 +000063void X86TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
64 // Skip 6 bytes of "jmpq *got(%rip)"
65 write32le(Buf, Plt + 6);
66}
67
68void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
69 uint64_t PltEntryAddr) const {
70 const uint8_t PltData[] = {
71 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
72 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
73 0x00, 0x00, 0x00, 0x00
74 };
75 memcpy(Buf, PltData, sizeof(PltData));
76 write32le(Buf + 2, GotEntryAddr - PltEntryAddr + 2); // GOT+8
77 write32le(Buf + 8, GotEntryAddr - PltEntryAddr + 4); // GOT+16
Rui Ueyamac2c22f42015-10-13 16:44:13 +000078}
George Rimar9fd8fcb2015-10-13 16:09:55 +000079
Rafael Espindola01205f72015-09-22 18:19:46 +000080void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
George Rimar9fd8fcb2015-10-13 16:09:55 +000081 uint64_t PltEntryAddr, int32_t Index) const {
82 const uint8_t Inst[] = {
83 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
84 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
85 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
86 };
Rui Ueyama1500a902015-09-29 23:00:47 +000087 memcpy(Buf, Inst, sizeof(Inst));
George Rimar9fd8fcb2015-10-13 16:09:55 +000088
89 write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
90 write32le(Buf + 7, Index);
91 write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16);
Rafael Espindola01205f72015-09-22 18:19:46 +000092}
93
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000094bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +000095 return Type == R_386_GOT32 || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +000096}
97
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000098bool X86TargetInfo::relocPointsToGot(uint32_t Type) const {
99 return Type == R_386_GOTPC;
100}
101
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000102bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
George Rimar730c2782015-10-07 18:46:13 +0000103 return Type == R_386_PLT32 || (Type == R_386_PC32 && S.isShared());
Rafael Espindola01205f72015-09-22 18:19:46 +0000104}
105
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000106static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); }
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000107static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); }
Rafael Espindola0872ea32015-09-24 14:16:02 +0000108
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000109void X86TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
110 uint32_t Type, uint64_t BaseAddr,
111 uint64_t SymVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +0000112 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
113 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
114
115 uint32_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000116 uint8_t *Loc = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +0000117 switch (Type) {
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000118 case R_386_GOT32:
Rui Ueyamaaf21d922015-10-08 20:06:07 +0000119 add32le(Loc, SymVA - Out<ELF32LE>::Got->getVA());
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000120 break;
Rafael Espindolac4010882015-09-22 20:54:08 +0000121 case R_386_PC32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000122 add32le(Loc, SymVA - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000123 break;
124 case R_386_32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000125 add32le(Loc, SymVA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000126 break;
127 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000128 error("unrecognized reloc " + Twine(Type));
Rafael Espindolac4010882015-09-22 20:54:08 +0000129 }
130}
131
Rafael Espindola7f074422015-09-22 21:35:51 +0000132X86_64TargetInfo::X86_64TargetInfo() {
133 PCRelReloc = R_X86_64_PC32;
134 GotReloc = R_X86_64_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000135 GotRefReloc = R_X86_64_PC32;
George Rimar9fd8fcb2015-10-13 16:09:55 +0000136 PltReloc = R_X86_64_JUMP_SLOT;
Rafael Espindolaae244002015-10-05 19:30:12 +0000137 RelativeReloc = R_X86_64_RELATIVE;
George Rimar9fd8fcb2015-10-13 16:09:55 +0000138 PltEntrySize = 16;
Hal Finkel47290642015-10-08 21:25:04 +0000139
140 // On freebsd x86_64 the first page cannot be mmaped.
141 // On linux that is controled by vm.mmap_min_addr. At least on some x86_64
142 // installs that is 65536, so the first 15 pages cannot be used.
143 // Given that, the smallest value that can be used in here is 0x10000.
144 // If using 2MB pages, the smallest page aligned address that works is
145 // 0x200000, but it looks like every OS uses 4k pages for executables.
146 VAStart = 0x10000;
Rafael Espindola7f074422015-09-22 21:35:51 +0000147}
Rafael Espindola01205f72015-09-22 18:19:46 +0000148
George Rimar9fd8fcb2015-10-13 16:09:55 +0000149void X86_64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
150 // Skip 6 bytes of "jmpq *got(%rip)"
151 write32le(Buf, Plt + 6);
152}
153
154void X86_64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
155 uint64_t PltEntryAddr) const {
156 const uint8_t PltData[] = {
157 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
158 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
159 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax)
160 };
161 memcpy(Buf, PltData, sizeof(PltData));
162 write32le(Buf + 2, GotEntryAddr - PltEntryAddr + 2); // GOT+8
163 write32le(Buf + 8, GotEntryAddr - PltEntryAddr + 4); // GOT+16
164}
165
Rafael Espindola01205f72015-09-22 18:19:46 +0000166void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
George Rimar9fd8fcb2015-10-13 16:09:55 +0000167 uint64_t PltEntryAddr, int32_t Index) const {
168 const uint8_t Inst[] = {
169 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
170 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
171 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
172 };
Rui Ueyama1500a902015-09-29 23:00:47 +0000173 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +0000174
George Rimar9fd8fcb2015-10-13 16:09:55 +0000175 write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
176 write32le(Buf + 7, Index);
177 write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16);
Rafael Espindola01205f72015-09-22 18:19:46 +0000178}
179
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000180bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +0000181 return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +0000182}
183
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000184bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Rafael Espindola01205f72015-09-22 18:19:46 +0000185 switch (Type) {
186 default:
187 return false;
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000188 case R_X86_64_PC32:
189 // This relocation is defined to have a value of (S + A - P).
Rafael Espindola3c412e12015-09-30 12:30:58 +0000190 // The problems start when a non PIC program calls a function in a shared
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000191 // library.
Rafael Espindola9a0db7c2015-09-29 23:23:53 +0000192 // In an ideal world, we could just report an error saying the relocation
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000193 // can overflow at runtime.
Rafael Espindola3c412e12015-09-30 12:30:58 +0000194 // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
195 // libc.so.
196 //
197 // The general idea on how to handle such cases is to create a PLT entry
198 // and use that as the function value.
199 //
200 // For the static linking part, we just return true and everything else
201 // will use the the PLT entry as the address.
202 //
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000203 // The remaining (unimplemented) problem is making sure pointer equality
Rafael Espindola3c412e12015-09-30 12:30:58 +0000204 // still works. We need the help of the dynamic linker for that. We
205 // let it know that we have a direct reference to a so symbol by creating
206 // an undefined symbol with a non zero st_value. Seeing that, the
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000207 // dynamic linker resolves the symbol to the value of the symbol we created.
208 // This is true even for got entries, so pointer equality is maintained.
209 // To avoid an infinite loop, the only entry that points to the
Rafael Espindola3c412e12015-09-30 12:30:58 +0000210 // real function is a dedicated got entry used by the plt. That is
211 // identified by special relocation types (R_X86_64_JUMP_SLOT,
212 // R_386_JMP_SLOT, etc).
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000213 return S.isShared();
Rafael Espindola01205f72015-09-22 18:19:46 +0000214 case R_X86_64_PLT32:
215 return true;
216 }
217}
Rafael Espindolac4010882015-09-22 20:54:08 +0000218
Rafael Espindolaae244002015-10-05 19:30:12 +0000219bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
220 switch (Type) {
221 default:
222 return false;
223 case R_X86_64_PC64:
224 case R_X86_64_PC32:
225 case R_X86_64_PC16:
226 case R_X86_64_PC8:
227 return true;
228 }
229}
230
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000231void X86_64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
232 const void *RelP, uint32_t Type,
233 uint64_t BaseAddr, uint64_t SymVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +0000234 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
235 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
236
237 uint64_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000238 uint8_t *Loc = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +0000239 switch (Type) {
240 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000241 case R_X86_64_GOTPCREL:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000242 write32le(Loc, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000243 break;
244 case R_X86_64_64:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000245 write64le(Loc, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000246 break;
247 case R_X86_64_32: {
248 case R_X86_64_32S:
249 uint64_t VA = SymVA + Rel.r_addend;
250 if (Type == R_X86_64_32 && !isUInt<32>(VA))
251 error("R_X86_64_32 out of range");
252 else if (!isInt<32>(VA))
253 error("R_X86_64_32S out of range");
254
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000255 write32le(Loc, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000256 break;
257 }
258 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000259 error("unrecognized reloc " + Twine(Type));
Rafael Espindolac4010882015-09-22 20:54:08 +0000260 }
261}
262
Hal Finkel3c8cc672015-10-12 20:56:18 +0000263// Relocation masks following the #lo(value), #hi(value), #ha(value),
264// #higher(value), #highera(value), #highest(value), and #highesta(value)
265// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
266// document.
267
268static uint16_t applyPPCLo(uint64_t V) { return V & 0xffff; }
269
270static uint16_t applyPPCHi(uint64_t V) { return (V >> 16) & 0xffff; }
271
272static uint16_t applyPPCHa(uint64_t V) { return ((V + 0x8000) >> 16) & 0xffff; }
273
274static uint16_t applyPPCHigher(uint64_t V) { return (V >> 32) & 0xffff; }
275
276static uint16_t applyPPCHighera(uint64_t V) {
277 return ((V + 0x8000) >> 32) & 0xffff;
278}
279
280static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
281
282static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
283
Rafael Espindolac4010882015-09-22 20:54:08 +0000284PPC64TargetInfo::PPC64TargetInfo() {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000285 PCRelReloc = R_PPC64_REL24;
286 GotReloc = R_PPC64_GLOB_DAT;
287 GotRefReloc = R_PPC64_REL64;
Hal Finkelbe0823d2015-10-12 20:58:52 +0000288 RelativeReloc = R_PPC64_RELATIVE;
George Rimar9fd8fcb2015-10-13 16:09:55 +0000289 // PltReloc = FIXME
Hal Finkel6c2a3b82015-10-08 21:51:31 +0000290 PltEntrySize = 32;
George Rimar9fd8fcb2015-10-13 16:09:55 +0000291 PltZeroEntrySize = 0; //FIXME
Hal Finkelc848b322015-10-12 19:34:29 +0000292
293 // We need 64K pages (at least under glibc/Linux, the loader won't
294 // set different permissions on a finer granularity than that).
Hal Finkele3c26262015-10-08 22:23:54 +0000295 PageSize = 65536;
Hal Finkelc848b322015-10-12 19:34:29 +0000296
Hal Finkel47290642015-10-08 21:25:04 +0000297 VAStart = 0x10000000;
Rafael Espindolac4010882015-09-22 20:54:08 +0000298}
Hal Finkel3c8cc672015-10-12 20:56:18 +0000299
300static uint64_t getPPC64TocBase() {
301 // The TOC consists of sections .got, .toc, .tocbss, .plt in that
302 // order. The TOC starts where the first of these sections starts.
303
304 // FIXME: This obviously does not do the right thing when there is no .got
305 // section, but there is a .toc or .tocbss section.
306 uint64_t TocVA = Out<ELF64BE>::Got->getVA();
307 if (!TocVA)
308 TocVA = Out<ELF64BE>::Plt->getVA();
309
310 // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
311 // thus permitting a full 64 Kbytes segment. Note that the glibc startup
312 // code (crt1.o) assumes that you can get from the TOC base to the
313 // start of the .toc section with only a single (signed) 16-bit relocation.
314 return TocVA + 0x8000;
315}
316
George Rimar9fd8fcb2015-10-13 16:09:55 +0000317
318void PPC64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
319void PPC64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac2c22f42015-10-13 16:44:13 +0000320 uint64_t PltEntryAddr) const {}
Rafael Espindolac4010882015-09-22 20:54:08 +0000321void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
George Rimar9fd8fcb2015-10-13 16:09:55 +0000322 uint64_t PltEntryAddr, int32_t Index) const {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000323 uint64_t Off = GotEntryAddr - getPPC64TocBase();
324
325 // FIXME: What we should do, in theory, is get the offset of the function
326 // descriptor in the .opd section, and use that as the offset from %r2 (the
327 // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
328 // be a pointer to the function descriptor in the .opd section. Using
329 // this scheme is simpler, but requires an extra indirection per PLT dispatch.
330
331 write32be(Buf, 0xf8410000); // std %r2, 40(%r1)
332 write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
333 write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
334 write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
335 write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
336 write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
337 write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
338 write32be(Buf + 28, 0x4e800420); // bctr
339}
340
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000341bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000342 if (relocNeedsPlt(Type, S))
343 return true;
344
345 switch (Type) {
346 default: return false;
347 case R_PPC64_GOT16:
348 case R_PPC64_GOT16_LO:
349 case R_PPC64_GOT16_HI:
350 case R_PPC64_GOT16_HA:
351 case R_PPC64_GOT16_DS:
352 case R_PPC64_GOT16_LO_DS:
353 return true;
354 }
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000355}
Hal Finkel3c8cc672015-10-12 20:56:18 +0000356
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000357bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000358 if (Type != R_PPC64_REL24)
359 return false;
360
361 // These are function calls that need to be redirected through a PLT stub.
362 return S.isShared() || (S.isUndefined() && S.isWeak());
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000363}
Hal Finkel3c8cc672015-10-12 20:56:18 +0000364
Hal Finkelbe0823d2015-10-12 20:58:52 +0000365bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
366 switch (Type) {
367 default:
368 return false;
369 case R_PPC64_REL24:
370 case R_PPC64_REL14:
371 case R_PPC64_REL14_BRTAKEN:
372 case R_PPC64_REL14_BRNTAKEN:
373 case R_PPC64_REL32:
374 case R_PPC64_REL64:
375 return true;
376 }
377}
378
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000379void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
380 const void *RelP, uint32_t Type,
Rui Ueyamaaf21d922015-10-08 20:06:07 +0000381 uint64_t BaseAddr, uint64_t SymVA) const {
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000382 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
383 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
384
Hal Finkel3c8cc672015-10-12 20:56:18 +0000385 uint8_t *L = Buf + Rel.r_offset;
386 uint64_t S = SymVA;
387 int64_t A = Rel.r_addend;
388 uint64_t P = BaseAddr + Rel.r_offset;
389 uint64_t TB = getPPC64TocBase();
390
391 if (Type == R_PPC64_TOC) {
392 write64be(L, TB);
393 return;
394 }
395
396 // For a TOC-relative relocation, adjust the addend and proceed in terms of
397 // the corresponding ADDR16 relocation type.
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000398 switch (Type) {
Hal Finkel3c8cc672015-10-12 20:56:18 +0000399 case R_PPC64_TOC16: Type = R_PPC64_ADDR16; A -= TB; break;
400 case R_PPC64_TOC16_DS: Type = R_PPC64_ADDR16_DS; A -= TB; break;
401 case R_PPC64_TOC16_LO: Type = R_PPC64_ADDR16_LO; A -= TB; break;
402 case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; A -= TB; break;
403 case R_PPC64_TOC16_HI: Type = R_PPC64_ADDR16_HI; A -= TB; break;
404 case R_PPC64_TOC16_HA: Type = R_PPC64_ADDR16_HA; A -= TB; break;
405 default: break;
406 }
407
408 uint64_t R = S + A;
409
410 switch (Type) {
411 case R_PPC64_ADDR16:
412 write16be(L, applyPPCLo(R));
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000413 break;
Hal Finkel3c8cc672015-10-12 20:56:18 +0000414 case R_PPC64_ADDR16_DS:
415 if (!isInt<16>(R))
416 error("Relocation R_PPC64_ADDR16_DS overflow");
417 write16be(L, (read16be(L) & 3) | (R & ~3));
418 break;
419 case R_PPC64_ADDR16_LO:
420 write16be(L, applyPPCLo(R));
421 break;
422 case R_PPC64_ADDR16_LO_DS:
423 write16be(L, (read16be(L) & 3) | (applyPPCLo(R) & ~3));
424 break;
425 case R_PPC64_ADDR16_HI:
426 write16be(L, applyPPCHi(R));
427 break;
428 case R_PPC64_ADDR16_HA:
429 write16be(L, applyPPCHa(R));
430 break;
431 case R_PPC64_ADDR16_HIGHER:
432 write16be(L, applyPPCHigher(R));
433 break;
434 case R_PPC64_ADDR16_HIGHERA:
435 write16be(L, applyPPCHighera(R));
436 break;
437 case R_PPC64_ADDR16_HIGHEST:
438 write16be(L, applyPPCHighest(R));
439 break;
440 case R_PPC64_ADDR16_HIGHESTA:
441 write16be(L, applyPPCHighesta(R));
442 break;
443 case R_PPC64_ADDR14: {
444 if ((R & 3) != 0)
445 error("Improper alignment for relocation R_PPC64_ADDR14");
446
447 // Preserve the AA/LK bits in the branch instruction
448 uint8_t AALK = L[3];
449 write16be(L + 2, (AALK & 3) | (R & 0xfffc));
450 break;
451 }
452 case R_PPC64_REL16_LO:
453 write16be(L, applyPPCLo(R - P));
454 break;
455 case R_PPC64_REL16_HI:
456 write16be(L, applyPPCHi(R - P));
457 break;
458 case R_PPC64_REL16_HA:
459 write16be(L, applyPPCHa(R - P));
460 break;
461 case R_PPC64_ADDR32:
462 if (!isInt<32>(R))
463 error("Relocation R_PPC64_ADDR32 overflow");
464 write32be(L, R);
465 break;
466 case R_PPC64_REL24: {
Hal Finkeldaedc122015-10-12 23:16:53 +0000467 uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
468 uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
469 bool InPlt = PltStart <= S + A && S + A < PltEnd;
470
471 if (!InPlt && Out<ELF64BE>::Opd) {
472 // If this is a local call, and we currently have the address of a
473 // function-descriptor, get the underlying code address instead.
474 uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
475 uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
476 bool InOpd = OpdStart <= S + A && S + A < OpdEnd;
477
478 if (InOpd)
479 R = read64be(&Out<ELF64BE>::OpdBuf[S + A - OpdStart]);
480 }
481
Hal Finkel3c8cc672015-10-12 20:56:18 +0000482 uint32_t Mask = 0x03FFFFFC;
483 if (!isInt<24>(R - P))
484 error("Relocation R_PPC64_REL24 overflow");
485 write32be(L, (read32be(L) & ~Mask) | ((R - P) & Mask));
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000486
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000487 if (InPlt && L + 8 < BufEnd &&
488 read32be(L + 4) == 0x60000000 /* nop */)
489 write32be(L + 4, 0xe8410028); // ld %r2, 40(%r1)
Hal Finkel3c8cc672015-10-12 20:56:18 +0000490 break;
491 }
492 case R_PPC64_REL32:
493 if (!isInt<32>(R - P))
494 error("Relocation R_PPC64_REL32 overflow");
495 write32be(L, R - P);
496 break;
497 case R_PPC64_REL64:
498 write64be(L, R - P);
499 break;
500 case R_PPC64_ADDR64:
501 write64be(L, R);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000502 break;
503 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000504 error("unrecognized reloc " + Twine(Type));
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000505 }
506}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000507
508PPCTargetInfo::PPCTargetInfo() {
509 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000510 // GotReloc = FIXME
George Rimar9fd8fcb2015-10-13 16:09:55 +0000511 // PltReloc = FIXME
Hal Finkele3c26262015-10-08 22:23:54 +0000512 PageSize = 65536;
Hal Finkel47290642015-10-08 21:25:04 +0000513 VAStart = 0x10000000;
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000514}
George Rimar9fd8fcb2015-10-13 16:09:55 +0000515
516void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
517void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac2c22f42015-10-13 16:44:13 +0000518 uint64_t PltEntryAddr) const {}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000519void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
George Rimar9fd8fcb2015-10-13 16:09:55 +0000520 uint64_t PltEntryAddr, int32_t Index) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000521bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
522 return false;
523}
524bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
525 return false;
526}
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000527void PPCTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
528 const void *RelP, uint32_t Type,
Rui Ueyamaaf21d922015-10-08 20:06:07 +0000529 uint64_t BaseAddr, uint64_t SymVA) const {}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000530
Davide Italianocde93362015-09-26 00:32:04 +0000531AArch64TargetInfo::AArch64TargetInfo() {
532 // PCRelReloc = FIXME
533 // GotReloc = FIXME
George Rimar9fd8fcb2015-10-13 16:09:55 +0000534 // PltReloc = FIXME
Hal Finkel47290642015-10-08 21:25:04 +0000535 VAStart = 0x400000;
Davide Italianocde93362015-09-26 00:32:04 +0000536}
George Rimar9fd8fcb2015-10-13 16:09:55 +0000537
538void AArch64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
539void AArch64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
Rui Ueyamac2c22f42015-10-13 16:44:13 +0000540 uint64_t PltEntryAddr) const {}
Davide Italianocde93362015-09-26 00:32:04 +0000541void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
George Rimar9fd8fcb2015-10-13 16:09:55 +0000542 uint64_t PltEntryAddr,
543 int32_t Index) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000544bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
545 const SymbolBody &S) const {
546 return false;
547}
548bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
549 const SymbolBody &S) const {
550 return false;
551}
Davide Italiano1d750a62015-09-27 08:45:38 +0000552
Davide Italianoef4be6b2015-10-06 19:01:32 +0000553static void updateAArch64Adr(uint8_t *L, uint64_t Imm) {
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000554 uint32_t ImmLo = (Imm & 0x3) << 29;
555 uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
556 uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000557 write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000558}
559
Davide Italiano318ca222015-10-02 22:13:51 +0000560// Page(Expr) is the page address of the expression Expr, defined
561// as (Expr & ~0xFFF). (This applies even if the machine page size
Davide Italianod9b5be42015-10-02 22:17:09 +0000562// supported by the platform has a different value.)
Davide Italianoef4be6b2015-10-06 19:01:32 +0000563static uint64_t getAArch64Page(uint64_t Expr) {
Davide Italiano318ca222015-10-02 22:13:51 +0000564 return Expr & (~static_cast<uint64_t>(0xFFF));
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000565}
566
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000567void AArch64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
568 const void *RelP, uint32_t Type,
569 uint64_t BaseAddr, uint64_t SymVA) const {
Davide Italiano1d750a62015-09-27 08:45:38 +0000570 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
571 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
572
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000573 uint8_t *L = Buf + Rel.r_offset;
Davide Italiano1d750a62015-09-27 08:45:38 +0000574 uint64_t S = SymVA;
575 int64_t A = Rel.r_addend;
576 uint64_t P = BaseAddr + Rel.r_offset;
577 switch (Type) {
Davide Italianodf88f962015-10-04 00:59:16 +0000578 case R_AARCH64_ABS16:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000579 if (!isInt<16>(S + A))
580 error("Relocation R_AARCH64_ABS16 out of range");
Davide Italiano06d84322015-10-07 22:10:02 +0000581 write16le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000582 break;
583 case R_AARCH64_ABS32:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000584 if (!isInt<32>(S + A))
585 error("Relocation R_AARCH64_ABS32 out of range");
Davide Italiano06d84322015-10-07 22:10:02 +0000586 write32le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000587 break;
588 case R_AARCH64_ABS64:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000589 // No overflow check needed.
Davide Italiano06d84322015-10-07 22:10:02 +0000590 write64le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000591 break;
Davide Italiano0b6974b2015-10-03 19:56:07 +0000592 case R_AARCH64_ADD_ABS_LO12_NC:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000593 // No overflow check needed.
594 or32le(L, ((S + A) & 0xFFF) << 10);
Davide Italiano0b6974b2015-10-03 19:56:07 +0000595 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000596 case R_AARCH64_ADR_PREL_LO21: {
597 uint64_t X = S + A - P;
598 if (!isInt<21>(X))
599 error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
600 updateAArch64Adr(L, X & 0x1FFFFF);
Davide Italiano1d750a62015-09-27 08:45:38 +0000601 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000602 }
603 case R_AARCH64_ADR_PREL_PG_HI21: {
604 uint64_t X = getAArch64Page(S + A) - getAArch64Page(P);
605 if (!isInt<33>(X))
606 error("Relocation R_AARCH64_ADR_PREL_PG_HI21 out of range");
607 updateAArch64Adr(L, (X >> 12) & 0x1FFFFF); // X[32:12]
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000608 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000609 }
Davide Italiano1d750a62015-09-27 08:45:38 +0000610 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000611 error("unrecognized reloc " + Twine(Type));
Davide Italiano1d750a62015-09-27 08:45:38 +0000612 }
613}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000614
615MipsTargetInfo::MipsTargetInfo() {
616 // PCRelReloc = FIXME
617 // GotReloc = FIXME
George Rimar9fd8fcb2015-10-13 16:09:55 +0000618 // PltReloc = FIXME
Hal Finkele3c26262015-10-08 22:23:54 +0000619 PageSize = 65536;
Hal Finkel47290642015-10-08 21:25:04 +0000620 VAStart = 0x400000;
Simon Atanasyan49829a12015-09-29 05:34:03 +0000621}
622
George Rimar9fd8fcb2015-10-13 16:09:55 +0000623void MipsTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
624
625void MipsTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
626 uint64_t PltEntryAddr) const {}
627
Simon Atanasyan49829a12015-09-29 05:34:03 +0000628void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
George Rimar9fd8fcb2015-10-13 16:09:55 +0000629 uint64_t PltEntryAddr, int32_t Index) const {
630}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000631
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000632bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
633 return false;
634}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000635
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000636bool MipsTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
637 return false;
638}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000639
Hal Finkel87bbd5f2015-10-12 21:19:18 +0000640void MipsTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
641 const void *RelP, uint32_t Type,
Simon Atanasyan3b732ac2015-10-12 15:10:02 +0000642 uint64_t BaseAddr, uint64_t SymVA) const {
643 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
644 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
645
646 switch (Type) {
647 case R_MIPS_32:
648 add32le(Buf + Rel.r_offset, SymVA);
649 break;
650 default:
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000651 error("unrecognized reloc " + Twine(Type));
Simon Atanasyan3b732ac2015-10-12 15:10:02 +0000652 }
653}
Rafael Espindola01205f72015-09-22 18:19:46 +0000654}
655}