1 //===- lib/FileFormat/MachO/ArchHandler_arm.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 "ArchHandler.h" 11 #include "Atoms.h" 12 #include "MachONormalizedFileBinaryUtils.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/StringSwitch.h" 15 #include "llvm/ADT/Triple.h" 16 #include "llvm/Support/Endian.h" 17 #include "llvm/Support/ErrorHandling.h" 18 19 using namespace llvm::MachO; 20 using namespace lld::mach_o::normalized; 21 22 namespace lld { 23 namespace mach_o { 24 25 using llvm::support::ulittle32_t; 26 using llvm::support::little32_t; 27 28 29 class ArchHandler_arm : public ArchHandler { 30 public: 31 ArchHandler_arm() = default; 32 ~ArchHandler_arm() override = default; 33 34 const Registry::KindStrings *kindStrings() override { return _sKindStrings; } 35 36 Reference::KindArch kindArch() override { return Reference::KindArch::ARM; } 37 38 const ArchHandler::StubInfo &stubInfo() override; 39 bool isCallSite(const Reference &) override; 40 bool isPointer(const Reference &) override; 41 bool isPairedReloc(const normalized::Relocation &) override; 42 bool isNonCallBranch(const Reference &) override; 43 44 bool needsCompactUnwind() override { 45 return false; 46 } 47 Reference::KindValue imageOffsetKind() override { 48 return invalid; 49 } 50 Reference::KindValue imageOffsetKindIndirect() override { 51 return invalid; 52 } 53 54 Reference::KindValue unwindRefToPersonalityFunctionKind() override { 55 return invalid; 56 } 57 58 Reference::KindValue unwindRefToCIEKind() override { 59 return invalid; 60 } 61 62 Reference::KindValue unwindRefToFunctionKind() override { 63 return invalid; 64 } 65 66 Reference::KindValue unwindRefToEhFrameKind() override { 67 return invalid; 68 } 69 70 Reference::KindValue pointerKind() override { 71 return invalid; 72 } 73 74 uint32_t dwarfCompactUnwindType() override { 75 // FIXME 76 return -1; 77 } 78 79 llvm::Error getReferenceInfo(const normalized::Relocation &reloc, 80 const DefinedAtom *inAtom, 81 uint32_t offsetInAtom, 82 uint64_t fixupAddress, bool swap, 83 FindAtomBySectionAndAddress atomFromAddress, 84 FindAtomBySymbolIndex atomFromSymbolIndex, 85 Reference::KindValue *kind, 86 const lld::Atom **target, 87 Reference::Addend *addend) override; 88 llvm::Error 89 getPairReferenceInfo(const normalized::Relocation &reloc1, 90 const normalized::Relocation &reloc2, 91 const DefinedAtom *inAtom, 92 uint32_t offsetInAtom, 93 uint64_t fixupAddress, bool swap, bool scatterable, 94 FindAtomBySectionAndAddress atomFromAddress, 95 FindAtomBySymbolIndex atomFromSymbolIndex, 96 Reference::KindValue *kind, 97 const lld::Atom **target, 98 Reference::Addend *addend) override; 99 100 void generateAtomContent(const DefinedAtom &atom, bool relocatable, 101 FindAddressForAtom findAddress, 102 FindAddressForAtom findSectionAddress, 103 uint64_t imageBaseAddress, 104 llvm::MutableArrayRef<uint8_t> atomContentBuffer) override; 105 106 void appendSectionRelocations(const DefinedAtom &atom, 107 uint64_t atomSectionOffset, 108 const Reference &ref, 109 FindSymbolIndexForAtom, 110 FindSectionIndexForAtom, 111 FindAddressForAtom, 112 normalized::Relocations &) override; 113 114 void addAdditionalReferences(MachODefinedAtom &atom) override; 115 116 bool isDataInCodeTransition(Reference::KindValue refKind) override { 117 switch (refKind) { 118 case modeThumbCode: 119 case modeArmCode: 120 case modeData: 121 return true; 122 default: 123 return false; 124 break; 125 } 126 } 127 128 Reference::KindValue dataInCodeTransitionStart( 129 const MachODefinedAtom &atom) override { 130 return modeData; 131 } 132 133 Reference::KindValue dataInCodeTransitionEnd( 134 const MachODefinedAtom &atom) override { 135 return atom.isThumb() ? modeThumbCode : modeArmCode; 136 } 137 138 bool isThumbFunction(const DefinedAtom &atom) override; 139 const DefinedAtom *createShim(MachOFile &file, bool thumbToArm, 140 const DefinedAtom &) override; 141 142 private: 143 friend class Thumb2ToArmShimAtom; 144 friend class ArmToThumbShimAtom; 145 146 static const Registry::KindStrings _sKindStrings[]; 147 static const StubInfo _sStubInfoArmPIC; 148 149 enum ArmKind : Reference::KindValue { 150 invalid, /// for error condition 151 152 modeThumbCode, /// Content starting at this offset is thumb. 153 modeArmCode, /// Content starting at this offset is arm. 154 modeData, /// Content starting at this offset is data. 155 156 // Kinds found in mach-o .o files: 157 thumb_bl22, /// ex: bl _foo 158 thumb_b22, /// ex: b _foo 159 thumb_movw, /// ex: movw r1, :lower16:_foo 160 thumb_movt, /// ex: movt r1, :lower16:_foo 161 thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4)) 162 thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4)) 163 arm_bl24, /// ex: bl _foo 164 arm_b24, /// ex: b _foo 165 arm_movw, /// ex: movw r1, :lower16:_foo 166 arm_movt, /// ex: movt r1, :lower16:_foo 167 arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4)) 168 arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4)) 169 pointer32, /// ex: .long _foo 170 delta32, /// ex: .long _foo - . 171 172 // Kinds introduced by Passes: 173 lazyPointer, /// Location contains a lazy pointer. 174 lazyImmediateLocation, /// Location contains immediate value used in stub. 175 }; 176 177 // Utility functions for inspecting/updating instructions. 178 static bool isThumbMovw(uint32_t instruction); 179 static bool isThumbMovt(uint32_t instruction); 180 static bool isArmMovw(uint32_t instruction); 181 static bool isArmMovt(uint32_t instruction); 182 static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t); 183 static int32_t getDisplacementFromArmBranch(uint32_t instruction); 184 static uint16_t getWordFromThumbMov(uint32_t instruction); 185 static uint16_t getWordFromArmMov(uint32_t instruction); 186 static uint32_t clearThumbBit(uint32_t value, const Atom *target); 187 static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp, 188 bool targetIsThumb); 189 static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia, 190 int32_t disp, bool targetThumb); 191 static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word); 192 static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word); 193 194 StringRef stubName(const DefinedAtom &); 195 bool useExternalRelocationTo(const Atom &target); 196 197 void applyFixupFinal(const Reference &ref, uint8_t *location, 198 uint64_t fixupAddress, uint64_t targetAddress, 199 uint64_t inAtomAddress, bool &thumbMode, 200 bool targetIsThumb); 201 202 void applyFixupRelocatable(const Reference &ref, uint8_t *location, 203 uint64_t fixupAddress, 204 uint64_t targetAddress, 205 uint64_t inAtomAddress, bool &thumbMode, 206 bool targetIsThumb); 207 }; 208 209 //===----------------------------------------------------------------------===// 210 // ArchHandler_arm 211 //===----------------------------------------------------------------------===// 212 213 const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = { 214 LLD_KIND_STRING_ENTRY(invalid), 215 LLD_KIND_STRING_ENTRY(modeThumbCode), 216 LLD_KIND_STRING_ENTRY(modeArmCode), 217 LLD_KIND_STRING_ENTRY(modeData), 218 LLD_KIND_STRING_ENTRY(thumb_bl22), 219 LLD_KIND_STRING_ENTRY(thumb_b22), 220 LLD_KIND_STRING_ENTRY(thumb_movw), 221 LLD_KIND_STRING_ENTRY(thumb_movt), 222 LLD_KIND_STRING_ENTRY(thumb_movw_funcRel), 223 LLD_KIND_STRING_ENTRY(thumb_movt_funcRel), 224 LLD_KIND_STRING_ENTRY(arm_bl24), 225 LLD_KIND_STRING_ENTRY(arm_b24), 226 LLD_KIND_STRING_ENTRY(arm_movw), 227 LLD_KIND_STRING_ENTRY(arm_movt), 228 LLD_KIND_STRING_ENTRY(arm_movw_funcRel), 229 LLD_KIND_STRING_ENTRY(arm_movt_funcRel), 230 LLD_KIND_STRING_ENTRY(pointer32), 231 LLD_KIND_STRING_ENTRY(delta32), 232 LLD_KIND_STRING_ENTRY(lazyPointer), 233 LLD_KIND_STRING_ENTRY(lazyImmediateLocation), 234 LLD_KIND_STRING_END 235 }; 236 237 const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = { 238 "dyld_stub_binder", 239 240 // References in lazy pointer 241 { Reference::KindArch::ARM, pointer32, 0, 0 }, 242 { Reference::KindArch::ARM, lazyPointer, 0, 0 }, 243 244 // GOT pointer to dyld_stub_binder 245 { Reference::KindArch::ARM, pointer32, 0, 0 }, 246 247 // arm code alignment 2^2 248 2, 249 250 // Stub size and code 251 16, 252 { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 12 253 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip 254 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip] 255 0x00, 0x00, 0x00, 0x00 }, // .long L_foo$lazy_ptr - (L1$scv + 8) 256 { Reference::KindArch::ARM, delta32, 12, 0 }, 257 { false, 0, 0, 0 }, 258 259 // Stub Helper size and code 260 12, 261 { 0x00, 0xC0, 0x9F, 0xE5, // ldr ip, [pc, #0] 262 0x00, 0x00, 0x00, 0xEA, // b _helperhelper 263 0x00, 0x00, 0x00, 0x00 }, // .long lazy-info-offset 264 { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 }, 265 { Reference::KindArch::ARM, arm_b24, 4, 0 }, 266 267 // Stub helper image cache content type 268 DefinedAtom::typeGOT, 269 270 // Stub Helper-Common size and code 271 36, 272 // Stub helper alignment 273 2, 274 { // push lazy-info-offset 275 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]! 276 // push address of dyld_mageLoaderCache 277 0x10, 0xC0, 0x9F, 0xE5, // ldr ip, L1 278 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip 279 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]! 280 // jump through dyld_stub_binder 281 0x08, 0xC0, 0x9F, 0xE5, // ldr ip, L2 282 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip 283 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip] 284 0x00, 0x00, 0x00, 0x00, // L1: .long fFastStubGOTAtom - (helper+16) 285 0x00, 0x00, 0x00, 0x00 }, // L2: .long dyld_stub_binder - (helper+28) 286 { Reference::KindArch::ARM, delta32, 28, 0xC }, 287 { false, 0, 0, 0 }, 288 { Reference::KindArch::ARM, delta32, 32, 0x04 }, 289 { false, 0, 0, 0 } 290 }; 291 292 const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() { 293 // If multiple kinds of stubs are supported, select which StubInfo here. 294 return _sStubInfoArmPIC; 295 } 296 297 bool ArchHandler_arm::isCallSite(const Reference &ref) { 298 switch (ref.kindValue()) { 299 case thumb_b22: 300 case thumb_bl22: 301 case arm_b24: 302 case arm_bl24: 303 return true; 304 default: 305 return false; 306 } 307 } 308 309 bool ArchHandler_arm::isPointer(const Reference &ref) { 310 return (ref.kindValue() == pointer32); 311 } 312 313 bool ArchHandler_arm::isNonCallBranch(const Reference &ref) { 314 switch (ref.kindValue()) { 315 case thumb_b22: 316 case arm_b24: 317 return true; 318 default: 319 return false; 320 } 321 } 322 323 bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) { 324 switch (reloc.type) { 325 case ARM_RELOC_SECTDIFF: 326 case ARM_RELOC_LOCAL_SECTDIFF: 327 case ARM_RELOC_HALF_SECTDIFF: 328 case ARM_RELOC_HALF: 329 return true; 330 default: 331 return false; 332 } 333 } 334 335 /// Trace references from stub atom to lazy pointer to target and get its name. 336 StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) { 337 assert(stubAtom.contentType() == DefinedAtom::typeStub); 338 for (const Reference *ref : stubAtom) { 339 if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) { 340 if (lp->contentType() != DefinedAtom::typeLazyPointer) 341 continue; 342 for (const Reference *ref2 : *lp) { 343 if (ref2->kindValue() != lazyPointer) 344 continue; 345 return ref2->target()->name(); 346 } 347 } 348 } 349 return "stub"; 350 } 351 352 /// Extract displacement from an ARM b/bl/blx instruction. 353 int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) { 354 // Sign-extend imm24 355 int32_t displacement = (instruction & 0x00FFFFFF) << 2; 356 if ((displacement & 0x02000000) != 0) 357 displacement |= 0xFC000000; 358 // If this is BLX and H bit set, add 2. 359 if ((instruction & 0xFF000000) == 0xFB000000) 360 displacement += 2; 361 return displacement; 362 } 363 364 /// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed. 365 uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction, 366 int32_t displacement, 367 bool targetIsThumb) { 368 assert((displacement <= 33554428) && (displacement > (-33554432)) 369 && "arm branch out of range"); 370 bool is_blx = ((instruction & 0xF0000000) == 0xF0000000); 371 uint32_t newInstruction = (instruction & 0xFF000000); 372 uint32_t h = 0; 373 if (targetIsThumb) { 374 // Force use of BLX. 375 newInstruction = 0xFA000000; 376 if (!is_blx) { 377 assert(((instruction & 0xF0000000) == 0xE0000000) 378 && "no conditional arm blx"); 379 assert(((instruction & 0xFF000000) == 0xEB000000) 380 && "no arm pc-rel BX instruction"); 381 } 382 if (displacement & 2) 383 h = 1; 384 } 385 else { 386 // Force use of B/BL. 387 if (is_blx) 388 newInstruction = 0xEB000000; 389 } 390 newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF); 391 return newInstruction; 392 } 393 394 /// Extract displacement from a thumb b/bl/blx instruction. 395 int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction, 396 uint32_t instrAddr) { 397 bool is_blx = ((instruction & 0xD000F800) == 0xC000F000); 398 uint32_t s = (instruction >> 10) & 0x1; 399 uint32_t j1 = (instruction >> 29) & 0x1; 400 uint32_t j2 = (instruction >> 27) & 0x1; 401 uint32_t imm10 = instruction & 0x3FF; 402 uint32_t imm11 = (instruction >> 16) & 0x7FF; 403 uint32_t i1 = (j1 == s); 404 uint32_t i2 = (j2 == s); 405 uint32_t dis = 406 (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); 407 int32_t sdis = dis; 408 int32_t result = s ? (sdis | 0xFE000000) : sdis; 409 if (is_blx && (instrAddr & 0x2)) { 410 // The thumb blx instruction always has low bit of imm11 as zero. The way 411 // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that 412 // the blx instruction always 4-byte aligns the pc before adding the 413 // displacement from the blx. We must emulate that when decoding this. 414 result -= 2; 415 } 416 return result; 417 } 418 419 /// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed. 420 uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction, 421 uint32_t instrAddr, 422 int32_t displacement, 423 bool targetIsThumb) { 424 assert((displacement <= 16777214) && (displacement > (-16777216)) 425 && "thumb branch out of range"); 426 bool is_bl = ((instruction & 0xD000F800) == 0xD000F000); 427 bool is_blx = ((instruction & 0xD000F800) == 0xC000F000); 428 bool is_b = ((instruction & 0xD000F800) == 0x9000F000); 429 uint32_t newInstruction = (instruction & 0xD000F800); 430 if (is_bl || is_blx) { 431 if (targetIsThumb) { 432 newInstruction = 0xD000F000; // Use bl 433 } else { 434 newInstruction = 0xC000F000; // Use blx 435 // See note in getDisplacementFromThumbBranch() about blx. 436 if (instrAddr & 0x2) 437 displacement += 2; 438 } 439 } else if (is_b) { 440 assert(targetIsThumb && "no pc-rel thumb branch instruction that " 441 "switches to arm mode"); 442 } 443 else { 444 llvm_unreachable("thumb branch22 reloc on a non-branch instruction"); 445 } 446 uint32_t s = (uint32_t)(displacement >> 24) & 0x1; 447 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1; 448 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1; 449 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF; 450 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF; 451 uint32_t j1 = (i1 == s); 452 uint32_t j2 = (i2 == s); 453 uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11; 454 uint32_t firstDisp = (s << 10) | imm10; 455 newInstruction |= (nextDisp << 16) | firstDisp; 456 return newInstruction; 457 } 458 459 bool ArchHandler_arm::isThumbMovw(uint32_t instruction) { 460 return (instruction & 0x8000FBF0) == 0x0000F240; 461 } 462 463 bool ArchHandler_arm::isThumbMovt(uint32_t instruction) { 464 return (instruction & 0x8000FBF0) == 0x0000F2C0; 465 } 466 467 bool ArchHandler_arm::isArmMovw(uint32_t instruction) { 468 return (instruction & 0x0FF00000) == 0x03000000; 469 } 470 471 bool ArchHandler_arm::isArmMovt(uint32_t instruction) { 472 return (instruction & 0x0FF00000) == 0x03400000; 473 } 474 475 uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) { 476 assert(isThumbMovw(instruction) || isThumbMovt(instruction)); 477 uint32_t i = ((instruction & 0x00000400) >> 10); 478 uint32_t imm4 = (instruction & 0x0000000F); 479 uint32_t imm3 = ((instruction & 0x70000000) >> 28); 480 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16); 481 return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; 482 } 483 484 uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) { 485 assert(isArmMovw(instruction) || isArmMovt(instruction)); 486 uint32_t imm4 = ((instruction & 0x000F0000) >> 16); 487 uint32_t imm12 = (instruction & 0x00000FFF); 488 return (imm4 << 12) | imm12; 489 } 490 491 uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) { 492 assert(isThumbMovw(instr) || isThumbMovt(instr)); 493 uint32_t imm4 = (word & 0xF000) >> 12; 494 uint32_t i = (word & 0x0800) >> 11; 495 uint32_t imm3 = (word & 0x0700) >> 8; 496 uint32_t imm8 = word & 0x00FF; 497 return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16); 498 } 499 500 uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) { 501 assert(isArmMovw(instr) || isArmMovt(instr)); 502 uint32_t imm4 = (word & 0xF000) >> 12; 503 uint32_t imm12 = word & 0x0FFF; 504 return (instr & 0xFFF0F000) | (imm4 << 16) | imm12; 505 } 506 507 uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) { 508 // The assembler often adds one to the address of a thumb function. 509 // We need to undo that so it does not look like an addend. 510 if (value & 1) { 511 if (isa<DefinedAtom>(target)) { 512 const MachODefinedAtom *machoTarget = 513 reinterpret_cast<const MachODefinedAtom *>(target); 514 if (machoTarget->isThumb()) 515 value &= -2; // mask off thumb-bit 516 } 517 } 518 return value; 519 } 520 521 llvm::Error ArchHandler_arm::getReferenceInfo( 522 const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, 523 uint64_t fixupAddress, bool isBig, 524 FindAtomBySectionAndAddress atomFromAddress, 525 FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, 526 const lld::Atom **target, Reference::Addend *addend) { 527 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; 528 uint64_t targetAddress; 529 uint32_t instruction = *(const ulittle32_t *)fixupContent; 530 int32_t displacement; 531 switch (relocPattern(reloc)) { 532 case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4: 533 // ex: bl _foo (and _foo is undefined) 534 if ((instruction & 0xD000F800) == 0x9000F000) 535 *kind = thumb_b22; 536 else 537 *kind = thumb_bl22; 538 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 539 return ec; 540 // Instruction contains branch to addend. 541 displacement = getDisplacementFromThumbBranch(instruction, fixupAddress); 542 *addend = fixupAddress + 4 + displacement; 543 return llvm::Error(); 544 case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4: 545 // ex: bl _foo (and _foo is defined) 546 if ((instruction & 0xD000F800) == 0x9000F000) 547 *kind = thumb_b22; 548 else 549 *kind = thumb_bl22; 550 displacement = getDisplacementFromThumbBranch(instruction, fixupAddress); 551 targetAddress = fixupAddress + 4 + displacement; 552 return atomFromAddress(reloc.symbol, targetAddress, target, addend); 553 case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4: 554 // ex: bl _foo+4 (and _foo is defined) 555 if ((instruction & 0xD000F800) == 0x9000F000) 556 *kind = thumb_b22; 557 else 558 *kind = thumb_bl22; 559 displacement = getDisplacementFromThumbBranch(instruction, fixupAddress); 560 targetAddress = fixupAddress + 4 + displacement; 561 if (auto ec = atomFromAddress(0, reloc.value, target, addend)) 562 return ec; 563 // reloc.value is target atom's address. Instruction contains branch 564 // to atom+addend. 565 *addend += (targetAddress - reloc.value); 566 return llvm::Error(); 567 case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4: 568 // ex: bl _foo (and _foo is undefined) 569 if (((instruction & 0x0F000000) == 0x0A000000) 570 && ((instruction & 0xF0000000) != 0xF0000000)) 571 *kind = arm_b24; 572 else 573 *kind = arm_bl24; 574 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 575 return ec; 576 // Instruction contains branch to addend. 577 displacement = getDisplacementFromArmBranch(instruction); 578 *addend = fixupAddress + 8 + displacement; 579 return llvm::Error(); 580 case ARM_RELOC_BR24 | rPcRel | rLength4: 581 // ex: bl _foo (and _foo is defined) 582 if (((instruction & 0x0F000000) == 0x0A000000) 583 && ((instruction & 0xF0000000) != 0xF0000000)) 584 *kind = arm_b24; 585 else 586 *kind = arm_bl24; 587 displacement = getDisplacementFromArmBranch(instruction); 588 targetAddress = fixupAddress + 8 + displacement; 589 return atomFromAddress(reloc.symbol, targetAddress, target, addend); 590 case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4: 591 // ex: bl _foo+4 (and _foo is defined) 592 if (((instruction & 0x0F000000) == 0x0A000000) 593 && ((instruction & 0xF0000000) != 0xF0000000)) 594 *kind = arm_b24; 595 else 596 *kind = arm_bl24; 597 displacement = getDisplacementFromArmBranch(instruction); 598 targetAddress = fixupAddress + 8 + displacement; 599 if (auto ec = atomFromAddress(0, reloc.value, target, addend)) 600 return ec; 601 // reloc.value is target atom's address. Instruction contains branch 602 // to atom+addend. 603 *addend += (targetAddress - reloc.value); 604 return llvm::Error(); 605 case ARM_RELOC_VANILLA | rExtern | rLength4: 606 // ex: .long _foo (and _foo is undefined) 607 *kind = pointer32; 608 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 609 return ec; 610 *addend = instruction; 611 return llvm::Error(); 612 case ARM_RELOC_VANILLA | rLength4: 613 // ex: .long _foo (and _foo is defined) 614 *kind = pointer32; 615 if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend)) 616 return ec; 617 *addend = clearThumbBit((uint32_t) * addend, *target); 618 return llvm::Error(); 619 case ARM_RELOC_VANILLA | rScattered | rLength4: 620 // ex: .long _foo+a (and _foo is defined) 621 *kind = pointer32; 622 if (auto ec = atomFromAddress(0, reloc.value, target, addend)) 623 return ec; 624 *addend += (clearThumbBit(instruction, *target) - reloc.value); 625 return llvm::Error(); 626 default: 627 return llvm::make_error<GenericError>("unsupported arm relocation type"); 628 } 629 return llvm::Error(); 630 } 631 632 llvm::Error 633 ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, 634 const normalized::Relocation &reloc2, 635 const DefinedAtom *inAtom, 636 uint32_t offsetInAtom, 637 uint64_t fixupAddress, bool isBig, 638 bool scatterable, 639 FindAtomBySectionAndAddress atomFromAddr, 640 FindAtomBySymbolIndex atomFromSymbolIndex, 641 Reference::KindValue *kind, 642 const lld::Atom **target, 643 Reference::Addend *addend) { 644 bool pointerDiff = false; 645 bool funcRel; 646 bool top; 647 bool thumbReloc; 648 switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { 649 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo) << 16 | 650 ARM_RELOC_PAIR | rScattered | rLenThmbLo): 651 // ex: movw r1, :lower16:(_x-L1) [thumb mode] 652 *kind = thumb_movw_funcRel; 653 funcRel = true; 654 top = false; 655 thumbReloc = true; 656 break; 657 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi) << 16 | 658 ARM_RELOC_PAIR | rScattered | rLenThmbHi): 659 // ex: movt r1, :upper16:(_x-L1) [thumb mode] 660 *kind = thumb_movt_funcRel; 661 funcRel = true; 662 top = true; 663 thumbReloc = true; 664 break; 665 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo) << 16 | 666 ARM_RELOC_PAIR | rScattered | rLenArmLo): 667 // ex: movw r1, :lower16:(_x-L1) [arm mode] 668 *kind = arm_movw_funcRel; 669 funcRel = true; 670 top = false; 671 thumbReloc = false; 672 break; 673 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi) << 16 | 674 ARM_RELOC_PAIR | rScattered | rLenArmHi): 675 // ex: movt r1, :upper16:(_x-L1) [arm mode] 676 *kind = arm_movt_funcRel; 677 funcRel = true; 678 top = true; 679 thumbReloc = false; 680 break; 681 case ((ARM_RELOC_HALF | rLenThmbLo) << 16 | 682 ARM_RELOC_PAIR | rLenThmbLo): 683 // ex: movw r1, :lower16:_x [thumb mode] 684 *kind = thumb_movw; 685 funcRel = false; 686 top = false; 687 thumbReloc = true; 688 break; 689 case ((ARM_RELOC_HALF | rLenThmbHi) << 16 | 690 ARM_RELOC_PAIR | rLenThmbHi): 691 // ex: movt r1, :upper16:_x [thumb mode] 692 *kind = thumb_movt; 693 funcRel = false; 694 top = true; 695 thumbReloc = true; 696 break; 697 case ((ARM_RELOC_HALF | rLenArmLo) << 16 | 698 ARM_RELOC_PAIR | rLenArmLo): 699 // ex: movw r1, :lower16:_x [arm mode] 700 *kind = arm_movw; 701 funcRel = false; 702 top = false; 703 thumbReloc = false; 704 break; 705 case ((ARM_RELOC_HALF | rLenArmHi) << 16 | 706 ARM_RELOC_PAIR | rLenArmHi): 707 // ex: movt r1, :upper16:_x [arm mode] 708 *kind = arm_movt; 709 funcRel = false; 710 top = true; 711 thumbReloc = false; 712 break; 713 case ((ARM_RELOC_HALF | rScattered | rLenThmbLo) << 16 | 714 ARM_RELOC_PAIR | rLenThmbLo): 715 // ex: movw r1, :lower16:_x+a [thumb mode] 716 *kind = thumb_movw; 717 funcRel = false; 718 top = false; 719 thumbReloc = true; 720 break; 721 case ((ARM_RELOC_HALF | rScattered | rLenThmbHi) << 16 | 722 ARM_RELOC_PAIR | rLenThmbHi): 723 // ex: movt r1, :upper16:_x+a [thumb mode] 724 *kind = thumb_movt; 725 funcRel = false; 726 top = true; 727 thumbReloc = true; 728 break; 729 case ((ARM_RELOC_HALF | rScattered | rLenArmLo) << 16 | 730 ARM_RELOC_PAIR | rLenArmLo): 731 // ex: movw r1, :lower16:_x+a [arm mode] 732 *kind = arm_movw; 733 funcRel = false; 734 top = false; 735 thumbReloc = false; 736 break; 737 case ((ARM_RELOC_HALF | rScattered | rLenArmHi) << 16 | 738 ARM_RELOC_PAIR | rLenArmHi): 739 // ex: movt r1, :upper16:_x+a [arm mode] 740 *kind = arm_movt; 741 funcRel = false; 742 top = true; 743 thumbReloc = false; 744 break; 745 case ((ARM_RELOC_HALF | rExtern | rLenThmbLo) << 16 | 746 ARM_RELOC_PAIR | rLenThmbLo): 747 // ex: movw r1, :lower16:_undef [thumb mode] 748 *kind = thumb_movw; 749 funcRel = false; 750 top = false; 751 thumbReloc = true; 752 break; 753 case ((ARM_RELOC_HALF | rExtern | rLenThmbHi) << 16 | 754 ARM_RELOC_PAIR | rLenThmbHi): 755 // ex: movt r1, :upper16:_undef [thumb mode] 756 *kind = thumb_movt; 757 funcRel = false; 758 top = true; 759 thumbReloc = true; 760 break; 761 case ((ARM_RELOC_HALF | rExtern | rLenArmLo) << 16 | 762 ARM_RELOC_PAIR | rLenArmLo): 763 // ex: movw r1, :lower16:_undef [arm mode] 764 *kind = arm_movw; 765 funcRel = false; 766 top = false; 767 thumbReloc = false; 768 break; 769 case ((ARM_RELOC_HALF | rExtern | rLenArmHi) << 16 | 770 ARM_RELOC_PAIR | rLenArmHi): 771 // ex: movt r1, :upper16:_undef [arm mode] 772 *kind = arm_movt; 773 funcRel = false; 774 top = true; 775 thumbReloc = false; 776 break; 777 case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 | 778 ARM_RELOC_PAIR | rScattered | rLength4): 779 case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 | 780 ARM_RELOC_PAIR | rScattered | rLength4): 781 // ex: .long _foo - . 782 pointerDiff = true; 783 break; 784 default: 785 return llvm::make_error<GenericError>("unsupported arm relocation pair"); 786 } 787 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; 788 uint32_t instruction = *(const ulittle32_t *)fixupContent; 789 uint32_t value; 790 uint32_t fromAddress; 791 uint32_t toAddress; 792 uint16_t instruction16; 793 uint16_t other16; 794 const lld::Atom *fromTarget; 795 Reference::Addend offsetInTo; 796 Reference::Addend offsetInFrom; 797 if (pointerDiff) { 798 toAddress = reloc1.value; 799 fromAddress = reloc2.value; 800 if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo)) 801 return ec; 802 if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom)) 803 return ec; 804 if (scatterable && (fromTarget != inAtom)) 805 return llvm::make_error<GenericError>( 806 "SECTDIFF relocation where subtrahend label is not in atom"); 807 *kind = delta32; 808 value = clearThumbBit(instruction, *target); 809 *addend = (int32_t)(value - (toAddress - fixupAddress)); 810 } else if (funcRel) { 811 toAddress = reloc1.value; 812 fromAddress = reloc2.value; 813 if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo)) 814 return ec; 815 if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom)) 816 return ec; 817 if (fromTarget != inAtom) 818 return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation" 819 " where subtrahend label is not in atom"); 820 other16 = (reloc2.offset & 0xFFFF); 821 if (thumbReloc) { 822 if (top) { 823 if (!isThumbMovt(instruction)) 824 return llvm::make_error<GenericError>("expected movt instruction"); 825 } 826 else { 827 if (!isThumbMovw(instruction)) 828 return llvm::make_error<GenericError>("expected movw instruction"); 829 } 830 instruction16 = getWordFromThumbMov(instruction); 831 } 832 else { 833 if (top) { 834 if (!isArmMovt(instruction)) 835 return llvm::make_error<GenericError>("expected movt instruction"); 836 } 837 else { 838 if (!isArmMovw(instruction)) 839 return llvm::make_error<GenericError>("expected movw instruction"); 840 } 841 instruction16 = getWordFromArmMov(instruction); 842 } 843 if (top) 844 value = (instruction16 << 16) | other16; 845 else 846 value = (other16 << 16) | instruction16; 847 value = clearThumbBit(value, *target); 848 int64_t ta = (int64_t) value - (toAddress - fromAddress); 849 *addend = ta - offsetInFrom; 850 return llvm::Error(); 851 } else { 852 uint32_t sectIndex; 853 if (thumbReloc) { 854 if (top) { 855 if (!isThumbMovt(instruction)) 856 return llvm::make_error<GenericError>("expected movt instruction"); 857 } 858 else { 859 if (!isThumbMovw(instruction)) 860 return llvm::make_error<GenericError>("expected movw instruction"); 861 } 862 instruction16 = getWordFromThumbMov(instruction); 863 } 864 else { 865 if (top) { 866 if (!isArmMovt(instruction)) 867 return llvm::make_error<GenericError>("expected movt instruction"); 868 } 869 else { 870 if (!isArmMovw(instruction)) 871 return llvm::make_error<GenericError>("expected movw instruction"); 872 } 873 instruction16 = getWordFromArmMov(instruction); 874 } 875 other16 = (reloc2.offset & 0xFFFF); 876 if (top) 877 value = (instruction16 << 16) | other16; 878 else 879 value = (other16 << 16) | instruction16; 880 if (reloc1.isExtern) { 881 if (auto ec = atomFromSymbolIndex(reloc1.symbol, target)) 882 return ec; 883 *addend = value; 884 } else { 885 if (reloc1.scattered) { 886 toAddress = reloc1.value; 887 sectIndex = 0; 888 } else { 889 toAddress = value; 890 sectIndex = reloc1.symbol; 891 } 892 if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo)) 893 return ec; 894 *addend = value - toAddress; 895 } 896 } 897 898 return llvm::Error(); 899 } 900 901 void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc, 902 uint64_t fixupAddress, 903 uint64_t targetAddress, 904 uint64_t inAtomAddress, 905 bool &thumbMode, bool targetIsThumb) { 906 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 907 return; 908 assert(ref.kindArch() == Reference::KindArch::ARM); 909 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc); 910 int32_t displacement; 911 uint16_t value16; 912 uint32_t value32; 913 switch (static_cast<ArmKind>(ref.kindValue())) { 914 case modeThumbCode: 915 thumbMode = true; 916 break; 917 case modeArmCode: 918 thumbMode = false; 919 break; 920 case modeData: 921 break; 922 case thumb_b22: 923 case thumb_bl22: 924 assert(thumbMode); 925 displacement = (targetAddress - (fixupAddress + 4)) + ref.addend(); 926 value32 = setDisplacementInThumbBranch(*loc32, fixupAddress, 927 displacement, targetIsThumb); 928 *loc32 = value32; 929 break; 930 case thumb_movw: 931 assert(thumbMode); 932 value16 = (targetAddress + ref.addend()) & 0xFFFF; 933 if (targetIsThumb) 934 value16 |= 1; 935 *loc32 = setWordFromThumbMov(*loc32, value16); 936 break; 937 case thumb_movt: 938 assert(thumbMode); 939 value16 = (targetAddress + ref.addend()) >> 16; 940 *loc32 = setWordFromThumbMov(*loc32, value16); 941 break; 942 case thumb_movw_funcRel: 943 assert(thumbMode); 944 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; 945 if (targetIsThumb) 946 value16 |= 1; 947 *loc32 = setWordFromThumbMov(*loc32, value16); 948 break; 949 case thumb_movt_funcRel: 950 assert(thumbMode); 951 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; 952 *loc32 = setWordFromThumbMov(*loc32, value16); 953 break; 954 case arm_b24: 955 case arm_bl24: 956 assert(!thumbMode); 957 displacement = (targetAddress - (fixupAddress + 8)) + ref.addend(); 958 value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb); 959 *loc32 = value32; 960 break; 961 case arm_movw: 962 assert(!thumbMode); 963 value16 = (targetAddress + ref.addend()) & 0xFFFF; 964 if (targetIsThumb) 965 value16 |= 1; 966 *loc32 = setWordFromArmMov(*loc32, value16); 967 break; 968 case arm_movt: 969 assert(!thumbMode); 970 value16 = (targetAddress + ref.addend()) >> 16; 971 *loc32 = setWordFromArmMov(*loc32, value16); 972 break; 973 case arm_movw_funcRel: 974 assert(!thumbMode); 975 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; 976 if (targetIsThumb) 977 value16 |= 1; 978 *loc32 = setWordFromArmMov(*loc32, value16); 979 break; 980 case arm_movt_funcRel: 981 assert(!thumbMode); 982 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; 983 *loc32 = setWordFromArmMov(*loc32, value16); 984 break; 985 case pointer32: 986 if (targetIsThumb) 987 *loc32 = targetAddress + ref.addend() + 1; 988 else 989 *loc32 = targetAddress + ref.addend(); 990 break; 991 case delta32: 992 if (targetIsThumb) 993 *loc32 = targetAddress - fixupAddress + ref.addend() + 1; 994 else 995 *loc32 = targetAddress - fixupAddress + ref.addend(); 996 break; 997 case lazyPointer: 998 // do nothing 999 break; 1000 case lazyImmediateLocation: 1001 *loc32 = ref.addend(); 1002 break; 1003 case invalid: 1004 llvm_unreachable("invalid ARM Reference Kind"); 1005 break; 1006 } 1007 } 1008 1009 void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom, 1010 bool relocatable, 1011 FindAddressForAtom findAddress, 1012 FindAddressForAtom findSectionAddress, 1013 uint64_t imageBaseAddress, 1014 llvm::MutableArrayRef<uint8_t> atomContentBuffer) { 1015 // Copy raw bytes. 1016 std::copy(atom.rawContent().begin(), atom.rawContent().end(), 1017 atomContentBuffer.begin()); 1018 // Apply fix-ups. 1019 bool thumbMode = false; 1020 for (const Reference *ref : atom) { 1021 uint32_t offset = ref->offsetInAtom(); 1022 const Atom *target = ref->target(); 1023 uint64_t targetAddress = 0; 1024 bool targetIsThumb = false; 1025 if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) { 1026 targetAddress = findAddress(*target); 1027 targetIsThumb = isThumbFunction(*defTarg); 1028 } 1029 uint64_t atomAddress = findAddress(atom); 1030 uint64_t fixupAddress = atomAddress + offset; 1031 if (relocatable) { 1032 applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress, 1033 targetAddress, atomAddress, thumbMode, 1034 targetIsThumb); 1035 } else { 1036 applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress, 1037 targetAddress, atomAddress, thumbMode, targetIsThumb); 1038 } 1039 } 1040 } 1041 1042 bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) { 1043 // Undefined symbols are referenced via external relocations. 1044 if (isa<UndefinedAtom>(&target)) 1045 return true; 1046 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) { 1047 switch (defAtom->merge()) { 1048 case DefinedAtom::mergeAsTentative: 1049 // Tentative definitions are referenced via external relocations. 1050 return true; 1051 case DefinedAtom::mergeAsWeak: 1052 case DefinedAtom::mergeAsWeakAndAddressUsed: 1053 // Global weak-defs are referenced via external relocations. 1054 return (defAtom->scope() == DefinedAtom::scopeGlobal); 1055 default: 1056 break; 1057 } 1058 } 1059 // Everything else is reference via an internal relocation. 1060 return false; 1061 } 1062 1063 void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc, 1064 uint64_t fixupAddress, 1065 uint64_t targetAddress, 1066 uint64_t inAtomAddress, 1067 bool &thumbMode, 1068 bool targetIsThumb) { 1069 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 1070 return; 1071 assert(ref.kindArch() == Reference::KindArch::ARM); 1072 bool useExternalReloc = useExternalRelocationTo(*ref.target()); 1073 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc); 1074 int32_t displacement; 1075 uint16_t value16; 1076 uint32_t value32; 1077 bool targetIsUndef = isa<UndefinedAtom>(ref.target()); 1078 switch (static_cast<ArmKind>(ref.kindValue())) { 1079 case modeThumbCode: 1080 thumbMode = true; 1081 break; 1082 case modeArmCode: 1083 thumbMode = false; 1084 break; 1085 case modeData: 1086 break; 1087 case thumb_b22: 1088 case thumb_bl22: 1089 assert(thumbMode); 1090 if (useExternalReloc) 1091 displacement = (ref.addend() - (fixupAddress + 4)); 1092 else 1093 displacement = (targetAddress - (fixupAddress + 4)) + ref.addend(); 1094 value32 = setDisplacementInThumbBranch(*loc32, fixupAddress, 1095 displacement, 1096 targetIsUndef || targetIsThumb); 1097 *loc32 = value32; 1098 break; 1099 case thumb_movw: 1100 assert(thumbMode); 1101 if (useExternalReloc) 1102 value16 = ref.addend() & 0xFFFF; 1103 else 1104 value16 = (targetAddress + ref.addend()) & 0xFFFF; 1105 *loc32 = setWordFromThumbMov(*loc32, value16); 1106 break; 1107 case thumb_movt: 1108 assert(thumbMode); 1109 if (useExternalReloc) 1110 value16 = ref.addend() >> 16; 1111 else 1112 value16 = (targetAddress + ref.addend()) >> 16; 1113 *loc32 = setWordFromThumbMov(*loc32, value16); 1114 break; 1115 case thumb_movw_funcRel: 1116 assert(thumbMode); 1117 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; 1118 *loc32 = setWordFromThumbMov(*loc32, value16); 1119 break; 1120 case thumb_movt_funcRel: 1121 assert(thumbMode); 1122 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; 1123 *loc32 = setWordFromThumbMov(*loc32, value16); 1124 break; 1125 case arm_b24: 1126 case arm_bl24: 1127 assert(!thumbMode); 1128 if (useExternalReloc) 1129 displacement = (ref.addend() - (fixupAddress + 8)); 1130 else 1131 displacement = (targetAddress - (fixupAddress + 8)) + ref.addend(); 1132 value32 = setDisplacementInArmBranch(*loc32, displacement, 1133 targetIsThumb); 1134 *loc32 = value32; 1135 break; 1136 case arm_movw: 1137 assert(!thumbMode); 1138 if (useExternalReloc) 1139 value16 = ref.addend() & 0xFFFF; 1140 else 1141 value16 = (targetAddress + ref.addend()) & 0xFFFF; 1142 *loc32 = setWordFromArmMov(*loc32, value16); 1143 break; 1144 case arm_movt: 1145 assert(!thumbMode); 1146 if (useExternalReloc) 1147 value16 = ref.addend() >> 16; 1148 else 1149 value16 = (targetAddress + ref.addend()) >> 16; 1150 *loc32 = setWordFromArmMov(*loc32, value16); 1151 break; 1152 case arm_movw_funcRel: 1153 assert(!thumbMode); 1154 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF; 1155 *loc32 = setWordFromArmMov(*loc32, value16); 1156 break; 1157 case arm_movt_funcRel: 1158 assert(!thumbMode); 1159 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16; 1160 *loc32 = setWordFromArmMov(*loc32, value16); 1161 break; 1162 case pointer32: 1163 *loc32 = targetAddress + ref.addend(); 1164 break; 1165 case delta32: 1166 *loc32 = targetAddress - fixupAddress + ref.addend(); 1167 break; 1168 case lazyPointer: 1169 case lazyImmediateLocation: 1170 // do nothing 1171 break; 1172 case invalid: 1173 llvm_unreachable("invalid ARM Reference Kind"); 1174 break; 1175 } 1176 } 1177 1178 void ArchHandler_arm::appendSectionRelocations( 1179 const DefinedAtom &atom, 1180 uint64_t atomSectionOffset, 1181 const Reference &ref, 1182 FindSymbolIndexForAtom symbolIndexForAtom, 1183 FindSectionIndexForAtom sectionIndexForAtom, 1184 FindAddressForAtom addressForAtom, 1185 normalized::Relocations &relocs) { 1186 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 1187 return; 1188 assert(ref.kindArch() == Reference::KindArch::ARM); 1189 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom(); 1190 bool useExternalReloc = useExternalRelocationTo(*ref.target()); 1191 uint32_t targetAtomAddress; 1192 uint32_t fromAtomAddress; 1193 uint16_t other16; 1194 switch (static_cast<ArmKind>(ref.kindValue())) { 1195 case modeThumbCode: 1196 case modeArmCode: 1197 case modeData: 1198 // Do nothing. 1199 break; 1200 case thumb_b22: 1201 case thumb_bl22: 1202 if (useExternalReloc) { 1203 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1204 ARM_THUMB_RELOC_BR22 | rExtern | rPcRel | rLength4); 1205 } else { 1206 if (ref.addend() != 0) 1207 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()), 1208 ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4); 1209 else 1210 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1211 ARM_THUMB_RELOC_BR22 | rPcRel | rLength4); 1212 } 1213 break; 1214 case thumb_movw: 1215 if (useExternalReloc) { 1216 other16 = ref.addend() >> 16; 1217 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1218 ARM_RELOC_HALF | rExtern | rLenThmbLo); 1219 appendReloc(relocs, other16, 0, 0, 1220 ARM_RELOC_PAIR | rLenThmbLo); 1221 } else { 1222 targetAtomAddress = addressForAtom(*ref.target()); 1223 if (ref.addend() != 0) { 1224 other16 = (targetAtomAddress + ref.addend()) >> 16; 1225 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1226 ARM_RELOC_HALF | rScattered | rLenThmbLo); 1227 appendReloc(relocs, other16, 0, 0, 1228 ARM_RELOC_PAIR | rLenThmbLo); 1229 } else { 1230 other16 = (targetAtomAddress + ref.addend()) >> 16; 1231 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1232 ARM_RELOC_HALF | rLenThmbLo); 1233 appendReloc(relocs, other16, 0, 0, 1234 ARM_RELOC_PAIR | rLenThmbLo); 1235 } 1236 } 1237 break; 1238 case thumb_movt: 1239 if (useExternalReloc) { 1240 other16 = ref.addend() & 0xFFFF; 1241 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1242 ARM_RELOC_HALF | rExtern | rLenThmbHi); 1243 appendReloc(relocs, other16, 0, 0, 1244 ARM_RELOC_PAIR | rLenThmbHi); 1245 } else { 1246 targetAtomAddress = addressForAtom(*ref.target()); 1247 if (ref.addend() != 0) { 1248 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF; 1249 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1250 ARM_RELOC_HALF | rScattered | rLenThmbHi); 1251 appendReloc(relocs, other16, 0, 0, 1252 ARM_RELOC_PAIR | rLenThmbHi); 1253 } else { 1254 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF; 1255 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1256 ARM_RELOC_HALF | rLenThmbHi); 1257 appendReloc(relocs, other16, 0, 0, 1258 ARM_RELOC_PAIR | rLenThmbHi); 1259 } 1260 } 1261 break; 1262 case thumb_movw_funcRel: 1263 fromAtomAddress = addressForAtom(atom); 1264 targetAtomAddress = addressForAtom(*ref.target()); 1265 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16; 1266 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1267 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo); 1268 appendReloc(relocs, other16, 0, fromAtomAddress, 1269 ARM_RELOC_PAIR | rScattered | rLenThmbLo); 1270 break; 1271 case thumb_movt_funcRel: 1272 fromAtomAddress = addressForAtom(atom); 1273 targetAtomAddress = addressForAtom(*ref.target()); 1274 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF; 1275 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1276 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi); 1277 appendReloc(relocs, other16, 0, fromAtomAddress, 1278 ARM_RELOC_PAIR | rScattered | rLenThmbHi); 1279 break; 1280 case arm_b24: 1281 case arm_bl24: 1282 if (useExternalReloc) { 1283 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1284 ARM_RELOC_BR24 | rExtern | rPcRel | rLength4); 1285 } else { 1286 if (ref.addend() != 0) 1287 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()), 1288 ARM_RELOC_BR24 | rScattered | rPcRel | rLength4); 1289 else 1290 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1291 ARM_RELOC_BR24 | rPcRel | rLength4); 1292 } 1293 break; 1294 case arm_movw: 1295 if (useExternalReloc) { 1296 other16 = ref.addend() >> 16; 1297 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1298 ARM_RELOC_HALF | rExtern | rLenArmLo); 1299 appendReloc(relocs, other16, 0, 0, 1300 ARM_RELOC_PAIR | rLenArmLo); 1301 } else { 1302 targetAtomAddress = addressForAtom(*ref.target()); 1303 if (ref.addend() != 0) { 1304 other16 = (targetAtomAddress + ref.addend()) >> 16; 1305 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1306 ARM_RELOC_HALF | rScattered | rLenArmLo); 1307 appendReloc(relocs, other16, 0, 0, 1308 ARM_RELOC_PAIR | rLenArmLo); 1309 } else { 1310 other16 = (targetAtomAddress + ref.addend()) >> 16; 1311 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1312 ARM_RELOC_HALF | rLenArmLo); 1313 appendReloc(relocs, other16, 0, 0, 1314 ARM_RELOC_PAIR | rLenArmLo); 1315 } 1316 } 1317 break; 1318 case arm_movt: 1319 if (useExternalReloc) { 1320 other16 = ref.addend() & 0xFFFF; 1321 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1322 ARM_RELOC_HALF | rExtern | rLenArmHi); 1323 appendReloc(relocs, other16, 0, 0, 1324 ARM_RELOC_PAIR | rLenArmHi); 1325 } else { 1326 targetAtomAddress = addressForAtom(*ref.target()); 1327 if (ref.addend() != 0) { 1328 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF; 1329 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1330 ARM_RELOC_HALF | rScattered | rLenArmHi); 1331 appendReloc(relocs, other16, 0, 0, 1332 ARM_RELOC_PAIR | rLenArmHi); 1333 } else { 1334 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF; 1335 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1336 ARM_RELOC_HALF | rLenArmHi); 1337 appendReloc(relocs, other16, 0, 0, 1338 ARM_RELOC_PAIR | rLenArmHi); 1339 } 1340 } 1341 break; 1342 case arm_movw_funcRel: 1343 fromAtomAddress = addressForAtom(atom); 1344 targetAtomAddress = addressForAtom(*ref.target()); 1345 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16; 1346 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1347 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo); 1348 appendReloc(relocs, other16, 0, fromAtomAddress, 1349 ARM_RELOC_PAIR | rScattered | rLenArmLo); 1350 break; 1351 case arm_movt_funcRel: 1352 fromAtomAddress = addressForAtom(atom); 1353 targetAtomAddress = addressForAtom(*ref.target()); 1354 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF; 1355 appendReloc(relocs, sectionOffset, 0, targetAtomAddress, 1356 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi); 1357 appendReloc(relocs, other16, 0, fromAtomAddress, 1358 ARM_RELOC_PAIR | rScattered | rLenArmHi); 1359 break; 1360 case pointer32: 1361 if (useExternalReloc) { 1362 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 1363 ARM_RELOC_VANILLA | rExtern | rLength4); 1364 } 1365 else { 1366 if (ref.addend() != 0) 1367 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()), 1368 ARM_RELOC_VANILLA | rScattered | rLength4); 1369 else 1370 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0, 1371 ARM_RELOC_VANILLA | rLength4); 1372 } 1373 break; 1374 case delta32: 1375 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()), 1376 ARM_RELOC_SECTDIFF | rScattered | rLength4); 1377 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) + 1378 ref.offsetInAtom(), 1379 ARM_RELOC_PAIR | rScattered | rLength4); 1380 break; 1381 case lazyPointer: 1382 case lazyImmediateLocation: 1383 // do nothing 1384 break; 1385 case invalid: 1386 llvm_unreachable("invalid ARM Reference Kind"); 1387 break; 1388 } 1389 } 1390 1391 void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) { 1392 if (atom.isThumb()) { 1393 atom.addReference(Reference::KindNamespace::mach_o, 1394 Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0); 1395 } 1396 } 1397 1398 bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) { 1399 for (const Reference *ref : atom) { 1400 if (ref->offsetInAtom() != 0) 1401 return false; 1402 if (ref->kindNamespace() != Reference::KindNamespace::mach_o) 1403 continue; 1404 assert(ref->kindArch() == Reference::KindArch::ARM); 1405 if (ref->kindValue() == modeThumbCode) 1406 return true; 1407 } 1408 return false; 1409 } 1410 1411 class Thumb2ToArmShimAtom : public SimpleDefinedAtom { 1412 public: 1413 Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName, 1414 const DefinedAtom &target) 1415 : SimpleDefinedAtom(file) { 1416 addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM, 1417 ArchHandler_arm::modeThumbCode, 0, this, 0); 1418 addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM, 1419 ArchHandler_arm::delta32, 8, &target, 0); 1420 std::string name = std::string(targetName) + "$shim"; 1421 StringRef tmp(name); 1422 _name = tmp.copy(file.allocator()); 1423 } 1424 1425 ~Thumb2ToArmShimAtom() override = default; 1426 1427 StringRef name() const override { 1428 return _name; 1429 } 1430 1431 ContentType contentType() const override { 1432 return DefinedAtom::typeCode; 1433 } 1434 1435 Alignment alignment() const override { return 4; } 1436 1437 uint64_t size() const override { 1438 return 12; 1439 } 1440 1441 ContentPermissions permissions() const override { 1442 return DefinedAtom::permR_X; 1443 } 1444 1445 ArrayRef<uint8_t> rawContent() const override { 1446 static const uint8_t bytes[] = 1447 { 0xDF, 0xF8, 0x04, 0xC0, // ldr ip, pc + 4 1448 0xFF, 0x44, // add ip, pc, ip 1449 0x60, 0x47, // ldr pc, [ip] 1450 0x00, 0x00, 0x00, 0x00 }; // .long target - this 1451 assert(sizeof(bytes) == size()); 1452 return llvm::makeArrayRef(bytes, sizeof(bytes)); 1453 } 1454 private: 1455 StringRef _name; 1456 }; 1457 1458 class ArmToThumbShimAtom : public SimpleDefinedAtom { 1459 public: 1460 ArmToThumbShimAtom(MachOFile &file, StringRef targetName, 1461 const DefinedAtom &target) 1462 : SimpleDefinedAtom(file) { 1463 addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM, 1464 ArchHandler_arm::delta32, 12, &target, 0); 1465 std::string name = std::string(targetName) + "$shim"; 1466 StringRef tmp(name); 1467 _name = tmp.copy(file.allocator()); 1468 } 1469 1470 ~ArmToThumbShimAtom() override = default; 1471 1472 StringRef name() const override { 1473 return _name; 1474 } 1475 1476 ContentType contentType() const override { 1477 return DefinedAtom::typeCode; 1478 } 1479 1480 Alignment alignment() const override { return 4; } 1481 1482 uint64_t size() const override { 1483 return 16; 1484 } 1485 1486 ContentPermissions permissions() const override { 1487 return DefinedAtom::permR_X; 1488 } 1489 1490 ArrayRef<uint8_t> rawContent() const override { 1491 static const uint8_t bytes[] = 1492 { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 4 1493 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip 1494 0x1C, 0xFF, 0x2F, 0xE1, // ldr pc, [ip] 1495 0x00, 0x00, 0x00, 0x00 }; // .long target - this 1496 assert(sizeof(bytes) == size()); 1497 return llvm::makeArrayRef(bytes, sizeof(bytes)); 1498 } 1499 private: 1500 StringRef _name; 1501 }; 1502 1503 const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file, 1504 bool thumbToArm, 1505 const DefinedAtom &target) { 1506 bool isStub = (target.contentType() == DefinedAtom::typeStub); 1507 StringRef targetName = isStub ? stubName(target) : target.name(); 1508 if (thumbToArm) 1509 return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target); 1510 else 1511 return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target); 1512 } 1513 1514 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() { 1515 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm()); 1516 } 1517 1518 } // namespace mach_o 1519 } // namespace lld 1520