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