1 //===- Thunks.cpp --------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===---------------------------------------------------------------------===// 8 // 9 // This file contains Thunk subclasses. 10 // 11 // A thunk is a small piece of code written after an input section 12 // which is used to jump between "incompatible" functions 13 // such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions. 14 // 15 // If a jump target is too far and its address doesn't fit to a 16 // short jump instruction, we need to create a thunk too, but we 17 // haven't supported it yet. 18 // 19 // i386 and x86-64 don't need thunks. 20 // 21 //===---------------------------------------------------------------------===// 22 23 #include "Thunks.h" 24 #include "Config.h" 25 #include "InputSection.h" 26 #include "OutputSections.h" 27 #include "Symbols.h" 28 #include "SyntheticSections.h" 29 #include "Target.h" 30 #include "lld/Common/ErrorHandler.h" 31 #include "lld/Common/Memory.h" 32 #include "llvm/BinaryFormat/ELF.h" 33 #include "llvm/Support/Casting.h" 34 #include "llvm/Support/Endian.h" 35 #include "llvm/Support/ErrorHandling.h" 36 #include "llvm/Support/MathExtras.h" 37 #include <cstdint> 38 #include <cstring> 39 40 using namespace llvm; 41 using namespace llvm::object; 42 using namespace llvm::ELF; 43 44 namespace lld { 45 namespace elf { 46 47 namespace { 48 49 // AArch64 long range Thunks 50 class AArch64ABSLongThunk final : public Thunk { 51 public: 52 AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {} 53 uint32_t size() override { return 16; } 54 void writeTo(uint8_t *Buf) override; 55 void addSymbols(ThunkSection &IS) override; 56 }; 57 58 class AArch64ADRPThunk final : public Thunk { 59 public: 60 AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {} 61 uint32_t size() override { return 12; } 62 void writeTo(uint8_t *Buf) override; 63 void addSymbols(ThunkSection &IS) override; 64 }; 65 66 // Base class for ARM thunks. 67 // 68 // An ARM thunk may be either short or long. A short thunk is simply a branch 69 // (B) instruction, and it may be used to call ARM functions when the distance 70 // from the thunk to the target is less than 32MB. Long thunks can branch to any 71 // virtual address and can switch between ARM and Thumb, and they are 72 // implemented in the derived classes. This class tries to create a short thunk 73 // if the target is in range, otherwise it creates a long thunk. 74 class ARMThunk : public Thunk { 75 public: 76 ARMThunk(Symbol &Dest) : Thunk(Dest) {} 77 78 bool mayUseShortThunk(); 79 uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } 80 void writeTo(uint8_t *Buf) override; 81 bool isCompatibleWith(RelType Type) const override; 82 83 // Returns the size of a long thunk. 84 virtual uint32_t sizeLong() = 0; 85 86 // Writes a long thunk to Buf. 87 virtual void writeLong(uint8_t *Buf) = 0; 88 89 private: 90 // This field tracks whether all previously considered layouts would allow 91 // this thunk to be short. If we have ever needed a long thunk, we always 92 // create a long thunk, even if the thunk may be short given the current 93 // distance to the target. We do this because transitioning from long to short 94 // can create layout oscillations in certain corner cases which would prevent 95 // the layout from converging. 96 bool MayUseShortThunk = true; 97 }; 98 99 // Base class for Thumb-2 thunks. 100 // 101 // This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction 102 // which has a range of 16MB. 103 class ThumbThunk : public Thunk { 104 public: 105 ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } 106 107 bool mayUseShortThunk(); 108 uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } 109 void writeTo(uint8_t *Buf) override; 110 bool isCompatibleWith(RelType Type) const override; 111 112 // Returns the size of a long thunk. 113 virtual uint32_t sizeLong() = 0; 114 115 // Writes a long thunk to Buf. 116 virtual void writeLong(uint8_t *Buf) = 0; 117 118 private: 119 // See comment in ARMThunk above. 120 bool MayUseShortThunk = true; 121 }; 122 123 // Specific ARM Thunk implementations. The naming convention is: 124 // Source State, TargetState, Target Requirement, ABS or PI, Range 125 class ARMV7ABSLongThunk final : public ARMThunk { 126 public: 127 ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {} 128 129 uint32_t sizeLong() override { return 12; } 130 void writeLong(uint8_t *Buf) override; 131 void addSymbols(ThunkSection &IS) override; 132 }; 133 134 class ARMV7PILongThunk final : public ARMThunk { 135 public: 136 ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {} 137 138 uint32_t sizeLong() override { return 16; } 139 void writeLong(uint8_t *Buf) override; 140 void addSymbols(ThunkSection &IS) override; 141 }; 142 143 class ThumbV7ABSLongThunk final : public ThumbThunk { 144 public: 145 ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {} 146 147 uint32_t sizeLong() override { return 10; } 148 void writeLong(uint8_t *Buf) override; 149 void addSymbols(ThunkSection &IS) override; 150 }; 151 152 class ThumbV7PILongThunk final : public ThumbThunk { 153 public: 154 ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {} 155 156 uint32_t sizeLong() override { return 12; } 157 void writeLong(uint8_t *Buf) override; 158 void addSymbols(ThunkSection &IS) override; 159 }; 160 161 // Implementations of Thunks for older Arm architectures that do not support 162 // the movt/movw instructions. These thunks require at least Architecture v5 163 // as used on processors such as the Arm926ej-s. There are no Thumb entry 164 // points as there is no Thumb branch instruction on these architecture that 165 // can result in a thunk 166 class ARMV5ABSLongThunk final : public ARMThunk { 167 public: 168 ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {} 169 170 uint32_t sizeLong() override { return 8; } 171 void writeLong(uint8_t *Buf) override; 172 void addSymbols(ThunkSection &IS) override; 173 bool isCompatibleWith(uint32_t RelocType) const override; 174 }; 175 176 class ARMV5PILongThunk final : public ARMThunk { 177 public: 178 ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {} 179 180 uint32_t sizeLong() override { return 16; } 181 void writeLong(uint8_t *Buf) override; 182 void addSymbols(ThunkSection &IS) override; 183 bool isCompatibleWith(uint32_t RelocType) const override; 184 }; 185 186 // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted 187 class ThumbV6MABSLongThunk final : public ThumbThunk { 188 public: 189 ThumbV6MABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {} 190 191 uint32_t sizeLong() override { return 12; } 192 void writeLong(uint8_t *Buf) override; 193 void addSymbols(ThunkSection &IS) override; 194 }; 195 196 class ThumbV6MPILongThunk final : public ThumbThunk { 197 public: 198 ThumbV6MPILongThunk(Symbol &Dest) : ThumbThunk(Dest) {} 199 200 uint32_t sizeLong() override { return 16; } 201 void writeLong(uint8_t *Buf) override; 202 void addSymbols(ThunkSection &IS) override; 203 }; 204 205 // MIPS LA25 thunk 206 class MipsThunk final : public Thunk { 207 public: 208 MipsThunk(Symbol &Dest) : Thunk(Dest) {} 209 210 uint32_t size() override { return 16; } 211 void writeTo(uint8_t *Buf) override; 212 void addSymbols(ThunkSection &IS) override; 213 InputSection *getTargetInputSection() const override; 214 }; 215 216 // microMIPS R2-R5 LA25 thunk 217 class MicroMipsThunk final : public Thunk { 218 public: 219 MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {} 220 221 uint32_t size() override { return 14; } 222 void writeTo(uint8_t *Buf) override; 223 void addSymbols(ThunkSection &IS) override; 224 InputSection *getTargetInputSection() const override; 225 }; 226 227 // microMIPS R6 LA25 thunk 228 class MicroMipsR6Thunk final : public Thunk { 229 public: 230 MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {} 231 232 uint32_t size() override { return 12; } 233 void writeTo(uint8_t *Buf) override; 234 void addSymbols(ThunkSection &IS) override; 235 InputSection *getTargetInputSection() const override; 236 }; 237 238 239 // PPC64 Plt call stubs. 240 // Any call site that needs to call through a plt entry needs a call stub in 241 // the .text section. The call stub is responsible for: 242 // 1) Saving the toc-pointer to the stack. 243 // 2) Loading the target functions address from the procedure linkage table into 244 // r12 for use by the target functions global entry point, and into the count 245 // register. 246 // 3) Transfering control to the target function through an indirect branch. 247 class PPC64PltCallStub final : public Thunk { 248 public: 249 PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {} 250 uint32_t size() override { return 20; } 251 void writeTo(uint8_t *Buf) override; 252 void addSymbols(ThunkSection &IS) override; 253 }; 254 255 // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte 256 // alignment. This gives a possible 26 bits of 'reach'. If the call offset is 257 // larger then that we need to emit a long-branch thunk. The target address 258 // of the callee is stored in a table to be accessed TOC-relative. Since the 259 // call must be local (a non-local call will have a PltCallStub instead) the 260 // table stores the address of the callee's local entry point. For 261 // position-independent code a corresponding relative dynamic relocation is 262 // used. 263 class PPC64LongBranchThunk : public Thunk { 264 public: 265 uint32_t size() override { return 16; } 266 void writeTo(uint8_t *Buf) override; 267 void addSymbols(ThunkSection &IS) override; 268 269 protected: 270 PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {} 271 }; 272 273 class PPC64PILongBranchThunk final : public PPC64LongBranchThunk { 274 public: 275 PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) { 276 assert(!Dest.IsPreemptible); 277 if (Dest.isInPPC64Branchlt()) 278 return; 279 280 In.PPC64LongBranchTarget->addEntry(Dest); 281 In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget, 282 Dest.getPPC64LongBranchOffset(), true, &Dest, 283 getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)}); 284 } 285 }; 286 287 class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk { 288 public: 289 PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) { 290 if (!Dest.isInPPC64Branchlt()) 291 In.PPC64LongBranchTarget->addEntry(Dest); 292 } 293 }; 294 295 } // end anonymous namespace 296 297 Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value, 298 InputSectionBase &Section) { 299 Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section); 300 Syms.push_back(D); 301 return D; 302 } 303 304 void Thunk::setOffset(uint64_t NewOffset) { 305 for (Defined *D : Syms) 306 D->Value = D->Value - Offset + NewOffset; 307 Offset = NewOffset; 308 } 309 310 // AArch64 long range Thunks 311 312 static uint64_t getAArch64ThunkDestVA(const Symbol &S) { 313 uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA(); 314 return V; 315 } 316 317 void AArch64ABSLongThunk::writeTo(uint8_t *Buf) { 318 const uint8_t Data[] = { 319 0x50, 0x00, 0x00, 0x58, // ldr x16, L0 320 0x00, 0x02, 0x1f, 0xd6, // br x16 321 0x00, 0x00, 0x00, 0x00, // L0: .xword S 322 0x00, 0x00, 0x00, 0x00, 323 }; 324 uint64_t S = getAArch64ThunkDestVA(Destination); 325 memcpy(Buf, Data, sizeof(Data)); 326 Target->relocateOne(Buf + 8, R_AARCH64_ABS64, S); 327 } 328 329 void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { 330 addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), 331 STT_FUNC, 0, IS); 332 addSymbol("$x", STT_NOTYPE, 0, IS); 333 addSymbol("$d", STT_NOTYPE, 8, IS); 334 } 335 336 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs 337 // using the small code model, including pc-relative ones. At time of writing 338 // clang and gcc do not support the large code model for position independent 339 // code so it is safe to use this for position independent thunks without 340 // worrying about the destination being more than 4Gb away. 341 void AArch64ADRPThunk::writeTo(uint8_t *Buf) { 342 const uint8_t Data[] = { 343 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest) 344 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest) 345 0x00, 0x02, 0x1f, 0xd6, // br x16 346 }; 347 uint64_t S = getAArch64ThunkDestVA(Destination); 348 uint64_t P = getThunkTargetSym()->getVA(); 349 memcpy(Buf, Data, sizeof(Data)); 350 Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, 351 getAArch64Page(S) - getAArch64Page(P)); 352 Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S); 353 } 354 355 void AArch64ADRPThunk::addSymbols(ThunkSection &IS) { 356 addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, 357 0, IS); 358 addSymbol("$x", STT_NOTYPE, 0, IS); 359 } 360 361 // ARM Target Thunks 362 static uint64_t getARMThunkDestVA(const Symbol &S) { 363 uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA(); 364 return SignExtend64<32>(V); 365 } 366 367 // This function returns true if the target is not Thumb and is within 2^26, and 368 // it has not previously returned false (see comment for MayUseShortThunk). 369 bool ARMThunk::mayUseShortThunk() { 370 if (!MayUseShortThunk) 371 return false; 372 uint64_t S = getARMThunkDestVA(Destination); 373 if (S & 1) { 374 MayUseShortThunk = false; 375 return false; 376 } 377 uint64_t P = getThunkTargetSym()->getVA(); 378 int64_t Offset = S - P - 8; 379 MayUseShortThunk = llvm::isInt<26>(Offset); 380 return MayUseShortThunk; 381 } 382 383 void ARMThunk::writeTo(uint8_t *Buf) { 384 if (!mayUseShortThunk()) { 385 writeLong(Buf); 386 return; 387 } 388 389 uint64_t S = getARMThunkDestVA(Destination); 390 uint64_t P = getThunkTargetSym()->getVA(); 391 int64_t Offset = S - P - 8; 392 const uint8_t Data[] = { 393 0x00, 0x00, 0x00, 0xea, // b S 394 }; 395 memcpy(Buf, Data, sizeof(Data)); 396 Target->relocateOne(Buf, R_ARM_JUMP24, Offset); 397 } 398 399 bool ARMThunk::isCompatibleWith(RelType Type) const { 400 // Thumb branch relocations can't use BLX 401 return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; 402 } 403 404 // This function returns true if the target is Thumb and is within 2^25, and 405 // it has not previously returned false (see comment for MayUseShortThunk). 406 bool ThumbThunk::mayUseShortThunk() { 407 if (!MayUseShortThunk) 408 return false; 409 uint64_t S = getARMThunkDestVA(Destination); 410 if ((S & 1) == 0) { 411 MayUseShortThunk = false; 412 return false; 413 } 414 uint64_t P = getThunkTargetSym()->getVA() & ~1; 415 int64_t Offset = S - P - 4; 416 MayUseShortThunk = llvm::isInt<25>(Offset); 417 return MayUseShortThunk; 418 } 419 420 void ThumbThunk::writeTo(uint8_t *Buf) { 421 if (!mayUseShortThunk()) { 422 writeLong(Buf); 423 return; 424 } 425 426 uint64_t S = getARMThunkDestVA(Destination); 427 uint64_t P = getThunkTargetSym()->getVA(); 428 int64_t Offset = S - P - 4; 429 const uint8_t Data[] = { 430 0x00, 0xf0, 0x00, 0xb0, // b.w S 431 }; 432 memcpy(Buf, Data, sizeof(Data)); 433 Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset); 434 } 435 436 bool ThumbThunk::isCompatibleWith(RelType Type) const { 437 // ARM branch relocations can't use BLX 438 return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; 439 } 440 441 void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) { 442 const uint8_t Data[] = { 443 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S 444 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S 445 0x1c, 0xff, 0x2f, 0xe1, // bx ip 446 }; 447 uint64_t S = getARMThunkDestVA(Destination); 448 memcpy(Buf, Data, sizeof(Data)); 449 Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S); 450 Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S); 451 } 452 453 void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { 454 addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), 455 STT_FUNC, 0, IS); 456 addSymbol("$a", STT_NOTYPE, 0, IS); 457 } 458 459 void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) { 460 const uint8_t Data[] = { 461 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S 462 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S 463 0x60, 0x47, // bx ip 464 }; 465 uint64_t S = getARMThunkDestVA(Destination); 466 memcpy(Buf, Data, sizeof(Data)); 467 Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S); 468 Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S); 469 } 470 471 void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { 472 addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), 473 STT_FUNC, 1, IS); 474 addSymbol("$t", STT_NOTYPE, 0, IS); 475 } 476 477 void ARMV7PILongThunk::writeLong(uint8_t *Buf) { 478 const uint8_t Data[] = { 479 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8) 480 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8) 481 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 482 0x1c, 0xff, 0x2f, 0xe1, // bx ip 483 }; 484 uint64_t S = getARMThunkDestVA(Destination); 485 uint64_t P = getThunkTargetSym()->getVA(); 486 int64_t Offset = S - P - 16; 487 memcpy(Buf, Data, sizeof(Data)); 488 Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset); 489 Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset); 490 } 491 492 void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { 493 addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, 494 0, IS); 495 addSymbol("$a", STT_NOTYPE, 0, IS); 496 } 497 498 void ThumbV7PILongThunk::writeLong(uint8_t *Buf) { 499 const uint8_t Data[] = { 500 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) 501 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) 502 0xfc, 0x44, // L1: add ip, pc 503 0x60, 0x47, // bx ip 504 }; 505 uint64_t S = getARMThunkDestVA(Destination); 506 uint64_t P = getThunkTargetSym()->getVA() & ~0x1; 507 int64_t Offset = S - P - 12; 508 memcpy(Buf, Data, sizeof(Data)); 509 Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset); 510 Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset); 511 } 512 513 void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { 514 addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), 515 STT_FUNC, 1, IS); 516 addSymbol("$t", STT_NOTYPE, 0, IS); 517 } 518 519 void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) { 520 const uint8_t Data[] = { 521 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 522 0x00, 0x00, 0x00, 0x00, // L1: .word S 523 }; 524 memcpy(Buf, Data, sizeof(Data)); 525 Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination)); 526 } 527 528 void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) { 529 addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()), 530 STT_FUNC, 0, IS); 531 addSymbol("$a", STT_NOTYPE, 0, IS); 532 addSymbol("$d", STT_NOTYPE, 4, IS); 533 } 534 535 bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { 536 // Thumb branch relocations can't use BLX 537 return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; 538 } 539 540 void ARMV5PILongThunk::writeLong(uint8_t *Buf) { 541 const uint8_t Data[] = { 542 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2 543 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip 544 0x1c, 0xff, 0x2f, 0xe1, // bx ip 545 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8) 546 }; 547 uint64_t S = getARMThunkDestVA(Destination); 548 uint64_t P = getThunkTargetSym()->getVA() & ~0x1; 549 memcpy(Buf, Data, sizeof(Data)); 550 Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12); 551 } 552 553 void ARMV5PILongThunk::addSymbols(ThunkSection &IS) { 554 addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC, 555 0, IS); 556 addSymbol("$a", STT_NOTYPE, 0, IS); 557 addSymbol("$d", STT_NOTYPE, 12, IS); 558 } 559 560 bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const { 561 // Thumb branch relocations can't use BLX 562 return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; 563 } 564 565 void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) { 566 // Most Thumb instructions cannot access the high registers r8 - r15. As the 567 // only register we can corrupt is r12 we must instead spill a low register 568 // to the stack to use as a scratch register. We push r1 even though we 569 // don't need to get some space to use for the return address. 570 const uint8_t Data[] = { 571 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers 572 0x01, 0x48, // ldr r0, [pc, #4] ; L1 573 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S 574 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest 575 0x00, 0x00, 0x00, 0x00 // L1: .word S 576 }; 577 uint64_t S = getARMThunkDestVA(Destination); 578 memcpy(Buf, Data, sizeof(Data)); 579 Target->relocateOne(Buf + 8, R_ARM_ABS32, S); 580 } 581 582 void ThumbV6MABSLongThunk::addSymbols(ThunkSection &IS) { 583 addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + Destination.getName()), 584 STT_FUNC, 1, IS); 585 addSymbol("$t", STT_NOTYPE, 0, IS); 586 addSymbol("$d", STT_NOTYPE, 8, IS); 587 } 588 589 void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) { 590 // Most Thumb instructions cannot access the high registers r8 - r15. As the 591 // only register we can corrupt is ip (r12) we must instead spill a low 592 // register to the stack to use as a scratch register. 593 const uint8_t Data[] = { 594 0x01, 0xb4, // P: push {r0} ; Obtain scratch register 595 0x02, 0x48, // ldr r0, [pc, #8] ; L2 596 0x84, 0x46, // mov ip, r0 ; high to low register 597 0x01, 0xbc, // pop {r0} ; restore scratch register 598 0xe7, 0x44, // L1: add pc, ip ; transfer control 599 0xc0, 0x46, // nop ; pad to 4-byte boundary 600 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4) 601 }; 602 uint64_t S = getARMThunkDestVA(Destination); 603 uint64_t P = getThunkTargetSym()->getVA() & ~0x1; 604 memcpy(Buf, Data, sizeof(Data)); 605 Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12); 606 } 607 608 void ThumbV6MPILongThunk::addSymbols(ThunkSection &IS) { 609 addSymbol(Saver.save("__Thumbv6MPILongThunk_" + Destination.getName()), 610 STT_FUNC, 1, IS); 611 addSymbol("$t", STT_NOTYPE, 0, IS); 612 addSymbol("$d", STT_NOTYPE, 12, IS); 613 } 614 615 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. 616 void MipsThunk::writeTo(uint8_t *Buf) { 617 uint64_t S = Destination.getVA(); 618 write32(Buf, 0x3c190000); // lui $25, %hi(func) 619 write32(Buf + 4, 0x08000000 | (S >> 2)); // j func 620 write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func) 621 write32(Buf + 12, 0x00000000); // nop 622 Target->relocateOne(Buf, R_MIPS_HI16, S); 623 Target->relocateOne(Buf + 8, R_MIPS_LO16, S); 624 } 625 626 void MipsThunk::addSymbols(ThunkSection &IS) { 627 addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0, 628 IS); 629 } 630 631 InputSection *MipsThunk::getTargetInputSection() const { 632 auto &DR = cast<Defined>(Destination); 633 return dyn_cast<InputSection>(DR.Section); 634 } 635 636 // Write microMIPS R2-R5 LA25 thunk code 637 // to call PIC function from the non-PIC one. 638 void MicroMipsThunk::writeTo(uint8_t *Buf) { 639 uint64_t S = Destination.getVA(); 640 write16(Buf, 0x41b9); // lui $25, %hi(func) 641 write16(Buf + 4, 0xd400); // j func 642 write16(Buf + 8, 0x3339); // addiu $25, $25, %lo(func) 643 write16(Buf + 12, 0x0c00); // nop 644 Target->relocateOne(Buf, R_MICROMIPS_HI16, S); 645 Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S); 646 Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S); 647 } 648 649 void MicroMipsThunk::addSymbols(ThunkSection &IS) { 650 Defined *D = addSymbol( 651 Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); 652 D->StOther |= STO_MIPS_MICROMIPS; 653 } 654 655 InputSection *MicroMipsThunk::getTargetInputSection() const { 656 auto &DR = cast<Defined>(Destination); 657 return dyn_cast<InputSection>(DR.Section); 658 } 659 660 // Write microMIPS R6 LA25 thunk code 661 // to call PIC function from the non-PIC one. 662 void MicroMipsR6Thunk::writeTo(uint8_t *Buf) { 663 uint64_t S = Destination.getVA(); 664 uint64_t P = getThunkTargetSym()->getVA(); 665 write16(Buf, 0x1320); // lui $25, %hi(func) 666 write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func) 667 write16(Buf + 8, 0x9400); // bc func 668 Target->relocateOne(Buf, R_MICROMIPS_HI16, S); 669 Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S); 670 Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12); 671 } 672 673 void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { 674 Defined *D = addSymbol( 675 Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); 676 D->StOther |= STO_MIPS_MICROMIPS; 677 } 678 679 InputSection *MicroMipsR6Thunk::getTargetInputSection() const { 680 auto &DR = cast<Defined>(Destination); 681 return dyn_cast<InputSection>(DR.Section); 682 } 683 684 static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) { 685 uint16_t OffHa = (Offset + 0x8000) >> 16; 686 uint16_t OffLo = Offset & 0xffff; 687 688 write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa 689 write32(Buf + 4, 0xe98c0000 | OffLo); // ld r12, OffLo(r12) 690 write32(Buf + 8, 0x7d8903a6); // mtctr r12 691 write32(Buf + 12, 0x4e800420); // bctr 692 } 693 694 void PPC64PltCallStub::writeTo(uint8_t *Buf) { 695 int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase(); 696 // Save the TOC pointer to the save-slot reserved in the call frame. 697 write32(Buf + 0, 0xf8410018); // std r2,24(r1) 698 writePPCLoadAndBranch(Buf + 4, Offset); 699 } 700 701 void PPC64PltCallStub::addSymbols(ThunkSection &IS) { 702 Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC, 703 0, IS); 704 S->NeedsTocRestore = true; 705 } 706 707 void PPC64LongBranchThunk::writeTo(uint8_t *Buf) { 708 int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase(); 709 writePPCLoadAndBranch(Buf, Offset); 710 } 711 712 void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) { 713 addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0, 714 IS); 715 } 716 717 Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {} 718 719 Thunk::~Thunk() = default; 720 721 static Thunk *addThunkAArch64(RelType Type, Symbol &S) { 722 if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) 723 fatal("unrecognized relocation type"); 724 if (Config->PicThunk) 725 return make<AArch64ADRPThunk>(S); 726 return make<AArch64ABSLongThunk>(S); 727 } 728 729 // Creates a thunk for Thumb-ARM interworking. 730 // Arm Architectures v5 and v6 do not support Thumb2 technology. This means 731 // - MOVT and MOVW instructions cannot be used 732 // - Only Thumb relocation that can generate a Thunk is a BL, this can always 733 // be transformed into a BLX 734 static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) { 735 switch (Reloc) { 736 case R_ARM_PC24: 737 case R_ARM_PLT32: 738 case R_ARM_JUMP24: 739 case R_ARM_CALL: 740 case R_ARM_THM_CALL: 741 if (Config->PicThunk) 742 return make<ARMV5PILongThunk>(S); 743 return make<ARMV5ABSLongThunk>(S); 744 } 745 fatal("relocation " + toString(Reloc) + " to " + toString(S) + 746 " not supported for Armv5 or Armv6 targets"); 747 } 748 749 // Create a thunk for Thumb long branch on V6-M. 750 // Arm Architecture v6-M only supports Thumb instructions. This means 751 // - MOVT and MOVW instructions cannot be used. 752 // - Only a limited number of instructions can access registers r8 and above 753 // - No interworking support is needed (all Thumb). 754 static Thunk *addThunkV6M(RelType Reloc, Symbol &S) { 755 switch (Reloc) { 756 case R_ARM_THM_JUMP19: 757 case R_ARM_THM_JUMP24: 758 case R_ARM_THM_CALL: 759 if (Config->Pic) 760 return make<ThumbV6MPILongThunk>(S); 761 return make<ThumbV6MABSLongThunk>(S); 762 } 763 fatal("relocation " + toString(Reloc) + " to " + toString(S) + 764 " not supported for Armv6-M targets"); 765 } 766 767 // Creates a thunk for Thumb-ARM interworking or branch range extension. 768 static Thunk *addThunkArm(RelType Reloc, Symbol &S) { 769 // Decide which Thunk is needed based on: 770 // Available instruction set 771 // - An Arm Thunk can only be used if Arm state is available. 772 // - A Thumb Thunk can only be used if Thumb state is available. 773 // - Can only use a Thunk if it uses instructions that the Target supports. 774 // Relocation is branch or branch and link 775 // - Branch instructions cannot change state, can only select Thunk that 776 // starts in the same state as the caller. 777 // - Branch and link relocations can change state, can select Thunks from 778 // either Arm or Thumb. 779 // Position independent Thunks if we require position independent code. 780 781 // Handle architectures that have restrictions on the instructions that they 782 // can use in Thunks. The flags below are set by reading the BuildAttributes 783 // of the input objects. InputFiles.cpp contains the mapping from ARM 784 // architecture to flag. 785 if (!Config->ARMHasMovtMovw) { 786 if (!Config->ARMJ1J2BranchEncoding) 787 return addThunkPreArmv7(Reloc, S); 788 return addThunkV6M(Reloc, S); 789 } 790 791 switch (Reloc) { 792 case R_ARM_PC24: 793 case R_ARM_PLT32: 794 case R_ARM_JUMP24: 795 case R_ARM_CALL: 796 if (Config->PicThunk) 797 return make<ARMV7PILongThunk>(S); 798 return make<ARMV7ABSLongThunk>(S); 799 case R_ARM_THM_JUMP19: 800 case R_ARM_THM_JUMP24: 801 case R_ARM_THM_CALL: 802 if (Config->PicThunk) 803 return make<ThumbV7PILongThunk>(S); 804 return make<ThumbV7ABSLongThunk>(S); 805 } 806 fatal("unrecognized relocation type"); 807 } 808 809 static Thunk *addThunkMips(RelType Type, Symbol &S) { 810 if ((S.StOther & STO_MIPS_MICROMIPS) && isMipsR6()) 811 return make<MicroMipsR6Thunk>(S); 812 if (S.StOther & STO_MIPS_MICROMIPS) 813 return make<MicroMipsThunk>(S); 814 return make<MipsThunk>(S); 815 } 816 817 static Thunk *addThunkPPC64(RelType Type, Symbol &S) { 818 assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk"); 819 if (S.isInPlt()) 820 return make<PPC64PltCallStub>(S); 821 822 if (Config->PicThunk) 823 return make<PPC64PILongBranchThunk>(S); 824 825 return make<PPC64PDLongBranchThunk>(S); 826 } 827 828 Thunk *addThunk(RelType Type, Symbol &S) { 829 if (Config->EMachine == EM_AARCH64) 830 return addThunkAArch64(Type, S); 831 832 if (Config->EMachine == EM_ARM) 833 return addThunkArm(Type, S); 834 835 if (Config->EMachine == EM_MIPS) 836 return addThunkMips(Type, S); 837 838 if (Config->EMachine == EM_PPC64) 839 return addThunkPPC64(Type, S); 840 841 llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC"); 842 } 843 844 } // end namespace elf 845 } // end namespace lld 846