blob: 4748bce528329de85690990e6d42fd5f0c8e3649 [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"
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000012#include "Symbols.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000013
14#include "llvm/ADT/ArrayRef.h"
Rafael Espindolac4010882015-09-22 20:54:08 +000015#include "llvm/Object/ELF.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000016#include "llvm/Support/Endian.h"
17#include "llvm/Support/ELF.h"
18
19using namespace llvm;
Rafael Espindolac4010882015-09-22 20:54:08 +000020using namespace llvm::object;
Rafael Espindola0872ea32015-09-24 14:16:02 +000021using namespace llvm::support::endian;
Rafael Espindola01205f72015-09-22 18:19:46 +000022using namespace llvm::ELF;
23
24namespace lld {
25namespace elf2 {
26
27std::unique_ptr<TargetInfo> Target;
28
29TargetInfo::~TargetInfo() {}
30
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000031bool TargetInfo::relocPointsToGot(uint32_t Type) const { return false; }
32
Rafael Espindolaae244002015-10-05 19:30:12 +000033bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
34
Rafael Espindola7f074422015-09-22 21:35:51 +000035X86TargetInfo::X86TargetInfo() {
36 PCRelReloc = R_386_PC32;
37 GotReloc = R_386_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +000038 GotRefReloc = R_386_GOT32;
Rafael Espindola7f074422015-09-22 21:35:51 +000039}
Rafael Espindola01205f72015-09-22 18:19:46 +000040
41void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
42 uint64_t PltEntryAddr) const {
Rui Ueyama1500a902015-09-29 23:00:47 +000043 // jmpl *val; nop; nop
44 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
45 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +000046 assert(isUInt<32>(GotEntryAddr));
Rui Ueyama1500a902015-09-29 23:00:47 +000047 write32le(Buf + 2, GotEntryAddr);
Rafael Espindola01205f72015-09-22 18:19:46 +000048}
49
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000050bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +000051 return Type == R_386_GOT32 || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +000052}
53
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000054bool X86TargetInfo::relocPointsToGot(uint32_t Type) const {
55 return Type == R_386_GOTPC;
56}
57
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +000058bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +000059 return Type == R_386_PLT32;
Rafael Espindola01205f72015-09-22 18:19:46 +000060}
61
Rafael Espindola0872ea32015-09-24 14:16:02 +000062static void add32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
63
Rafael Espindolac4010882015-09-22 20:54:08 +000064void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +000065 uint64_t BaseAddr, uint64_t SymVA,
66 uint64_t GotVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +000067 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
68 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
69
70 uint32_t Offset = Rel.r_offset;
71 uint8_t *Location = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +000072 switch (Type) {
Rafael Espindola8acb95c2015-09-29 14:42:37 +000073 case R_386_GOT32:
74 add32le(Location, SymVA - GotVA);
75 break;
Rafael Espindolac4010882015-09-22 20:54:08 +000076 case R_386_PC32:
Rafael Espindola0872ea32015-09-24 14:16:02 +000077 add32le(Location, SymVA - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +000078 break;
79 case R_386_32:
Rafael Espindola0872ea32015-09-24 14:16:02 +000080 add32le(Location, SymVA);
Rafael Espindolac4010882015-09-22 20:54:08 +000081 break;
82 default:
83 error(Twine("unrecognized reloc ") + Twine(Type));
84 break;
85 }
86}
87
Rafael Espindola7f074422015-09-22 21:35:51 +000088X86_64TargetInfo::X86_64TargetInfo() {
89 PCRelReloc = R_X86_64_PC32;
90 GotReloc = R_X86_64_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +000091 GotRefReloc = R_X86_64_PC32;
Rafael Espindolaae244002015-10-05 19:30:12 +000092 RelativeReloc = R_X86_64_RELATIVE;
Rafael Espindola7f074422015-09-22 21:35:51 +000093}
Rafael Espindola01205f72015-09-22 18:19:46 +000094
95void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
96 uint64_t PltEntryAddr) const {
Rui Ueyama1500a902015-09-29 23:00:47 +000097 // jmpq *val(%rip); nop; nop
98 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
99 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +0000100
Rui Ueyamae3fbc892015-09-29 23:25:21 +0000101 uint64_t NextPC = PltEntryAddr + 6;
102 int64_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +0000103 assert(isInt<32>(Delta));
Rui Ueyama1500a902015-09-29 23:00:47 +0000104 write32le(Buf + 2, Delta);
Rafael Espindola01205f72015-09-22 18:19:46 +0000105}
106
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000107bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +0000108 return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +0000109}
110
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000111bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Rafael Espindola01205f72015-09-22 18:19:46 +0000112 switch (Type) {
113 default:
114 return false;
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000115 case R_X86_64_PC32:
116 // This relocation is defined to have a value of (S + A - P).
Rafael Espindola3c412e12015-09-30 12:30:58 +0000117 // The problems start when a non PIC program calls a function in a shared
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000118 // library.
Rafael Espindola9a0db7c2015-09-29 23:23:53 +0000119 // In an ideal world, we could just report an error saying the relocation
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000120 // can overflow at runtime.
Rafael Espindola3c412e12015-09-30 12:30:58 +0000121 // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
122 // libc.so.
123 //
124 // The general idea on how to handle such cases is to create a PLT entry
125 // and use that as the function value.
126 //
127 // For the static linking part, we just return true and everything else
128 // will use the the PLT entry as the address.
129 //
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000130 // The remaining (unimplemented) problem is making sure pointer equality
Rafael Espindola3c412e12015-09-30 12:30:58 +0000131 // still works. We need the help of the dynamic linker for that. We
132 // let it know that we have a direct reference to a so symbol by creating
133 // an undefined symbol with a non zero st_value. Seeing that, the
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000134 // dynamic linker resolves the symbol to the value of the symbol we created.
135 // This is true even for got entries, so pointer equality is maintained.
136 // To avoid an infinite loop, the only entry that points to the
Rafael Espindola3c412e12015-09-30 12:30:58 +0000137 // real function is a dedicated got entry used by the plt. That is
138 // identified by special relocation types (R_X86_64_JUMP_SLOT,
139 // R_386_JMP_SLOT, etc).
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000140 return S.isShared();
Rafael Espindola01205f72015-09-22 18:19:46 +0000141 case R_X86_64_PLT32:
142 return true;
143 }
144}
Rafael Espindolac4010882015-09-22 20:54:08 +0000145
Rafael Espindolaae244002015-10-05 19:30:12 +0000146bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
147 switch (Type) {
148 default:
149 return false;
150 case R_X86_64_PC64:
151 case R_X86_64_PC32:
152 case R_X86_64_PC16:
153 case R_X86_64_PC8:
154 return true;
155 }
156}
157
Rafael Espindolac4010882015-09-22 20:54:08 +0000158void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
159 uint32_t Type, uint64_t BaseAddr,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000160 uint64_t SymVA, uint64_t GotVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +0000161 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
162 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
163
164 uint64_t Offset = Rel.r_offset;
165 uint8_t *Location = Buf + Offset;
166 switch (Type) {
167 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000168 case R_X86_64_GOTPCREL:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000169 write32le(Location, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000170 break;
171 case R_X86_64_64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000172 write64le(Location, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000173 break;
174 case R_X86_64_32: {
175 case R_X86_64_32S:
176 uint64_t VA = SymVA + Rel.r_addend;
177 if (Type == R_X86_64_32 && !isUInt<32>(VA))
178 error("R_X86_64_32 out of range");
179 else if (!isInt<32>(VA))
180 error("R_X86_64_32S out of range");
181
Rafael Espindola0872ea32015-09-24 14:16:02 +0000182 write32le(Location, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000183 break;
184 }
185 default:
186 error(Twine("unrecognized reloc ") + Twine(Type));
187 break;
188 }
189}
190
191PPC64TargetInfo::PPC64TargetInfo() {
192 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000193 // GotReloc = FIXME
Rafael Espindolac4010882015-09-22 20:54:08 +0000194}
195void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
196 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000197bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
198 return false;
199}
200bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
201 return false;
202}
Rafael Espindolac4010882015-09-22 20:54:08 +0000203void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000204 uint64_t BaseAddr, uint64_t SymVA,
205 uint64_t GotVA) const {
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000206 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
207 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
208
209 uint64_t Offset = Rel.r_offset;
210 uint8_t *Location = Buf + Offset;
211 switch (Type) {
212 case R_PPC64_ADDR64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000213 write64be(Location, SymVA + Rel.r_addend);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000214 break;
215 case R_PPC64_TOC:
216 // We don't create a TOC yet.
217 break;
218 default:
219 error(Twine("unrecognized reloc ") + Twine(Type));
220 break;
221 }
222}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000223
224PPCTargetInfo::PPCTargetInfo() {
225 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000226 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000227}
228void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
229 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000230bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
231 return false;
232}
233bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
234 return false;
235}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000236void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000237 uint64_t BaseAddr, uint64_t SymVA,
238 uint64_t GotVA) const {}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000239
240ARMTargetInfo::ARMTargetInfo() {
241 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000242 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000243}
244void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
245 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000246bool ARMTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
247 return false;
248}
249bool ARMTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
250 return false;
251}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000252void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000253 uint64_t BaseAddr, uint64_t SymVA,
254 uint64_t GotVA) const {}
Davide Italianocde93362015-09-26 00:32:04 +0000255
256AArch64TargetInfo::AArch64TargetInfo() {
257 // PCRelReloc = FIXME
258 // GotReloc = FIXME
259}
260void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
261 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000262bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
263 const SymbolBody &S) const {
264 return false;
265}
266bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
267 const SymbolBody &S) const {
268 return false;
269}
Davide Italiano1d750a62015-09-27 08:45:38 +0000270
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000271static void AArch64UpdateAdr(uint8_t *Location, uint64_t Imm) {
272 uint32_t ImmLo = (Imm & 0x3) << 29;
273 uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
274 uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
275 write32le(Location, (read32le(Location) & ~Mask) | ImmLo | ImmHi);
276}
277
Davide Italiano318ca222015-10-02 22:13:51 +0000278// Page(Expr) is the page address of the expression Expr, defined
279// as (Expr & ~0xFFF). (This applies even if the machine page size
Davide Italianod9b5be42015-10-02 22:17:09 +0000280// supported by the platform has a different value.)
Davide Italiano318ca222015-10-02 22:13:51 +0000281static uint64_t AArch64GetPage(uint64_t Expr) {
282 return Expr & (~static_cast<uint64_t>(0xFFF));
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000283}
284
Davide Italianodf88f962015-10-04 00:59:16 +0000285static void handle_ABS16(uint8_t *Location, uint64_t S, int64_t A) {
286 uint64_t X = S + A;
287 if (!isInt<16>(X)) // -2^15 <= X < 2^16
288 error("Relocation R_AARCH64_ABS16 out of range");
289 write16le(Location, read32le(Location) | X);
290}
291
292static void handle_ABS32(uint8_t *Location, uint64_t S, int64_t A) {
293 uint64_t X = S + A;
294 if (!isInt<32>(X)) // -2^31 <= X < 2^32
295 error("Relocation R_AARCH64_ABS32 out of range");
296 write32le(Location, read32le(Location) | X);
297}
298
299static void handle_ABS64(uint8_t *Location, uint64_t S, int64_t A) {
300 uint64_t X = S + A;
301 // No overflow check.
302 write64le(Location, read32le(Location) | X);
303}
304
Davide Italiano0b6974b2015-10-03 19:56:07 +0000305static void handle_ADD_ABS_LO12_NC(uint8_t *Location, uint64_t S, int64_t A) {
306 // No overflow check.
307 uint64_t X = ((S + A) & 0xFFF) << 10;
308 write32le(Location, read32le(Location) | X);
309}
310
Davide Italiano1d750a62015-09-27 08:45:38 +0000311static void handle_ADR_PREL_LO21(uint8_t *Location, uint64_t S, int64_t A,
312 uint64_t P) {
313 uint64_t X = S + A - P;
314 if (!isInt<21>(X))
315 error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000316 AArch64UpdateAdr(Location, X & 0x1FFFFF);
317}
318
319static void handle_ADR_PREL_PG_HI21(uint8_t *Location, uint64_t S, int64_t A,
320 uint64_t P) {
321 uint64_t X = AArch64GetPage(S + A) - AArch64GetPage(P);
322 if (!isInt<33>(X))
323 error("Relocation R_AARCH64_ADR_PREL_PG_HI21 out of range");
324 AArch64UpdateAdr(Location, (X >> 12) & 0x1FFFFF); // X[32:12]
Davide Italiano1d750a62015-09-27 08:45:38 +0000325}
326
Davide Italianocde93362015-09-26 00:32:04 +0000327void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
328 uint32_t Type, uint64_t BaseAddr,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000329 uint64_t SymVA, uint64_t GotVA) const {
Davide Italiano1d750a62015-09-27 08:45:38 +0000330 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
331 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
332
333 uint8_t *Location = Buf + Rel.r_offset;
334 uint64_t S = SymVA;
335 int64_t A = Rel.r_addend;
336 uint64_t P = BaseAddr + Rel.r_offset;
337 switch (Type) {
Davide Italianodf88f962015-10-04 00:59:16 +0000338 case R_AARCH64_ABS16:
339 handle_ABS16(Location, S, A);
340 break;
341 case R_AARCH64_ABS32:
342 handle_ABS32(Location, S, A);
343 break;
344 case R_AARCH64_ABS64:
345 handle_ABS64(Location, S, A);
346 break;
Davide Italiano0b6974b2015-10-03 19:56:07 +0000347 case R_AARCH64_ADD_ABS_LO12_NC:
348 handle_ADD_ABS_LO12_NC(Location, S, A);
349 break;
Davide Italiano1d750a62015-09-27 08:45:38 +0000350 case R_AARCH64_ADR_PREL_LO21:
351 handle_ADR_PREL_LO21(Location, S, A, P);
352 break;
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000353 case R_AARCH64_ADR_PREL_PG_HI21:
354 handle_ADR_PREL_PG_HI21(Location, S, A, P);
355 break;
Davide Italiano1d750a62015-09-27 08:45:38 +0000356 default:
357 error(Twine("unrecognized reloc ") + Twine(Type));
358 break;
359 }
360}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000361
362MipsTargetInfo::MipsTargetInfo() {
363 // PCRelReloc = FIXME
364 // GotReloc = FIXME
365 DefaultEntry = "__start";
366}
367
368void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
369 uint64_t PltEntryAddr) const {}
370
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000371bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
372 return false;
373}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000374
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000375bool MipsTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
376 return false;
377}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000378
379void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000380 uint64_t BaseAddr, uint64_t SymVA,
381 uint64_t GotVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000382}
383}