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