blob: 97c8b8e9dc1f22f8ca6a05e5323818521dc6c504 [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;
35}
Rafael Espindola01205f72015-09-22 18:19:46 +000036
37void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
38 uint64_t PltEntryAddr) const {
39 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpl *val
40 memcpy(Buf, Jmp.data(), Jmp.size());
41 Buf += Jmp.size();
42
43 assert(isUInt<32>(GotEntryAddr));
Rafael Espindola0872ea32015-09-24 14:16:02 +000044 write32le(Buf, GotEntryAddr);
Rafael Espindola01205f72015-09-22 18:19:46 +000045 Buf += 4;
46
47 ArrayRef<uint8_t> Nops = {0x90, 0x90};
48 memcpy(Buf, Nops.data(), Nops.size());
49}
50
51bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
52 if (relocNeedsPlt(Type))
53 return true;
54 switch (Type) {
55 default:
56 return false;
57 case R_386_GOT32:
58 return true;
59 }
60}
61
Rafael Espindola6d7fcdb2015-09-29 13:36:32 +000062bool X86TargetInfo::relocPointsToGot(uint32_t Type) const {
63 return Type == R_386_GOTPC;
64}
65
Rafael Espindola01205f72015-09-22 18:19:46 +000066bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
67 switch (Type) {
68 default:
69 return false;
70 case R_386_PLT32:
71 return true;
72 }
73}
74
Rafael Espindola0872ea32015-09-24 14:16:02 +000075static void add32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
76
Rafael Espindolac4010882015-09-22 20:54:08 +000077void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
78 uint64_t BaseAddr, uint64_t SymVA) const {
79 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
80 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
81
82 uint32_t Offset = Rel.r_offset;
83 uint8_t *Location = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +000084 switch (Type) {
85 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;
100}
Rafael Espindola01205f72015-09-22 18:19:46 +0000101
102void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
103 uint64_t PltEntryAddr) const {
104 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
105 memcpy(Buf, Jmp.data(), Jmp.size());
106 Buf += Jmp.size();
107
108 uintptr_t NextPC = PltEntryAddr + 6;
Rafael Espindola8c21fad2015-09-22 20:06:19 +0000109 intptr_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +0000110 assert(isInt<32>(Delta));
Rafael Espindola0872ea32015-09-24 14:16:02 +0000111 write32le(Buf, Delta);
Rafael Espindola01205f72015-09-22 18:19:46 +0000112 Buf += 4;
113
114 ArrayRef<uint8_t> Nops = {0x90, 0x90};
115 memcpy(Buf, Nops.data(), Nops.size());
116}
117
118bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
119 if (relocNeedsPlt(Type))
120 return true;
121 switch (Type) {
122 default:
123 return false;
124 case R_X86_64_GOTPCREL:
125 return true;
126 }
127}
128
129bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
130 switch (Type) {
131 default:
132 return false;
133 case R_X86_64_PLT32:
134 return true;
135 }
136}
Rafael Espindolac4010882015-09-22 20:54:08 +0000137
138void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
139 uint32_t Type, uint64_t BaseAddr,
140 uint64_t SymVA) const {
141 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
142 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
143
144 uint64_t Offset = Rel.r_offset;
145 uint8_t *Location = Buf + Offset;
146 switch (Type) {
147 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000148 case R_X86_64_GOTPCREL:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000149 write32le(Location, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000150 break;
151 case R_X86_64_64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000152 write64le(Location, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000153 break;
154 case R_X86_64_32: {
155 case R_X86_64_32S:
156 uint64_t VA = SymVA + Rel.r_addend;
157 if (Type == R_X86_64_32 && !isUInt<32>(VA))
158 error("R_X86_64_32 out of range");
159 else if (!isInt<32>(VA))
160 error("R_X86_64_32S out of range");
161
Rafael Espindola0872ea32015-09-24 14:16:02 +0000162 write32le(Location, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000163 break;
164 }
165 default:
166 error(Twine("unrecognized reloc ") + Twine(Type));
167 break;
168 }
169}
170
171PPC64TargetInfo::PPC64TargetInfo() {
172 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000173 // GotReloc = FIXME
Rafael Espindolac4010882015-09-22 20:54:08 +0000174}
175void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
176 uint64_t PltEntryAddr) const {}
177bool PPC64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
178bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
179void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000180 uint64_t BaseAddr, uint64_t SymVA) const {
181 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
182 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
183
184 uint64_t Offset = Rel.r_offset;
185 uint8_t *Location = Buf + Offset;
186 switch (Type) {
187 case R_PPC64_ADDR64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000188 write64be(Location, SymVA + Rel.r_addend);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000189 break;
190 case R_PPC64_TOC:
191 // We don't create a TOC yet.
192 break;
193 default:
194 error(Twine("unrecognized reloc ") + Twine(Type));
195 break;
196 }
197}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000198
199PPCTargetInfo::PPCTargetInfo() {
200 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000201 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000202}
203void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
204 uint64_t PltEntryAddr) const {}
205bool PPCTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
206bool PPCTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
207void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
208 uint64_t BaseAddr, uint64_t SymVA) const {}
209
210ARMTargetInfo::ARMTargetInfo() {
211 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000212 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000213}
214void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
215 uint64_t PltEntryAddr) const {}
216bool ARMTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
217bool ARMTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
218void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
219 uint64_t BaseAddr, uint64_t SymVA) 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,
Davide Italiano1d750a62015-09-27 08:45:38 +0000244 uint64_t SymVA) const {
245 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,
276 uint64_t BaseAddr, uint64_t SymVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000277}
278}