xref: /llvm-project-15.0.7/lld/ELF/Target.cpp (revision d2793a03)
1 //===- 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"
11 #include "Error.h"
12 #include "Symbols.h"
13 
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/Object/ELF.h"
16 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/ELF.h"
18 
19 using namespace llvm;
20 using namespace llvm::object;
21 using namespace llvm::support::endian;
22 using namespace llvm::ELF;
23 
24 namespace lld {
25 namespace elf2 {
26 
27 std::unique_ptr<TargetInfo> Target;
28 
29 TargetInfo::~TargetInfo() {}
30 
31 bool TargetInfo::relocPointsToGot(uint32_t Type) const { return false; }
32 
33 bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
34 
35 X86TargetInfo::X86TargetInfo() {
36   PCRelReloc = R_386_PC32;
37   GotReloc = R_386_GLOB_DAT;
38   GotRefReloc = R_386_GOT32;
39 }
40 
41 void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
42                                   uint64_t PltEntryAddr) const {
43   // jmpl *val; nop; nop
44   const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
45   memcpy(Buf, Inst, sizeof(Inst));
46   assert(isUInt<32>(GotEntryAddr));
47   write32le(Buf + 2, GotEntryAddr);
48 }
49 
50 bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
51   return Type == R_386_GOT32 || relocNeedsPlt(Type, S);
52 }
53 
54 bool X86TargetInfo::relocPointsToGot(uint32_t Type) const {
55   return Type == R_386_GOTPC;
56 }
57 
58 bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
59   return Type == R_386_PLT32;
60 }
61 
62 static void add32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
63 
64 void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
65                                 uint64_t BaseAddr, uint64_t SymVA,
66                                 uint64_t GotVA) 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   switch (Type) {
73   case R_386_GOT32:
74     add32le(Location, SymVA - GotVA);
75     break;
76   case R_386_PC32:
77     add32le(Location, SymVA - (BaseAddr + Offset));
78     break;
79   case R_386_32:
80     add32le(Location, SymVA);
81     break;
82   default:
83     error(Twine("unrecognized reloc ") + Twine(Type));
84     break;
85   }
86 }
87 
88 X86_64TargetInfo::X86_64TargetInfo() {
89   PCRelReloc = R_X86_64_PC32;
90   GotReloc = R_X86_64_GLOB_DAT;
91   GotRefReloc = R_X86_64_PC32;
92   RelativeReloc = R_X86_64_RELATIVE;
93 }
94 
95 void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
96                                      uint64_t PltEntryAddr) const {
97   // jmpq *val(%rip); nop; nop
98   const uint8_t Inst[] = {0xff, 0x25, 0, 0, 0, 0, 0x90, 0x90};
99   memcpy(Buf, Inst, sizeof(Inst));
100 
101   uint64_t NextPC = PltEntryAddr + 6;
102   int64_t Delta = GotEntryAddr - NextPC;
103   assert(isInt<32>(Delta));
104   write32le(Buf + 2, Delta);
105 }
106 
107 bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
108   return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S);
109 }
110 
111 bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
112   switch (Type) {
113   default:
114     return false;
115   case R_X86_64_PC32:
116     // This relocation is defined to have a value of (S + A - P).
117     // The problems start when a non PIC program calls a function in a shared
118     // library.
119     // In an ideal world, we could just report an error saying the relocation
120     // can overflow at runtime.
121     // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
122     // libc.so.
123     //
124     // The general idea on how to handle such cases is to create a PLT entry
125     // and use that as the function value.
126     //
127     // For the static linking part, we just return true and everything else
128     // will use the the PLT entry as the address.
129     //
130     // The remaining (unimplemented) problem is making sure pointer equality
131     // still works. We need the help of the dynamic linker for that. We
132     // let it know that we have a direct reference to a so symbol by creating
133     // an undefined symbol with a non zero st_value. Seeing that, the
134     // dynamic linker resolves the symbol to the value of the symbol we created.
135     // This is true even for got entries, so pointer equality is maintained.
136     // To avoid an infinite loop, the only entry that points to the
137     // real function is a dedicated got entry used by the plt. That is
138     // identified by special relocation types (R_X86_64_JUMP_SLOT,
139     // R_386_JMP_SLOT, etc).
140     return S.isShared();
141   case R_X86_64_PLT32:
142     return true;
143   }
144 }
145 
146 bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
147   switch (Type) {
148   default:
149     return false;
150   case R_X86_64_PC64:
151   case R_X86_64_PC32:
152   case R_X86_64_PC16:
153   case R_X86_64_PC8:
154     return true;
155   }
156 }
157 
158 void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
159                                    uint32_t Type, uint64_t BaseAddr,
160                                    uint64_t SymVA, uint64_t GotVA) const {
161   typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
162   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
163 
164   uint64_t Offset = Rel.r_offset;
165   uint8_t *Location = Buf + Offset;
166   switch (Type) {
167   case R_X86_64_PC32:
168   case R_X86_64_GOTPCREL:
169     write32le(Location, SymVA + Rel.r_addend - (BaseAddr + Offset));
170     break;
171   case R_X86_64_64:
172     write64le(Location, SymVA + Rel.r_addend);
173     break;
174   case R_X86_64_32: {
175   case R_X86_64_32S:
176     uint64_t VA = SymVA + Rel.r_addend;
177     if (Type == R_X86_64_32 && !isUInt<32>(VA))
178       error("R_X86_64_32 out of range");
179     else if (!isInt<32>(VA))
180       error("R_X86_64_32S out of range");
181 
182     write32le(Location, VA);
183     break;
184   }
185   default:
186     error(Twine("unrecognized reloc ") + Twine(Type));
187     break;
188   }
189 }
190 
191 PPC64TargetInfo::PPC64TargetInfo() {
192   // PCRelReloc = FIXME
193   // GotReloc = FIXME
194 }
195 void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
196                                     uint64_t PltEntryAddr) const {}
197 bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
198   return false;
199 }
200 bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
201   return false;
202 }
203 void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
204                                   uint64_t BaseAddr, uint64_t SymVA,
205                                   uint64_t GotVA) const {
206   typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
207   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
208 
209   uint64_t Offset = Rel.r_offset;
210   uint8_t *Location = Buf + Offset;
211   switch (Type) {
212   case R_PPC64_ADDR64:
213     write64be(Location, SymVA + Rel.r_addend);
214     break;
215   case R_PPC64_TOC:
216     // We don't create a TOC yet.
217     break;
218   default:
219     error(Twine("unrecognized reloc ") + Twine(Type));
220     break;
221   }
222 }
223 
224 PPCTargetInfo::PPCTargetInfo() {
225   // PCRelReloc = FIXME
226   // GotReloc = FIXME
227 }
228 void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
229                                   uint64_t PltEntryAddr) const {}
230 bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
231   return false;
232 }
233 bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
234   return false;
235 }
236 void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
237                                 uint64_t BaseAddr, uint64_t SymVA,
238                                 uint64_t GotVA) const {}
239 
240 ARMTargetInfo::ARMTargetInfo() {
241   // PCRelReloc = FIXME
242   // GotReloc = FIXME
243 }
244 void ARMTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
245                                   uint64_t PltEntryAddr) const {}
246 bool ARMTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
247   return false;
248 }
249 bool ARMTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
250   return false;
251 }
252 void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
253                                 uint64_t BaseAddr, uint64_t SymVA,
254                                 uint64_t GotVA) const {}
255 
256 AArch64TargetInfo::AArch64TargetInfo() {
257   // PCRelReloc = FIXME
258   // GotReloc = FIXME
259 }
260 void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
261                                       uint64_t PltEntryAddr) const {}
262 bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
263                                       const SymbolBody &S) const {
264   return false;
265 }
266 bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
267                                       const SymbolBody &S) const {
268   return false;
269 }
270 
271 static void AArch64UpdateAdr(uint8_t *Location, uint64_t Imm) {
272   uint32_t ImmLo = (Imm & 0x3) << 29;
273   uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
274   uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
275   write32le(Location, (read32le(Location) & ~Mask) | ImmLo | ImmHi);
276 }
277 
278 // Page(Expr) is the page address of the expression Expr, defined
279 // as (Expr & ~0xFFF). (This applies even if the machine page size
280 // supported by the platform has a different value.)
281 static uint64_t AArch64GetPage(uint64_t Expr) {
282   return Expr & (~static_cast<uint64_t>(0xFFF));
283 }
284 
285 static void handle_ABS16(uint8_t *Location, uint64_t S, int64_t A) {
286   uint64_t X = S + A;
287   if (!isInt<16>(X)) // -2^15 <= X < 2^16
288     error("Relocation R_AARCH64_ABS16 out of range");
289   write16le(Location, read16le(Location) | X);
290 }
291 
292 static void handle_ABS32(uint8_t *Location, uint64_t S, int64_t A) {
293   uint64_t X = S + A;
294   if (!isInt<32>(X)) // -2^31 <= X < 2^32
295     error("Relocation R_AARCH64_ABS32 out of range");
296   write32le(Location, read32le(Location) | X);
297 }
298 
299 static void handle_ABS64(uint8_t *Location, uint64_t S, int64_t A) {
300   uint64_t X = S + A;
301   // No overflow check.
302   write64le(Location, read64le(Location) | X);
303 }
304 
305 static void handle_ADD_ABS_LO12_NC(uint8_t *Location, uint64_t S, int64_t A) {
306   // No overflow check.
307   uint64_t X = ((S + A) & 0xFFF) << 10;
308   write32le(Location, read32le(Location) | X);
309 }
310 
311 static void handle_ADR_PREL_LO21(uint8_t *Location, uint64_t S, int64_t A,
312                                  uint64_t P) {
313   uint64_t X = S + A - P;
314   if (!isInt<21>(X))
315     error("Relocation R_AARCH64_ADR_PREL_LO21 out of range");
316   AArch64UpdateAdr(Location, X & 0x1FFFFF);
317 }
318 
319 static void handle_ADR_PREL_PG_HI21(uint8_t *Location, uint64_t S, int64_t A,
320                                     uint64_t P) {
321   uint64_t X = AArch64GetPage(S + A) - AArch64GetPage(P);
322   if (!isInt<33>(X))
323     error("Relocation R_AARCH64_ADR_PREL_PG_HI21 out of range");
324   AArch64UpdateAdr(Location, (X >> 12) & 0x1FFFFF); // X[32:12]
325 }
326 
327 void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
328                                     uint32_t Type, uint64_t BaseAddr,
329                                     uint64_t SymVA, uint64_t GotVA) const {
330   typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
331   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
332 
333   uint8_t *Location = Buf + Rel.r_offset;
334   uint64_t S = SymVA;
335   int64_t A = Rel.r_addend;
336   uint64_t P = BaseAddr + Rel.r_offset;
337   switch (Type) {
338   case R_AARCH64_ABS16:
339     handle_ABS16(Location, S, A);
340     break;
341   case R_AARCH64_ABS32:
342     handle_ABS32(Location, S, A);
343     break;
344   case R_AARCH64_ABS64:
345     handle_ABS64(Location, S, A);
346     break;
347   case R_AARCH64_ADD_ABS_LO12_NC:
348     handle_ADD_ABS_LO12_NC(Location, S, A);
349     break;
350   case R_AARCH64_ADR_PREL_LO21:
351     handle_ADR_PREL_LO21(Location, S, A, P);
352     break;
353   case R_AARCH64_ADR_PREL_PG_HI21:
354     handle_ADR_PREL_PG_HI21(Location, S, A, P);
355     break;
356   default:
357     error(Twine("unrecognized reloc ") + Twine(Type));
358     break;
359   }
360 }
361 
362 MipsTargetInfo::MipsTargetInfo() {
363   // PCRelReloc = FIXME
364   // GotReloc = FIXME
365   DefaultEntry = "__start";
366 }
367 
368 void MipsTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
369                                    uint64_t PltEntryAddr) const {}
370 
371 bool MipsTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
372   return false;
373 }
374 
375 bool MipsTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
376   return false;
377 }
378 
379 void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
380                                  uint64_t BaseAddr, uint64_t SymVA,
381                                  uint64_t GotVA) const {}
382 }
383 }
384