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