blob: ea20ced8956390b786140d4412e2179bb6cd0d31 [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 Espindola01205f72015-09-22 18:19:46 +000020using namespace llvm::ELF;
21
22namespace lld {
23namespace elf2 {
24
25std::unique_ptr<TargetInfo> Target;
26
27TargetInfo::~TargetInfo() {}
28
Rafael Espindola7f074422015-09-22 21:35:51 +000029X86TargetInfo::X86TargetInfo() {
30 PCRelReloc = R_386_PC32;
31 GotReloc = R_386_GLOB_DAT;
32}
Rafael Espindola01205f72015-09-22 18:19:46 +000033
34void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
35 uint64_t PltEntryAddr) const {
36 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpl *val
37 memcpy(Buf, Jmp.data(), Jmp.size());
38 Buf += Jmp.size();
39
40 assert(isUInt<32>(GotEntryAddr));
41 support::endian::write32le(Buf, GotEntryAddr);
42 Buf += 4;
43
44 ArrayRef<uint8_t> Nops = {0x90, 0x90};
45 memcpy(Buf, Nops.data(), Nops.size());
46}
47
48bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
49 if (relocNeedsPlt(Type))
50 return true;
51 switch (Type) {
52 default:
53 return false;
54 case R_386_GOT32:
55 return true;
56 }
57}
58
59bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
60 switch (Type) {
61 default:
62 return false;
63 case R_386_PLT32:
64 return true;
65 }
66}
67
Rafael Espindolac4010882015-09-22 20:54:08 +000068void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
69 uint64_t BaseAddr, uint64_t SymVA) const {
70 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
71 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
72
73 uint32_t Offset = Rel.r_offset;
74 uint8_t *Location = Buf + Offset;
75 uint32_t Addend = *(support::ulittle32_t *)Location;
76 switch (Type) {
77 case R_386_PC32:
78 support::endian::write32le(Location, SymVA + Addend - (BaseAddr + Offset));
79 break;
80 case R_386_32:
81 support::endian::write32le(Location, SymVA + Addend);
82 break;
83 default:
84 error(Twine("unrecognized reloc ") + Twine(Type));
85 break;
86 }
87}
88
Rafael Espindola7f074422015-09-22 21:35:51 +000089X86_64TargetInfo::X86_64TargetInfo() {
90 PCRelReloc = R_X86_64_PC32;
91 GotReloc = R_X86_64_GLOB_DAT;
92}
Rafael Espindola01205f72015-09-22 18:19:46 +000093
94void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
95 uint64_t PltEntryAddr) const {
96 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
97 memcpy(Buf, Jmp.data(), Jmp.size());
98 Buf += Jmp.size();
99
100 uintptr_t NextPC = PltEntryAddr + 6;
Rafael Espindola8c21fad2015-09-22 20:06:19 +0000101 intptr_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +0000102 assert(isInt<32>(Delta));
103 support::endian::write32le(Buf, Delta);
104 Buf += 4;
105
106 ArrayRef<uint8_t> Nops = {0x90, 0x90};
107 memcpy(Buf, Nops.data(), Nops.size());
108}
109
110bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
111 if (relocNeedsPlt(Type))
112 return true;
113 switch (Type) {
114 default:
115 return false;
116 case R_X86_64_GOTPCREL:
117 return true;
118 }
119}
120
121bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
122 switch (Type) {
123 default:
124 return false;
125 case R_X86_64_PLT32:
126 return true;
127 }
128}
Rafael Espindolac4010882015-09-22 20:54:08 +0000129
130void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
131 uint32_t Type, uint64_t BaseAddr,
132 uint64_t SymVA) const {
133 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
134 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
135
136 uint64_t Offset = Rel.r_offset;
137 uint8_t *Location = Buf + Offset;
138 switch (Type) {
139 case R_X86_64_PC32:
Rafael Espindolacdfecff2015-09-23 20:08:25 +0000140 case R_X86_64_GOTPCREL:
Rafael Espindolac4010882015-09-22 20:54:08 +0000141 support::endian::write32le(Location,
142 SymVA + Rel.r_addend - (BaseAddr + Offset));
143 break;
144 case R_X86_64_64:
145 support::endian::write64le(Location, SymVA + Rel.r_addend);
146 break;
147 case R_X86_64_32: {
148 case R_X86_64_32S:
149 uint64_t VA = SymVA + Rel.r_addend;
150 if (Type == R_X86_64_32 && !isUInt<32>(VA))
151 error("R_X86_64_32 out of range");
152 else if (!isInt<32>(VA))
153 error("R_X86_64_32S out of range");
154
155 support::endian::write32le(Location, VA);
156 break;
157 }
158 default:
159 error(Twine("unrecognized reloc ") + Twine(Type));
160 break;
161 }
162}
163
164PPC64TargetInfo::PPC64TargetInfo() {
165 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000166 // GotReloc = FIXME
Rafael Espindolac4010882015-09-22 20:54:08 +0000167}
168void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
169 uint64_t PltEntryAddr) const {}
170bool PPC64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
171bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
172void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000173 uint64_t BaseAddr, uint64_t SymVA) const {
174 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
175 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
176
177 uint64_t Offset = Rel.r_offset;
178 uint8_t *Location = Buf + Offset;
179 switch (Type) {
180 case R_PPC64_ADDR64:
181 support::endian::write64be(Location, SymVA + Rel.r_addend);
182 break;
183 case R_PPC64_TOC:
184 // We don't create a TOC yet.
185 break;
186 default:
187 error(Twine("unrecognized reloc ") + Twine(Type));
188 break;
189 }
190}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000191
192PPCTargetInfo::PPCTargetInfo() {
193 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000194 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000195}
196void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
197 uint64_t PltEntryAddr) const {}
198bool PPCTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
199bool PPCTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
200void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
201 uint64_t BaseAddr, uint64_t SymVA) const {}
202
203ARMTargetInfo::ARMTargetInfo() {
204 // PCRelReloc = FIXME
Rafael Espindola7f074422015-09-22 21:35:51 +0000205 // GotReloc = FIXME
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000206}
207void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
208 uint64_t PltEntryAddr) const {}
209bool ARMTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
210bool ARMTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
211void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
212 uint64_t BaseAddr, uint64_t SymVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000213}
214}