blob: e1c280171783eb90ae9e65bd3e4d0f85ef80f25f [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 Espindola01205f72015-09-22 18:19:46 +000012
13#include "llvm/ADT/ArrayRef.h"
Rafael Espindolac4010882015-09-22 20:54:08 +000014#include "llvm/Object/ELF.h"
Rafael Espindola01205f72015-09-22 18:19:46 +000015#include "llvm/Support/Endian.h"
16#include "llvm/Support/ELF.h"
17
18using namespace llvm;
Rafael Espindolac4010882015-09-22 20:54:08 +000019using namespace llvm::object;
Rafael Espindola0872ea32015-09-24 14:16:02 +000020using namespace llvm::support::endian;
Rafael Espindola01205f72015-09-22 18:19:46 +000021using namespace llvm::ELF;
22
23namespace lld {
24namespace elf2 {
25
26std::unique_ptr<TargetInfo> Target;
27
28TargetInfo::~TargetInfo() {}
29
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000030bool TargetInfo::relocPointsToGot(uint32_t Type) const { return false; }
31
Rafael Espindola7f074422015-09-22 21:35:51 +000032X86TargetInfo::X86TargetInfo() {
33 PCRelReloc = R_386_PC32;
34 GotReloc = R_386_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +000035 GotRefReloc = R_386_GOT32;
Rafael Espindola7f074422015-09-22 21:35:51 +000036}
Rafael Espindola01205f72015-09-22 18:19:46 +000037
38void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
39 uint64_t PltEntryAddr) const {
Rui Ueyama1500a902015-09-29 23:00:47 +000040 // jmpl *val; nop; nop
41 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
42 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +000043 assert(isUInt<32>(GotEntryAddr));
Rui Ueyama1500a902015-09-29 23:00:47 +000044 write32le(Buf + 2, GotEntryAddr);
Rafael Espindola01205f72015-09-22 18:19:46 +000045}
46
47bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
48 if (relocNeedsPlt(Type))
49 return true;
50 switch (Type) {
51 default:
52 return false;
53 case R_386_GOT32:
54 return true;
55 }
56}
57
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000058bool X86TargetInfo::relocPointsToGot(uint32_t Type) const {
59 return Type == R_386_GOTPC;
60}
61
Rafael Espindola01205f72015-09-22 18:19:46 +000062bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
63 switch (Type) {
64 default:
65 return false;
66 case R_386_PLT32:
67 return true;
68 }
69}
70
Rafael Espindola0872ea32015-09-24 14:16:02 +000071static void add32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
72
Rafael Espindolac4010882015-09-22 20:54:08 +000073void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +000074 uint64_t BaseAddr, uint64_t SymVA,
75 uint64_t GotVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +000076 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
77 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
78
79 uint32_t Offset = Rel.r_offset;
80 uint8_t *Location = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +000081 switch (Type) {
Rafael Espindola8acb95c2015-09-29 14:42:37 +000082 case R_386_GOT32:
83 add32le(Location, SymVA - GotVA);
84 break;
Rafael Espindolac4010882015-09-22 20:54:08 +000085 case R_386_PC32:
Rafael Espindola0872ea32015-09-24 14:16:02 +000086 add32le(Location, SymVA - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +000087 break;
88 case R_386_32:
Rafael Espindola0872ea32015-09-24 14:16:02 +000089 add32le(Location, SymVA);
Rafael Espindolac4010882015-09-22 20:54:08 +000090 break;
91 default:
92 error(Twine("unrecognized reloc ") + Twine(Type));
93 break;
94 }
95}
96
Rafael Espindola7f074422015-09-22 21:35:51 +000097X86_64TargetInfo::X86_64TargetInfo() {
98 PCRelReloc = R_X86_64_PC32;
99 GotReloc = R_X86_64_GLOB_DAT;
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000100 GotRefReloc = R_X86_64_PC32;
Rafael Espindola7f074422015-09-22 21:35:51 +0000101}
Rafael Espindola01205f72015-09-22 18:19:46 +0000102
103void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
104 uint64_t PltEntryAddr) const {
Rui Ueyama1500a902015-09-29 23:00:47 +0000105 // jmpq *val(%rip); nop; nop
106 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
107 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +0000108
109 uintptr_t NextPC = PltEntryAddr + 6;
Rafael Espindola8c21fad2015-09-22 20:06:19 +0000110 intptr_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +0000111 assert(isInt<32>(Delta));
Rui Ueyama1500a902015-09-29 23:00:47 +0000112 write32le(Buf + 2, Delta);
Rafael Espindola01205f72015-09-22 18:19:46 +0000113}
114
115bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
116 if (relocNeedsPlt(Type))
117 return true;
118 switch (Type) {
119 default:
120 return false;
121 case R_X86_64_GOTPCREL:
122 return true;
123 }
124}
125
126bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
127 switch (Type) {
128 default:
129 return false;
130 case R_X86_64_PLT32:
131 return true;
132 }
133}
Rafael Espindolac4010882015-09-22 20:54:08 +0000134
135void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
136 uint32_t Type, uint64_t BaseAddr,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000137 uint64_t SymVA, uint64_t GotVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +0000138 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
139 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
140
141 uint64_t Offset = Rel.r_offset;
142 uint8_t *Location = Buf + Offset;
143 switch (Type) {
144 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000145 case R_X86_64_GOTPCREL:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000146 write32le(Location, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000147 break;
148 case R_X86_64_64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000149 write64le(Location, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000150 break;
151 case R_X86_64_32: {
152 case R_X86_64_32S:
153 uint64_t VA = SymVA + Rel.r_addend;
154 if (Type == R_X86_64_32 && !isUInt<32>(VA))
155 error("R_X86_64_32 out of range");
156 else if (!isInt<32>(VA))
157 error("R_X86_64_32S out of range");
158
Rafael Espindola0872ea32015-09-24 14:16:02 +0000159 write32le(Location, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000160 break;
161 }
162 default:
163 error(Twine("unrecognized reloc ") + Twine(Type));
164 break;
165 }
166}
167
168PPC64TargetInfo::PPC64TargetInfo() {
169 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000170 // GotReloc = FIXME
Rafael Espindolac4010882015-09-22 20:54:08 +0000171}
172void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
173 uint64_t PltEntryAddr) const {}
174bool PPC64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
175bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
176void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000177 uint64_t BaseAddr, uint64_t SymVA,
178 uint64_t GotVA) const {
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000179 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
180 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
181
182 uint64_t Offset = Rel.r_offset;
183 uint8_t *Location = Buf + Offset;
184 switch (Type) {
185 case R_PPC64_ADDR64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000186 write64be(Location, SymVA + Rel.r_addend);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000187 break;
188 case R_PPC64_TOC:
189 // We don't create a TOC yet.
190 break;
191 default:
192 error(Twine("unrecognized reloc ") + Twine(Type));
193 break;
194 }
195}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000196
197PPCTargetInfo::PPCTargetInfo() {
198 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000199 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000200}
201void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
202 uint64_t PltEntryAddr) const {}
203bool PPCTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
204bool PPCTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
205void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000206 uint64_t BaseAddr, uint64_t SymVA,
207 uint64_t GotVA) const {}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000208
209ARMTargetInfo::ARMTargetInfo() {
210 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000211 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000212}
213void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
214 uint64_t PltEntryAddr) const {}
215bool ARMTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
216bool ARMTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
217void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000218 uint64_t BaseAddr, uint64_t SymVA,
219 uint64_t GotVA) const {}
Davide Italianocde93362015-09-26 00:32:04 +0000220
221AArch64TargetInfo::AArch64TargetInfo() {
222 // PCRelReloc = FIXME
223 // GotReloc = FIXME
224}
225void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
226 uint64_t PltEntryAddr) const {}
227bool AArch64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
228bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
Davide Italiano1d750a62015-09-27 08:45:38 +0000229
230static void handle_ADR_PREL_LO21(uint8_t *Location, uint64_t S, int64_t A,
231 uint64_t P) {
232 uint64_t X = S + A - P;
233 if (!isInt<21>(X))
234 error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
235 uint32_t Imm = X & 0x1FFFFF;
236 uint32_t ImmLo = (Imm & 0x3) << 29;
237 uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
238 uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
239 write32le(Location, (read32le(Location) & ~Mask) | ImmLo | ImmHi);
240}
241
Davide Italianocde93362015-09-26 00:32:04 +0000242void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
243 uint32_t Type, uint64_t BaseAddr,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000244 uint64_t SymVA, uint64_t GotVA) const {
Davide Italiano1d750a62015-09-27 08:45:38 +0000245 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
246 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
247
248 uint8_t *Location = Buf + Rel.r_offset;
249 uint64_t S = SymVA;
250 int64_t A = Rel.r_addend;
251 uint64_t P = BaseAddr + Rel.r_offset;
252 switch (Type) {
253 case R_AARCH64_ADR_PREL_LO21:
254 handle_ADR_PREL_LO21(Location, S, A, P);
255 break;
256 default:
257 error(Twine("unrecognized reloc ") + Twine(Type));
258 break;
259 }
260}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000261
262MipsTargetInfo::MipsTargetInfo() {
263 // PCRelReloc = FIXME
264 // GotReloc = FIXME
265 DefaultEntry = "__start";
266}
267
268void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
269 uint64_t PltEntryAddr) const {}
270
271bool MipsTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
272
273bool MipsTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
274
275void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000276 uint64_t BaseAddr, uint64_t SymVA,
277 uint64_t GotVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000278}
279}