blob: 56b336face1bcd6617759588e2f2b5c2a30e6fb8 [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
Rui Ueyama87bc41b2015-10-06 18:54:43 +000062static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); }
63static void or16le(uint8_t *L, int16_t V) { write16le(L, read16le(L) | V); }
64static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); }
65static void or64le(uint8_t *L, int64_t V) { write64le(L, read64le(L) | V); }
Rafael Espindola0872ea32015-09-24 14:16:02 +000066
Rafael Espindolac4010882015-09-22 20:54:08 +000067void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +000068 uint64_t BaseAddr, uint64_t SymVA,
69 uint64_t GotVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +000070 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
71 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
72
73 uint32_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +000074 uint8_t *Loc = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +000075 switch (Type) {
Rafael Espindola8acb95c2015-09-29 14:42:37 +000076 case R_386_GOT32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +000077 add32le(Loc, SymVA - GotVA);
Rafael Espindola8acb95c2015-09-29 14:42:37 +000078 break;
Rafael Espindolac4010882015-09-22 20:54:08 +000079 case R_386_PC32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +000080 add32le(Loc, SymVA - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +000081 break;
82 case R_386_32:
Rui Ueyama87bc41b2015-10-06 18:54:43 +000083 add32le(Loc, 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;
Rafael Espindola8acb95c2015-09-29 14:42:37 +000094 GotRefReloc = R_X86_64_PC32;
Rafael Espindolaae244002015-10-05 19:30:12 +000095 RelativeReloc = R_X86_64_RELATIVE;
Rafael Espindola7f074422015-09-22 21:35:51 +000096}
Rafael Espindola01205f72015-09-22 18:19:46 +000097
98void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
99 uint64_t PltEntryAddr) const {
Rui Ueyama1500a902015-09-29 23:00:47 +0000100 // jmpq *val(%rip); nop; nop
101 const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
102 memcpy(Buf, Inst, sizeof(Inst));
Rafael Espindola01205f72015-09-22 18:19:46 +0000103
Rui Ueyamae3fbc892015-09-29 23:25:21 +0000104 uint64_t NextPC = PltEntryAddr + 6;
105 int64_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +0000106 assert(isInt<32>(Delta));
Rui Ueyama1500a902015-09-29 23:00:47 +0000107 write32le(Buf + 2, Delta);
Rafael Espindola01205f72015-09-22 18:19:46 +0000108}
109
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000110bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
Rui Ueyama5ba3ac42015-09-30 01:40:08 +0000111 return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S);
Rafael Espindola01205f72015-09-22 18:19:46 +0000112}
113
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000114bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
Rafael Espindola01205f72015-09-22 18:19:46 +0000115 switch (Type) {
116 default:
117 return false;
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000118 case R_X86_64_PC32:
119 // This relocation is defined to have a value of (S + A - P).
Rafael Espindola3c412e12015-09-30 12:30:58 +0000120 // The problems start when a non PIC program calls a function in a shared
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000121 // library.
Rafael Espindola9a0db7c2015-09-29 23:23:53 +0000122 // In an ideal world, we could just report an error saying the relocation
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000123 // can overflow at runtime.
Rafael Espindola3c412e12015-09-30 12:30:58 +0000124 // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
125 // libc.so.
126 //
127 // The general idea on how to handle such cases is to create a PLT entry
128 // and use that as the function value.
129 //
130 // For the static linking part, we just return true and everything else
131 // will use the the PLT entry as the address.
132 //
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000133 // The remaining (unimplemented) problem is making sure pointer equality
Rafael Espindola3c412e12015-09-30 12:30:58 +0000134 // still works. We need the help of the dynamic linker for that. We
135 // let it know that we have a direct reference to a so symbol by creating
136 // an undefined symbol with a non zero st_value. Seeing that, the
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000137 // dynamic linker resolves the symbol to the value of the symbol we created.
138 // This is true even for got entries, so pointer equality is maintained.
139 // To avoid an infinite loop, the only entry that points to the
Rafael Espindola3c412e12015-09-30 12:30:58 +0000140 // real function is a dedicated got entry used by the plt. That is
141 // identified by special relocation types (R_X86_64_JUMP_SLOT,
142 // R_386_JMP_SLOT, etc).
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000143 return S.isShared();
Rafael Espindola01205f72015-09-22 18:19:46 +0000144 case R_X86_64_PLT32:
145 return true;
146 }
147}
Rafael Espindolac4010882015-09-22 20:54:08 +0000148
Rafael Espindolaae244002015-10-05 19:30:12 +0000149bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
150 switch (Type) {
151 default:
152 return false;
153 case R_X86_64_PC64:
154 case R_X86_64_PC32:
155 case R_X86_64_PC16:
156 case R_X86_64_PC8:
157 return true;
158 }
159}
160
Rafael Espindolac4010882015-09-22 20:54:08 +0000161void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
162 uint32_t Type, uint64_t BaseAddr,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000163 uint64_t SymVA, uint64_t GotVA) const {
Rafael Espindolac4010882015-09-22 20:54:08 +0000164 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
165 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
166
167 uint64_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000168 uint8_t *Loc = Buf + Offset;
Rafael Espindolac4010882015-09-22 20:54:08 +0000169 switch (Type) {
170 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000171 case R_X86_64_GOTPCREL:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000172 write32le(Loc, SymVA + Rel.r_addend - (BaseAddr + Offset));
Rafael Espindolac4010882015-09-22 20:54:08 +0000173 break;
174 case R_X86_64_64:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000175 write64le(Loc, SymVA + Rel.r_addend);
Rafael Espindolac4010882015-09-22 20:54:08 +0000176 break;
177 case R_X86_64_32: {
178 case R_X86_64_32S:
179 uint64_t VA = SymVA + Rel.r_addend;
180 if (Type == R_X86_64_32 && !isUInt<32>(VA))
181 error("R_X86_64_32 out of range");
182 else if (!isInt<32>(VA))
183 error("R_X86_64_32S out of range");
184
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000185 write32le(Loc, VA);
Rafael Espindolac4010882015-09-22 20:54:08 +0000186 break;
187 }
188 default:
189 error(Twine("unrecognized reloc ") + Twine(Type));
190 break;
191 }
192}
193
194PPC64TargetInfo::PPC64TargetInfo() {
195 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000196 // GotReloc = FIXME
Rafael Espindolac4010882015-09-22 20:54:08 +0000197}
198void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
199 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000200bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
201 return false;
202}
203bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
204 return false;
205}
Rafael Espindolac4010882015-09-22 20:54:08 +0000206void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000207 uint64_t BaseAddr, uint64_t SymVA,
208 uint64_t GotVA) const {
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000209 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
210 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
211
212 uint64_t Offset = Rel.r_offset;
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000213 uint8_t *Loc = Buf + Offset;
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000214 switch (Type) {
215 case R_PPC64_ADDR64:
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000216 write64be(Loc, SymVA + Rel.r_addend);
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000217 break;
218 case R_PPC64_TOC:
219 // We don't create a TOC yet.
220 break;
221 default:
222 error(Twine("unrecognized reloc ") + Twine(Type));
223 break;
224 }
225}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000226
227PPCTargetInfo::PPCTargetInfo() {
228 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000229 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000230}
231void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
232 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000233bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
234 return false;
235}
236bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
237 return false;
238}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000239void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000240 uint64_t BaseAddr, uint64_t SymVA,
241 uint64_t GotVA) const {}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000242
243ARMTargetInfo::ARMTargetInfo() {
244 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000245 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000246}
247void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
248 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000249bool ARMTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
250 return false;
251}
252bool ARMTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
253 return false;
254}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000255void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000256 uint64_t BaseAddr, uint64_t SymVA,
257 uint64_t GotVA) const {}
Davide Italianocde93362015-09-26 00:32:04 +0000258
259AArch64TargetInfo::AArch64TargetInfo() {
260 // PCRelReloc = FIXME
261 // GotReloc = FIXME
262}
263void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
264 uint64_t PltEntryAddr) const {}
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000265bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
266 const SymbolBody &S) const {
267 return false;
268}
269bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
270 const SymbolBody &S) const {
271 return false;
272}
Davide Italiano1d750a62015-09-27 08:45:38 +0000273
Davide Italianoef4be6b2015-10-06 19:01:32 +0000274static void updateAArch64Adr(uint8_t *L, uint64_t Imm) {
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000275 uint32_t ImmLo = (Imm & 0x3) << 29;
276 uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
277 uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
Rui Ueyama87bc41b2015-10-06 18:54:43 +0000278 write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000279}
280
Davide Italiano318ca222015-10-02 22:13:51 +0000281// Page(Expr) is the page address of the expression Expr, defined
282// as (Expr & ~0xFFF). (This applies even if the machine page size
Davide Italianod9b5be42015-10-02 22:17:09 +0000283// supported by the platform has a different value.)
Davide Italianoef4be6b2015-10-06 19:01:32 +0000284static uint64_t getAArch64Page(uint64_t Expr) {
Davide Italiano318ca222015-10-02 22:13:51 +0000285 return Expr & (~static_cast<uint64_t>(0xFFF));
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000286}
287
Davide Italianocde93362015-09-26 00:32:04 +0000288void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
289 uint32_t Type, uint64_t BaseAddr,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000290 uint64_t SymVA, uint64_t GotVA) const {
Davide Italiano1d750a62015-09-27 08:45:38 +0000291 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
292 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
293
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000294 uint8_t *L = Buf + Rel.r_offset;
Davide Italiano1d750a62015-09-27 08:45:38 +0000295 uint64_t S = SymVA;
296 int64_t A = Rel.r_addend;
297 uint64_t P = BaseAddr + Rel.r_offset;
298 switch (Type) {
Davide Italianodf88f962015-10-04 00:59:16 +0000299 case R_AARCH64_ABS16:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000300 if (!isInt<16>(S + A))
301 error("Relocation R_AARCH64_ABS16 out of range");
302 or16le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000303 break;
304 case R_AARCH64_ABS32:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000305 if (!isInt<32>(S + A))
306 error("Relocation R_AARCH64_ABS32 out of range");
307 or32le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000308 break;
309 case R_AARCH64_ABS64:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000310 // No overflow check needed.
311 or64le(L, S + A);
Davide Italianodf88f962015-10-04 00:59:16 +0000312 break;
Davide Italiano0b6974b2015-10-03 19:56:07 +0000313 case R_AARCH64_ADD_ABS_LO12_NC:
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000314 // No overflow check needed.
315 or32le(L, ((S + A) & 0xFFF) << 10);
Davide Italiano0b6974b2015-10-03 19:56:07 +0000316 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000317 case R_AARCH64_ADR_PREL_LO21: {
318 uint64_t X = S + A - P;
319 if (!isInt<21>(X))
320 error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
321 updateAArch64Adr(L, X & 0x1FFFFF);
Davide Italiano1d750a62015-09-27 08:45:38 +0000322 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000323 }
324 case R_AARCH64_ADR_PREL_PG_HI21: {
325 uint64_t X = getAArch64Page(S + A) - getAArch64Page(P);
326 if (!isInt<33>(X))
327 error("Relocation R_AARCH64_ADR_PREL_PG_HI21 out of range");
328 updateAArch64Adr(L, (X >> 12) & 0x1FFFFF); // X[32:12]
Davide Italiano1f31a2c2015-10-02 22:00:42 +0000329 break;
Rui Ueyamaee8c53b2015-10-06 19:57:01 +0000330 }
Davide Italiano1d750a62015-09-27 08:45:38 +0000331 default:
332 error(Twine("unrecognized reloc ") + Twine(Type));
333 break;
334 }
335}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000336
337MipsTargetInfo::MipsTargetInfo() {
338 // PCRelReloc = FIXME
339 // GotReloc = FIXME
340 DefaultEntry = "__start";
341}
342
343void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
344 uint64_t PltEntryAddr) const {}
345
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000346bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
347 return false;
348}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000349
Rafael Espindola3ef3a4c2015-09-29 23:22:16 +0000350bool MipsTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
351 return false;
352}
Simon Atanasyan49829a12015-09-29 05:34:03 +0000353
354void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola8acb95c2015-09-29 14:42:37 +0000355 uint64_t BaseAddr, uint64_t SymVA,
356 uint64_t GotVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000357}
358}