blob: b2560960fd1bb8d52650aa875414abe2b97974d6 [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
29X86TargetInfo::X86TargetInfo() { PCRelReloc = R_386_PC32; }
30
31void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
32 uint64_t PltEntryAddr) const {
33 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpl *val
34 memcpy(Buf, Jmp.data(), Jmp.size());
35 Buf += Jmp.size();
36
37 assert(isUInt<32>(GotEntryAddr));
38 support::endian::write32le(Buf, GotEntryAddr);
39 Buf += 4;
40
41 ArrayRef<uint8_t> Nops = {0x90, 0x90};
42 memcpy(Buf, Nops.data(), Nops.size());
43}
44
45bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
46 if (relocNeedsPlt(Type))
47 return true;
48 switch (Type) {
49 default:
50 return false;
51 case R_386_GOT32:
52 return true;
53 }
54}
55
56bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
57 switch (Type) {
58 default:
59 return false;
60 case R_386_PLT32:
61 return true;
62 }
63}
64
Rafael Espindolac4010882015-09-22 20:54:08 +000065void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
66 uint64_t BaseAddr, uint64_t SymVA) const {
67 typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
68 auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
69
70 uint32_t Offset = Rel.r_offset;
71 uint8_t *Location = Buf + Offset;
72 uint32_t Addend = *(support::ulittle32_t *)Location;
73 switch (Type) {
74 case R_386_PC32:
75 support::endian::write32le(Location, SymVA + Addend - (BaseAddr + Offset));
76 break;
77 case R_386_32:
78 support::endian::write32le(Location, SymVA + Addend);
79 break;
80 default:
81 error(Twine("unrecognized reloc ") + Twine(Type));
82 break;
83 }
84}
85
Rafael Espindola01205f72015-09-22 18:19:46 +000086X86_64TargetInfo::X86_64TargetInfo() { PCRelReloc = R_X86_64_PC32; }
87
88void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
89 uint64_t PltEntryAddr) const {
90 ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
91 memcpy(Buf, Jmp.data(), Jmp.size());
92 Buf += Jmp.size();
93
94 uintptr_t NextPC = PltEntryAddr + 6;
Rafael Espindola8c21fad2015-09-22 20:06:19 +000095 intptr_t Delta = GotEntryAddr - NextPC;
Rafael Espindola01205f72015-09-22 18:19:46 +000096 assert(isInt<32>(Delta));
97 support::endian::write32le(Buf, Delta);
98 Buf += 4;
99
100 ArrayRef<uint8_t> Nops = {0x90, 0x90};
101 memcpy(Buf, Nops.data(), Nops.size());
102}
103
104bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
105 if (relocNeedsPlt(Type))
106 return true;
107 switch (Type) {
108 default:
109 return false;
110 case R_X86_64_GOTPCREL:
111 return true;
112 }
113}
114
115bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
116 switch (Type) {
117 default:
118 return false;
119 case R_X86_64_PLT32:
120 return true;
121 }
122}
Rafael Espindolac4010882015-09-22 20:54:08 +0000123
124void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
125 uint32_t Type, uint64_t BaseAddr,
126 uint64_t SymVA) const {
127 typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
128 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
129
130 uint64_t Offset = Rel.r_offset;
131 uint8_t *Location = Buf + Offset;
132 switch (Type) {
133 case R_X86_64_PC32:
134 support::endian::write32le(Location,
135 SymVA + Rel.r_addend - (BaseAddr + Offset));
136 break;
137 case R_X86_64_64:
138 support::endian::write64le(Location, SymVA + Rel.r_addend);
139 break;
140 case R_X86_64_32: {
141 case R_X86_64_32S:
142 uint64_t VA = SymVA + Rel.r_addend;
143 if (Type == R_X86_64_32 && !isUInt<32>(VA))
144 error("R_X86_64_32 out of range");
145 else if (!isInt<32>(VA))
146 error("R_X86_64_32S out of range");
147
148 support::endian::write32le(Location, VA);
149 break;
150 }
151 default:
152 error(Twine("unrecognized reloc ") + Twine(Type));
153 break;
154 }
155}
156
157PPC64TargetInfo::PPC64TargetInfo() {
158 // PCRelReloc = FIXME
159}
160void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
161 uint64_t PltEntryAddr) const {}
162bool PPC64TargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
163bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
164void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
Rafael Espindola3efa4e92015-09-22 21:12:55 +0000165 uint64_t BaseAddr, uint64_t SymVA) const {
166 typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
167 auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
168
169 uint64_t Offset = Rel.r_offset;
170 uint8_t *Location = Buf + Offset;
171 switch (Type) {
172 case R_PPC64_ADDR64:
173 support::endian::write64be(Location, SymVA + Rel.r_addend);
174 break;
175 case R_PPC64_TOC:
176 // We don't create a TOC yet.
177 break;
178 default:
179 error(Twine("unrecognized reloc ") + Twine(Type));
180 break;
181 }
182}
Rafael Espindola1d6063e2015-09-22 21:24:52 +0000183
184PPCTargetInfo::PPCTargetInfo() {
185 // PCRelReloc = FIXME
186}
187void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
188 uint64_t PltEntryAddr) const {}
189bool PPCTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
190bool PPCTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
191void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
192 uint64_t BaseAddr, uint64_t SymVA) const {}
193
194ARMTargetInfo::ARMTargetInfo() {
195 // PCRelReloc = FIXME
196}
197void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
198 uint64_t PltEntryAddr) const {}
199bool ARMTargetInfo::relocNeedsGot(uint32_t Type) const { return false; }
200bool ARMTargetInfo::relocNeedsPlt(uint32_t Type) const { return false; }
201void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
202 uint64_t BaseAddr, uint64_t SymVA) const {}
Rafael Espindola01205f72015-09-22 18:19:46 +0000203}
204}