blob: 493b8e7717915fe2f8e9293c45f040d237f9303f [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 Espindola7f074422015-09-22 21:35:51 +000030X86TargetInfo::X86TargetInfo() {
31 PCRelReloc = R_386_PC32;
32 GotReloc = R_386_GLOB_DAT;
33}
Rafael Espindola01205f72015-09-22 18:19:46 +000034
35void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
36 uint64_t PltEntryAddr) const {
37 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpl *val
38 memcpy(Buf, Jmp.data(), Jmp.size());
39 Buf += Jmp.size();
40
41 assert(isUInt<32>(GotEntryAddr));
Rafael Espindola0872ea32015-09-24 14:16:02 +000042 write32le(Buf, GotEntryAddr);
Rafael Espindola01205f72015-09-22 18:19:46 +000043 Buf += 4;
44
45 ArrayRef<uint8_t> Nops = {0x90, 0x90};
46 memcpy(Buf, Nops.data(), Nops.size());
47}
48
49bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
50 if (relocNeedsPlt(Type))
51 return true;
52 switch (Type) {
53 default:
54 return false;
55 case R_386_GOT32:
56 return true;
57 }
58}
59
60bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
61 switch (Type) {
62 default:
63 return false;
64 case R_386_PLT32:
65 return true;
66 }
67}
68
Rafael Espindola0872ea32015-09-24 14:16:02 +000069static void add32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
70
Rafael Espindolac4010882015-09-22 20:54:08 +000071void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
72 uint64_t BaseAddr, uint64_t SymVA) const {
73 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
74 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
75
76 uint32_t Offset = Rel.r_offset;
77 uint8_t *Location = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +000078 switch (Type) {
79 case R_386_PC32:
Rafael Espindola0872ea32015-09-24 14:16:02 +000080 add32le(Location, SymVA - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +000081 break;
82 case R_386_32:
Rafael Espindola0872ea32015-09-24 14:16:02 +000083 add32le(Location, SymVA);
Rafael Espindolac4010882015-09-22 20:54:08 +000084 break;
85 default:
86 error(Twine("unrecognized reloc ") + Twine(Type));
87 break;
88 }
89}
90
Rafael Espindola7f074422015-09-22 21:35:51 +000091X86_64TargetInfo::X86_64TargetInfo() {
92 PCRelReloc = R_X86_64_PC32;
93 GotReloc = R_X86_64_GLOB_DAT;
94}
Rafael Espindola01205f72015-09-22 18:19:46 +000095
96void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
97 uint64_t PltEntryAddr) const {
98 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
99 memcpy(Buf, Jmp.data(), Jmp.size());
100 Buf += Jmp.size();
101
102 uintptr_t NextPC = PltEntryAddr + 6;
Rafael Espindola8c21fad2015-09-22 20:06:19 +0000103 intptr_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +0000104 assert(isInt<32>(Delta));
Rafael Espindola0872ea32015-09-24 14:16:02 +0000105 write32le(Buf, Delta);
Rafael Espindola01205f72015-09-22 18:19:46 +0000106 Buf += 4;
107
108 ArrayRef<uint8_t> Nops = {0x90, 0x90};
109 memcpy(Buf, Nops.data(), Nops.size());
110}
111
112bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
113 if (relocNeedsPlt(Type))
114 return true;
115 switch (Type) {
116 default:
117 return false;
118 case R_X86_64_GOTPCREL:
119 return true;
120 }
121}
122
123bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
124 switch (Type) {
125 default:
126 return false;
127 case R_X86_64_PLT32:
128 return true;
129 }
130}
Rafael Espindolac4010882015-09-22 20:54:08 +0000131
132void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
133 uint32_t Type, uint64_t BaseAddr,
134 uint64_t SymVA) const {
135 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
136 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
137
138 uint64_t Offset = Rel.r_offset;
139 uint8_t *Location = Buf + Offset;
140 switch (Type) {
141 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000142 case R_X86_64_GOTPCREL:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000143 write32le(Location, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000144 break;
145 case R_X86_64_64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000146 write64le(Location, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000147 break;
148 case R_X86_64_32: {
149 case R_X86_64_32S:
150 uint64_t VA = SymVA + Rel.r_addend;
151 if (Type == R_X86_64_32 && !isUInt<32>(VA))
152 error("R_X86_64_32 out of range");
153 else if (!isInt<32>(VA))
154 error("R_X86_64_32S out of range");
155
Rafael Espindola0872ea32015-09-24 14:16:02 +0000156 write32le(Location, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000157 break;
158 }
159 default:
160 error(Twine("unrecognized reloc ") + Twine(Type));
161 break;
162 }
163}
164
165PPC64TargetInfo::PPC64TargetInfo() {
166 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000167 // GotReloc = FIXME
Rafael Espindolac4010882015-09-22 20:54:08 +0000168}
169void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
170 uint64_t PltEntryAddr) const {}
171bool PPC64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
172bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
173void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000174 uint64_t BaseAddr, uint64_t SymVA) const {
175 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
176 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
177
178 uint64_t Offset = Rel.r_offset;
179 uint8_t *Location = Buf + Offset;
180 switch (Type) {
181 case R_PPC64_ADDR64:
Rafael Espindola0872ea32015-09-24 14:16:02 +0000182 write64be(Location, SymVA + Rel.r_addend);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000183 break;
184 case R_PPC64_TOC:
185 // We don't create a TOC yet.
186 break;
187 default:
188 error(Twine("unrecognized reloc ") + Twine(Type));
189 break;
190 }
191}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000192
193PPCTargetInfo::PPCTargetInfo() {
194 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000195 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000196}
197void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
198 uint64_t PltEntryAddr) const {}
199bool PPCTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
200bool PPCTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
201void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
202 uint64_t BaseAddr, uint64_t SymVA) const {}
203
204ARMTargetInfo::ARMTargetInfo() {
205 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000206 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000207}
208void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
209 uint64_t PltEntryAddr) const {}
210bool ARMTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
211bool ARMTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
212void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
213 uint64_t BaseAddr, uint64_t SymVA) const {}
Davide Italianocde93362015-09-26 00:32:04 +0000214
215AArch64TargetInfo::AArch64TargetInfo() {
216 // PCRelReloc = FIXME
217 // GotReloc = FIXME
218}
219void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
220 uint64_t PltEntryAddr) const {}
221bool AArch64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
222bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
Davide Italiano1d750a62015-09-27 08:45:38 +0000223
224static void handle_ADR_PREL_LO21(uint8_t *Location, uint64_t S, int64_t A,
225 uint64_t P) {
226 uint64_t X = S + A - P;
227 if (!isInt<21>(X))
228 error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
229 uint32_t Imm = X & 0x1FFFFF;
230 uint32_t ImmLo = (Imm & 0x3) << 29;
231 uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
232 uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
233 write32le(Location, (read32le(Location) & ~Mask) | ImmLo | ImmHi);
234}
235
Davide Italianocde93362015-09-26 00:32:04 +0000236void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
237 uint32_t Type, uint64_t BaseAddr,
Davide Italiano1d750a62015-09-27 08:45:38 +0000238 uint64_t SymVA) const {
239 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
240 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
241
242 uint8_t *Location = Buf + Rel.r_offset;
243 uint64_t S = SymVA;
244 int64_t A = Rel.r_addend;
245 uint64_t P = BaseAddr + Rel.r_offset;
246 switch (Type) {
247 case R_AARCH64_ADR_PREL_LO21:
248 handle_ADR_PREL_LO21(Location, S, A, P);
249 break;
250 default:
251 error(Twine("unrecognized reloc ") + Twine(Type));
252 break;
253 }
254}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000255
256MipsTargetInfo::MipsTargetInfo() {
257 // PCRelReloc = FIXME
258 // GotReloc = FIXME
259 DefaultEntry = "__start";
260}
261
262void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
263 uint64_t PltEntryAddr) const {}
264
265bool MipsTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
266
267bool MipsTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
268
269void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
270 uint64_t BaseAddr, uint64_t SymVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000271}
272}