blob: 1536d4a8770c497eda7054d70526f7bc397e9279 [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 {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000214}
215}