summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
commitb64793999546ed8adebaeebd9d8345d18db8927d (patch)
tree4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
parentAdd support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff)
downloadwireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz
wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp')
-rw-r--r--gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp1523
1 files changed, 0 insertions, 1523 deletions
diff --git a/gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
deleted file mode 100644
index 2f663c660f5..00000000000
--- a/gnu/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ /dev/null
@@ -1,1523 +0,0 @@
-//===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ArchHandler.h"
-#include "Atoms.h"
-#include "MachONormalizedFileBinaryUtils.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-
-using namespace llvm::MachO;
-using namespace lld::mach_o::normalized;
-
-namespace lld {
-namespace mach_o {
-
-using llvm::support::ulittle32_t;
-using llvm::support::little32_t;
-
-
-class ArchHandler_arm : public ArchHandler {
-public:
- ArchHandler_arm() = default;
- ~ArchHandler_arm() override = default;
-
- const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
-
- Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
-
- const ArchHandler::StubInfo &stubInfo() override;
- bool isCallSite(const Reference &) override;
- bool isPointer(const Reference &) override;
- bool isPairedReloc(const normalized::Relocation &) override;
- bool isNonCallBranch(const Reference &) override;
-
- bool needsCompactUnwind() override {
- return false;
- }
- Reference::KindValue imageOffsetKind() override {
- return invalid;
- }
- Reference::KindValue imageOffsetKindIndirect() override {
- return invalid;
- }
-
- Reference::KindValue unwindRefToPersonalityFunctionKind() override {
- return invalid;
- }
-
- Reference::KindValue unwindRefToCIEKind() override {
- return invalid;
- }
-
- Reference::KindValue unwindRefToFunctionKind() override {
- return invalid;
- }
-
- Reference::KindValue unwindRefToEhFrameKind() override {
- return invalid;
- }
-
- Reference::KindValue lazyImmediateLocationKind() override {
- return lazyImmediateLocation;
- }
-
- Reference::KindValue pointerKind() override {
- return invalid;
- }
-
- uint32_t dwarfCompactUnwindType() override {
- // FIXME
- return -1;
- }
-
- llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
- llvm::Error
- getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap, bool scatterable,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
-
- void generateAtomContent(const DefinedAtom &atom, bool relocatable,
- FindAddressForAtom findAddress,
- FindAddressForAtom findSectionAddress,
- uint64_t imageBaseAddress,
- llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
-
- void appendSectionRelocations(const DefinedAtom &atom,
- uint64_t atomSectionOffset,
- const Reference &ref,
- FindSymbolIndexForAtom,
- FindSectionIndexForAtom,
- FindAddressForAtom,
- normalized::Relocations &) override;
-
- void addAdditionalReferences(MachODefinedAtom &atom) override;
-
- bool isDataInCodeTransition(Reference::KindValue refKind) override {
- switch (refKind) {
- case modeThumbCode:
- case modeArmCode:
- case modeData:
- return true;
- default:
- return false;
- break;
- }
- }
-
- Reference::KindValue dataInCodeTransitionStart(
- const MachODefinedAtom &atom) override {
- return modeData;
- }
-
- Reference::KindValue dataInCodeTransitionEnd(
- const MachODefinedAtom &atom) override {
- return atom.isThumb() ? modeThumbCode : modeArmCode;
- }
-
- bool isThumbFunction(const DefinedAtom &atom) override;
- const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
- const DefinedAtom &) override;
-
-private:
- friend class Thumb2ToArmShimAtom;
- friend class ArmToThumbShimAtom;
-
- static const Registry::KindStrings _sKindStrings[];
- static const StubInfo _sStubInfoArmPIC;
-
- enum ArmKind : Reference::KindValue {
- invalid, /// for error condition
-
- modeThumbCode, /// Content starting at this offset is thumb.
- modeArmCode, /// Content starting at this offset is arm.
- modeData, /// Content starting at this offset is data.
-
- // Kinds found in mach-o .o files:
- thumb_bl22, /// ex: bl _foo
- thumb_b22, /// ex: b _foo
- thumb_movw, /// ex: movw r1, :lower16:_foo
- thumb_movt, /// ex: movt r1, :lower16:_foo
- thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
- thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
- arm_bl24, /// ex: bl _foo
- arm_b24, /// ex: b _foo
- arm_movw, /// ex: movw r1, :lower16:_foo
- arm_movt, /// ex: movt r1, :lower16:_foo
- arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
- arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
- pointer32, /// ex: .long _foo
- delta32, /// ex: .long _foo - .
-
- // Kinds introduced by Passes:
- lazyPointer, /// Location contains a lazy pointer.
- lazyImmediateLocation, /// Location contains immediate value used in stub.
- };
-
- // Utility functions for inspecting/updating instructions.
- static bool isThumbMovw(uint32_t instruction);
- static bool isThumbMovt(uint32_t instruction);
- static bool isArmMovw(uint32_t instruction);
- static bool isArmMovt(uint32_t instruction);
- static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t);
- static int32_t getDisplacementFromArmBranch(uint32_t instruction);
- static uint16_t getWordFromThumbMov(uint32_t instruction);
- static uint16_t getWordFromArmMov(uint32_t instruction);
- static uint32_t clearThumbBit(uint32_t value, const Atom *target);
- static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp,
- bool targetIsThumb);
- static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia,
- int32_t disp, bool targetThumb);
- static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
- static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
-
- StringRef stubName(const DefinedAtom &);
- bool useExternalRelocationTo(const Atom &target);
-
- void applyFixupFinal(const Reference &ref, uint8_t *location,
- uint64_t fixupAddress, uint64_t targetAddress,
- uint64_t inAtomAddress, bool &thumbMode,
- bool targetIsThumb);
-
- void applyFixupRelocatable(const Reference &ref, uint8_t *location,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress, bool &thumbMode,
- bool targetIsThumb);
-};
-
-//===----------------------------------------------------------------------===//
-// ArchHandler_arm
-//===----------------------------------------------------------------------===//
-
-const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
- LLD_KIND_STRING_ENTRY(invalid),
- LLD_KIND_STRING_ENTRY(modeThumbCode),
- LLD_KIND_STRING_ENTRY(modeArmCode),
- LLD_KIND_STRING_ENTRY(modeData),
- LLD_KIND_STRING_ENTRY(thumb_bl22),
- LLD_KIND_STRING_ENTRY(thumb_b22),
- LLD_KIND_STRING_ENTRY(thumb_movw),
- LLD_KIND_STRING_ENTRY(thumb_movt),
- LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
- LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
- LLD_KIND_STRING_ENTRY(arm_bl24),
- LLD_KIND_STRING_ENTRY(arm_b24),
- LLD_KIND_STRING_ENTRY(arm_movw),
- LLD_KIND_STRING_ENTRY(arm_movt),
- LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
- LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
- LLD_KIND_STRING_ENTRY(pointer32),
- LLD_KIND_STRING_ENTRY(delta32),
- LLD_KIND_STRING_ENTRY(lazyPointer),
- LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
- LLD_KIND_STRING_END
-};
-
-const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
- "dyld_stub_binder",
-
- // References in lazy pointer
- { Reference::KindArch::ARM, pointer32, 0, 0 },
- { Reference::KindArch::ARM, lazyPointer, 0, 0 },
-
- // GOT pointer to dyld_stub_binder
- { Reference::KindArch::ARM, pointer32, 0, 0 },
-
- // arm code alignment 2^2
- 2,
-
- // Stub size and code
- 16,
- { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 12
- 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
- 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
- 0x00, 0x00, 0x00, 0x00 }, // .long L_foo$lazy_ptr - (L1$scv + 8)
- { Reference::KindArch::ARM, delta32, 12, 0 },
- { false, 0, 0, 0 },
-
- // Stub Helper size and code
- 12,
- { 0x00, 0xC0, 0x9F, 0xE5, // ldr ip, [pc, #0]
- 0x00, 0x00, 0x00, 0xEA, // b _helperhelper
- 0x00, 0x00, 0x00, 0x00 }, // .long lazy-info-offset
- { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
- { Reference::KindArch::ARM, arm_b24, 4, 0 },
-
- // Stub helper image cache content type
- DefinedAtom::typeGOT,
-
- // Stub Helper-Common size and code
- 36,
- // Stub helper alignment
- 2,
- { // push lazy-info-offset
- 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
- // push address of dyld_mageLoaderCache
- 0x10, 0xC0, 0x9F, 0xE5, // ldr ip, L1
- 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
- 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
- // jump through dyld_stub_binder
- 0x08, 0xC0, 0x9F, 0xE5, // ldr ip, L2
- 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
- 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
- 0x00, 0x00, 0x00, 0x00, // L1: .long fFastStubGOTAtom - (helper+16)
- 0x00, 0x00, 0x00, 0x00 }, // L2: .long dyld_stub_binder - (helper+28)
- { Reference::KindArch::ARM, delta32, 28, 0xC },
- { false, 0, 0, 0 },
- { Reference::KindArch::ARM, delta32, 32, 0x04 },
- { false, 0, 0, 0 }
-};
-
-const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
- // If multiple kinds of stubs are supported, select which StubInfo here.
- return _sStubInfoArmPIC;
-}
-
-bool ArchHandler_arm::isCallSite(const Reference &ref) {
- switch (ref.kindValue()) {
- case thumb_b22:
- case thumb_bl22:
- case arm_b24:
- case arm_bl24:
- return true;
- default:
- return false;
- }
-}
-
-bool ArchHandler_arm::isPointer(const Reference &ref) {
- return (ref.kindValue() == pointer32);
-}
-
-bool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
- switch (ref.kindValue()) {
- case thumb_b22:
- case arm_b24:
- return true;
- default:
- return false;
- }
-}
-
-bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
- switch (reloc.type) {
- case ARM_RELOC_SECTDIFF:
- case ARM_RELOC_LOCAL_SECTDIFF:
- case ARM_RELOC_HALF_SECTDIFF:
- case ARM_RELOC_HALF:
- return true;
- default:
- return false;
- }
-}
-
-/// Trace references from stub atom to lazy pointer to target and get its name.
-StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
- assert(stubAtom.contentType() == DefinedAtom::typeStub);
- for (const Reference *ref : stubAtom) {
- if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
- if (lp->contentType() != DefinedAtom::typeLazyPointer)
- continue;
- for (const Reference *ref2 : *lp) {
- if (ref2->kindValue() != lazyPointer)
- continue;
- return ref2->target()->name();
- }
- }
- }
- return "stub";
-}
-
-/// Extract displacement from an ARM b/bl/blx instruction.
-int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
- // Sign-extend imm24
- int32_t displacement = (instruction & 0x00FFFFFF) << 2;
- if ((displacement & 0x02000000) != 0)
- displacement |= 0xFC000000;
- // If this is BLX and H bit set, add 2.
- if ((instruction & 0xFF000000) == 0xFB000000)
- displacement += 2;
- return displacement;
-}
-
-/// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed.
-uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
- int32_t displacement,
- bool targetIsThumb) {
- assert((displacement <= 33554428) && (displacement > (-33554432))
- && "arm branch out of range");
- bool is_blx = ((instruction & 0xF0000000) == 0xF0000000);
- uint32_t newInstruction = (instruction & 0xFF000000);
- uint32_t h = 0;
- if (targetIsThumb) {
- // Force use of BLX.
- newInstruction = 0xFA000000;
- if (!is_blx) {
- assert(((instruction & 0xF0000000) == 0xE0000000)
- && "no conditional arm blx");
- assert(((instruction & 0xFF000000) == 0xEB000000)
- && "no arm pc-rel BX instruction");
- }
- if (displacement & 2)
- h = 1;
- }
- else {
- // Force use of B/BL.
- if (is_blx)
- newInstruction = 0xEB000000;
- }
- newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF);
- return newInstruction;
-}
-
-/// Extract displacement from a thumb b/bl/blx instruction.
-int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction,
- uint32_t instrAddr) {
- bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
- uint32_t s = (instruction >> 10) & 0x1;
- uint32_t j1 = (instruction >> 29) & 0x1;
- uint32_t j2 = (instruction >> 27) & 0x1;
- uint32_t imm10 = instruction & 0x3FF;
- uint32_t imm11 = (instruction >> 16) & 0x7FF;
- uint32_t i1 = (j1 == s);
- uint32_t i2 = (j2 == s);
- uint32_t dis =
- (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
- int32_t sdis = dis;
- int32_t result = s ? (sdis | 0xFE000000) : sdis;
- if (is_blx && (instrAddr & 0x2)) {
- // The thumb blx instruction always has low bit of imm11 as zero. The way
- // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that
- // the blx instruction always 4-byte aligns the pc before adding the
- // displacement from the blx. We must emulate that when decoding this.
- result -= 2;
- }
- return result;
-}
-
-/// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed.
-uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
- uint32_t instrAddr,
- int32_t displacement,
- bool targetIsThumb) {
- assert((displacement <= 16777214) && (displacement > (-16777216))
- && "thumb branch out of range");
- bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
- bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
- bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
- uint32_t newInstruction = (instruction & 0xD000F800);
- if (is_bl || is_blx) {
- if (targetIsThumb) {
- newInstruction = 0xD000F000; // Use bl
- } else {
- newInstruction = 0xC000F000; // Use blx
- // See note in getDisplacementFromThumbBranch() about blx.
- if (instrAddr & 0x2)
- displacement += 2;
- }
- } else if (is_b) {
- assert(targetIsThumb && "no pc-rel thumb branch instruction that "
- "switches to arm mode");
- }
- else {
- llvm_unreachable("thumb branch22 reloc on a non-branch instruction");
- }
- uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
- uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
- uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
- uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
- uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
- uint32_t j1 = (i1 == s);
- uint32_t j2 = (i2 == s);
- uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
- uint32_t firstDisp = (s << 10) | imm10;
- newInstruction |= (nextDisp << 16) | firstDisp;
- return newInstruction;
-}
-
-bool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
- return (instruction & 0x8000FBF0) == 0x0000F240;
-}
-
-bool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
- return (instruction & 0x8000FBF0) == 0x0000F2C0;
-}
-
-bool ArchHandler_arm::isArmMovw(uint32_t instruction) {
- return (instruction & 0x0FF00000) == 0x03000000;
-}
-
-bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
- return (instruction & 0x0FF00000) == 0x03400000;
-}
-
-uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
- assert(isThumbMovw(instruction) || isThumbMovt(instruction));
- uint32_t i = ((instruction & 0x00000400) >> 10);
- uint32_t imm4 = (instruction & 0x0000000F);
- uint32_t imm3 = ((instruction & 0x70000000) >> 28);
- uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
- return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
-}
-
-uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
- assert(isArmMovw(instruction) || isArmMovt(instruction));
- uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
- uint32_t imm12 = (instruction & 0x00000FFF);
- return (imm4 << 12) | imm12;
-}
-
-uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
- assert(isThumbMovw(instr) || isThumbMovt(instr));
- uint32_t imm4 = (word & 0xF000) >> 12;
- uint32_t i = (word & 0x0800) >> 11;
- uint32_t imm3 = (word & 0x0700) >> 8;
- uint32_t imm8 = word & 0x00FF;
- return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
-}
-
-uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
- assert(isArmMovw(instr) || isArmMovt(instr));
- uint32_t imm4 = (word & 0xF000) >> 12;
- uint32_t imm12 = word & 0x0FFF;
- return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
-}
-
-uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
- // The assembler often adds one to the address of a thumb function.
- // We need to undo that so it does not look like an addend.
- if (value & 1) {
- if (isa<DefinedAtom>(target)) {
- const MachODefinedAtom *machoTarget =
- reinterpret_cast<const MachODefinedAtom *>(target);
- if (machoTarget->isThumb())
- value &= -2; // mask off thumb-bit
- }
- }
- return value;
-}
-
-llvm::Error ArchHandler_arm::getReferenceInfo(
- const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
- uint64_t fixupAddress, bool isBig,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
- const lld::Atom **target, Reference::Addend *addend) {
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- uint64_t targetAddress;
- uint32_t instruction = *(const ulittle32_t *)fixupContent;
- int32_t displacement;
- switch (relocPattern(reloc)) {
- case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
- // ex: bl _foo (and _foo is undefined)
- if ((instruction & 0xD000F800) == 0x9000F000)
- *kind = thumb_b22;
- else
- *kind = thumb_bl22;
- if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- // Instruction contains branch to addend.
- displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
- *addend = fixupAddress + 4 + displacement;
- return llvm::Error::success();
- case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
- // ex: bl _foo (and _foo is defined)
- if ((instruction & 0xD000F800) == 0x9000F000)
- *kind = thumb_b22;
- else
- *kind = thumb_bl22;
- displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
- targetAddress = fixupAddress + 4 + displacement;
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
- // ex: bl _foo+4 (and _foo is defined)
- if ((instruction & 0xD000F800) == 0x9000F000)
- *kind = thumb_b22;
- else
- *kind = thumb_bl22;
- displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
- targetAddress = fixupAddress + 4 + displacement;
- if (auto ec = atomFromAddress(0, reloc.value, target, addend))
- return ec;
- // reloc.value is target atom's address. Instruction contains branch
- // to atom+addend.
- *addend += (targetAddress - reloc.value);
- return llvm::Error::success();
- case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
- // ex: bl _foo (and _foo is undefined)
- if (((instruction & 0x0F000000) == 0x0A000000)
- && ((instruction & 0xF0000000) != 0xF0000000))
- *kind = arm_b24;
- else
- *kind = arm_bl24;
- if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- // Instruction contains branch to addend.
- displacement = getDisplacementFromArmBranch(instruction);
- *addend = fixupAddress + 8 + displacement;
- return llvm::Error::success();
- case ARM_RELOC_BR24 | rPcRel | rLength4:
- // ex: bl _foo (and _foo is defined)
- if (((instruction & 0x0F000000) == 0x0A000000)
- && ((instruction & 0xF0000000) != 0xF0000000))
- *kind = arm_b24;
- else
- *kind = arm_bl24;
- displacement = getDisplacementFromArmBranch(instruction);
- targetAddress = fixupAddress + 8 + displacement;
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
- // ex: bl _foo+4 (and _foo is defined)
- if (((instruction & 0x0F000000) == 0x0A000000)
- && ((instruction & 0xF0000000) != 0xF0000000))
- *kind = arm_b24;
- else
- *kind = arm_bl24;
- displacement = getDisplacementFromArmBranch(instruction);
- targetAddress = fixupAddress + 8 + displacement;
- if (auto ec = atomFromAddress(0, reloc.value, target, addend))
- return ec;
- // reloc.value is target atom's address. Instruction contains branch
- // to atom+addend.
- *addend += (targetAddress - reloc.value);
- return llvm::Error::success();
- case ARM_RELOC_VANILLA | rExtern | rLength4:
- // ex: .long _foo (and _foo is undefined)
- *kind = pointer32;
- if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = instruction;
- return llvm::Error::success();
- case ARM_RELOC_VANILLA | rLength4:
- // ex: .long _foo (and _foo is defined)
- *kind = pointer32;
- if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
- return ec;
- *addend = clearThumbBit((uint32_t) * addend, *target);
- return llvm::Error::success();
- case ARM_RELOC_VANILLA | rScattered | rLength4:
- // ex: .long _foo+a (and _foo is defined)
- *kind = pointer32;
- if (auto ec = atomFromAddress(0, reloc.value, target, addend))
- return ec;
- *addend += (clearThumbBit(instruction, *target) - reloc.value);
- return llvm::Error::success();
- default:
- return llvm::make_error<GenericError>("unsupported arm relocation type");
- }
- return llvm::Error::success();
-}
-
-llvm::Error
-ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool isBig,
- bool scatterable,
- FindAtomBySectionAndAddress atomFromAddr,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) {
- bool pointerDiff = false;
- bool funcRel;
- bool top;
- bool thumbReloc;
- switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo) << 16 |
- ARM_RELOC_PAIR | rScattered | rLenThmbLo):
- // ex: movw r1, :lower16:(_x-L1) [thumb mode]
- *kind = thumb_movw_funcRel;
- funcRel = true;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi) << 16 |
- ARM_RELOC_PAIR | rScattered | rLenThmbHi):
- // ex: movt r1, :upper16:(_x-L1) [thumb mode]
- *kind = thumb_movt_funcRel;
- funcRel = true;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo) << 16 |
- ARM_RELOC_PAIR | rScattered | rLenArmLo):
- // ex: movw r1, :lower16:(_x-L1) [arm mode]
- *kind = arm_movw_funcRel;
- funcRel = true;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi) << 16 |
- ARM_RELOC_PAIR | rScattered | rLenArmHi):
- // ex: movt r1, :upper16:(_x-L1) [arm mode]
- *kind = arm_movt_funcRel;
- funcRel = true;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rLenThmbLo) << 16 |
- ARM_RELOC_PAIR | rLenThmbLo):
- // ex: movw r1, :lower16:_x [thumb mode]
- *kind = thumb_movw;
- funcRel = false;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rLenThmbHi) << 16 |
- ARM_RELOC_PAIR | rLenThmbHi):
- // ex: movt r1, :upper16:_x [thumb mode]
- *kind = thumb_movt;
- funcRel = false;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rLenArmLo) << 16 |
- ARM_RELOC_PAIR | rLenArmLo):
- // ex: movw r1, :lower16:_x [arm mode]
- *kind = arm_movw;
- funcRel = false;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rLenArmHi) << 16 |
- ARM_RELOC_PAIR | rLenArmHi):
- // ex: movt r1, :upper16:_x [arm mode]
- *kind = arm_movt;
- funcRel = false;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLenThmbLo) << 16 |
- ARM_RELOC_PAIR | rLenThmbLo):
- // ex: movw r1, :lower16:_x+a [thumb mode]
- *kind = thumb_movw;
- funcRel = false;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLenThmbHi) << 16 |
- ARM_RELOC_PAIR | rLenThmbHi):
- // ex: movt r1, :upper16:_x+a [thumb mode]
- *kind = thumb_movt;
- funcRel = false;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLenArmLo) << 16 |
- ARM_RELOC_PAIR | rLenArmLo):
- // ex: movw r1, :lower16:_x+a [arm mode]
- *kind = arm_movw;
- funcRel = false;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLenArmHi) << 16 |
- ARM_RELOC_PAIR | rLenArmHi):
- // ex: movt r1, :upper16:_x+a [arm mode]
- *kind = arm_movt;
- funcRel = false;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLenThmbLo) << 16 |
- ARM_RELOC_PAIR | rLenThmbLo):
- // ex: movw r1, :lower16:_undef [thumb mode]
- *kind = thumb_movw;
- funcRel = false;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLenThmbHi) << 16 |
- ARM_RELOC_PAIR | rLenThmbHi):
- // ex: movt r1, :upper16:_undef [thumb mode]
- *kind = thumb_movt;
- funcRel = false;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLenArmLo) << 16 |
- ARM_RELOC_PAIR | rLenArmLo):
- // ex: movw r1, :lower16:_undef [arm mode]
- *kind = arm_movw;
- funcRel = false;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLenArmHi) << 16 |
- ARM_RELOC_PAIR | rLenArmHi):
- // ex: movt r1, :upper16:_undef [arm mode]
- *kind = arm_movt;
- funcRel = false;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength4):
- case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength4):
- // ex: .long _foo - .
- pointerDiff = true;
- break;
- default:
- return llvm::make_error<GenericError>("unsupported arm relocation pair");
- }
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- uint32_t instruction = *(const ulittle32_t *)fixupContent;
- uint32_t value;
- uint32_t fromAddress;
- uint32_t toAddress;
- uint16_t instruction16;
- uint16_t other16;
- const lld::Atom *fromTarget;
- Reference::Addend offsetInTo;
- Reference::Addend offsetInFrom;
- if (pointerDiff) {
- toAddress = reloc1.value;
- fromAddress = reloc2.value;
- if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
- return ec;
- if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
- return ec;
- if (scatterable && (fromTarget != inAtom))
- return llvm::make_error<GenericError>(
- "SECTDIFF relocation where subtrahend label is not in atom");
- *kind = delta32;
- value = clearThumbBit(instruction, *target);
- *addend = (int32_t)(value - (toAddress - fixupAddress));
- } else if (funcRel) {
- toAddress = reloc1.value;
- fromAddress = reloc2.value;
- if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
- return ec;
- if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
- return ec;
- if (fromTarget != inAtom)
- return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
- " where subtrahend label is not in atom");
- other16 = (reloc2.offset & 0xFFFF);
- if (thumbReloc) {
- if (top) {
- if (!isThumbMovt(instruction))
- return llvm::make_error<GenericError>("expected movt instruction");
- }
- else {
- if (!isThumbMovw(instruction))
- return llvm::make_error<GenericError>("expected movw instruction");
- }
- instruction16 = getWordFromThumbMov(instruction);
- }
- else {
- if (top) {
- if (!isArmMovt(instruction))
- return llvm::make_error<GenericError>("expected movt instruction");
- }
- else {
- if (!isArmMovw(instruction))
- return llvm::make_error<GenericError>("expected movw instruction");
- }
- instruction16 = getWordFromArmMov(instruction);
- }
- if (top)
- value = (instruction16 << 16) | other16;
- else
- value = (other16 << 16) | instruction16;
- value = clearThumbBit(value, *target);
- int64_t ta = (int64_t) value - (toAddress - fromAddress);
- *addend = ta - offsetInFrom;
- return llvm::Error::success();
- } else {
- uint32_t sectIndex;
- if (thumbReloc) {
- if (top) {
- if (!isThumbMovt(instruction))
- return llvm::make_error<GenericError>("expected movt instruction");
- }
- else {
- if (!isThumbMovw(instruction))
- return llvm::make_error<GenericError>("expected movw instruction");
- }
- instruction16 = getWordFromThumbMov(instruction);
- }
- else {
- if (top) {
- if (!isArmMovt(instruction))
- return llvm::make_error<GenericError>("expected movt instruction");
- }
- else {
- if (!isArmMovw(instruction))
- return llvm::make_error<GenericError>("expected movw instruction");
- }
- instruction16 = getWordFromArmMov(instruction);
- }
- other16 = (reloc2.offset & 0xFFFF);
- if (top)
- value = (instruction16 << 16) | other16;
- else
- value = (other16 << 16) | instruction16;
- if (reloc1.isExtern) {
- if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
- return ec;
- *addend = value;
- } else {
- if (reloc1.scattered) {
- toAddress = reloc1.value;
- sectIndex = 0;
- } else {
- toAddress = value;
- sectIndex = reloc1.symbol;
- }
- if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
- return ec;
- *addend = value - toAddress;
- }
- }
-
- return llvm::Error::success();
-}
-
-void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress,
- bool &thumbMode, bool targetIsThumb) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return;
- assert(ref.kindArch() == Reference::KindArch::ARM);
- ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
- int32_t displacement;
- uint16_t value16;
- uint32_t value32;
- switch (static_cast<ArmKind>(ref.kindValue())) {
- case modeThumbCode:
- thumbMode = true;
- break;
- case modeArmCode:
- thumbMode = false;
- break;
- case modeData:
- break;
- case thumb_b22:
- case thumb_bl22:
- assert(thumbMode);
- displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
- value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
- displacement, targetIsThumb);
- *loc32 = value32;
- break;
- case thumb_movw:
- assert(thumbMode);
- value16 = (targetAddress + ref.addend()) & 0xFFFF;
- if (targetIsThumb)
- value16 |= 1;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case thumb_movt:
- assert(thumbMode);
- value16 = (targetAddress + ref.addend()) >> 16;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case thumb_movw_funcRel:
- assert(thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
- if (targetIsThumb)
- value16 |= 1;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case thumb_movt_funcRel:
- assert(thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case arm_b24:
- case arm_bl24:
- assert(!thumbMode);
- displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
- value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
- *loc32 = value32;
- break;
- case arm_movw:
- assert(!thumbMode);
- value16 = (targetAddress + ref.addend()) & 0xFFFF;
- if (targetIsThumb)
- value16 |= 1;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case arm_movt:
- assert(!thumbMode);
- value16 = (targetAddress + ref.addend()) >> 16;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case arm_movw_funcRel:
- assert(!thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
- if (targetIsThumb)
- value16 |= 1;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case arm_movt_funcRel:
- assert(!thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case pointer32:
- if (targetIsThumb)
- *loc32 = targetAddress + ref.addend() + 1;
- else
- *loc32 = targetAddress + ref.addend();
- break;
- case delta32:
- if (targetIsThumb)
- *loc32 = targetAddress - fixupAddress + ref.addend() + 1;
- else
- *loc32 = targetAddress - fixupAddress + ref.addend();
- break;
- case lazyPointer:
- // do nothing
- break;
- case lazyImmediateLocation:
- *loc32 = ref.addend();
- break;
- case invalid:
- llvm_unreachable("invalid ARM Reference Kind");
- break;
- }
-}
-
-void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
- bool relocatable,
- FindAddressForAtom findAddress,
- FindAddressForAtom findSectionAddress,
- uint64_t imageBaseAddress,
- llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
- // Copy raw bytes.
- std::copy(atom.rawContent().begin(), atom.rawContent().end(),
- atomContentBuffer.begin());
- // Apply fix-ups.
- bool thumbMode = false;
- for (const Reference *ref : atom) {
- uint32_t offset = ref->offsetInAtom();
- const Atom *target = ref->target();
- uint64_t targetAddress = 0;
- bool targetIsThumb = false;
- if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) {
- targetAddress = findAddress(*target);
- targetIsThumb = isThumbFunction(*defTarg);
- }
- uint64_t atomAddress = findAddress(atom);
- uint64_t fixupAddress = atomAddress + offset;
- if (relocatable) {
- applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
- targetAddress, atomAddress, thumbMode,
- targetIsThumb);
- } else {
- applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
- targetAddress, atomAddress, thumbMode, targetIsThumb);
- }
- }
-}
-
-bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
- // Undefined symbols are referenced via external relocations.
- if (isa<UndefinedAtom>(&target))
- return true;
- if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
- switch (defAtom->merge()) {
- case DefinedAtom::mergeAsTentative:
- // Tentative definitions are referenced via external relocations.
- return true;
- case DefinedAtom::mergeAsWeak:
- case DefinedAtom::mergeAsWeakAndAddressUsed:
- // Global weak-defs are referenced via external relocations.
- return (defAtom->scope() == DefinedAtom::scopeGlobal);
- default:
- break;
- }
- }
- // Everything else is reference via an internal relocation.
- return false;
-}
-
-void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress,
- bool &thumbMode,
- bool targetIsThumb) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return;
- assert(ref.kindArch() == Reference::KindArch::ARM);
- bool useExternalReloc = useExternalRelocationTo(*ref.target());
- ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
- int32_t displacement;
- uint16_t value16;
- uint32_t value32;
- bool targetIsUndef = isa<UndefinedAtom>(ref.target());
- switch (static_cast<ArmKind>(ref.kindValue())) {
- case modeThumbCode:
- thumbMode = true;
- break;
- case modeArmCode:
- thumbMode = false;
- break;
- case modeData:
- break;
- case thumb_b22:
- case thumb_bl22:
- assert(thumbMode);
- if (useExternalReloc)
- displacement = (ref.addend() - (fixupAddress + 4));
- else
- displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
- value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
- displacement,
- targetIsUndef || targetIsThumb);
- *loc32 = value32;
- break;
- case thumb_movw:
- assert(thumbMode);
- if (useExternalReloc)
- value16 = ref.addend() & 0xFFFF;
- else
- value16 = (targetAddress + ref.addend()) & 0xFFFF;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case thumb_movt:
- assert(thumbMode);
- if (useExternalReloc)
- value16 = ref.addend() >> 16;
- else
- value16 = (targetAddress + ref.addend()) >> 16;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case thumb_movw_funcRel:
- assert(thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case thumb_movt_funcRel:
- assert(thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
- *loc32 = setWordFromThumbMov(*loc32, value16);
- break;
- case arm_b24:
- case arm_bl24:
- assert(!thumbMode);
- if (useExternalReloc)
- displacement = (ref.addend() - (fixupAddress + 8));
- else
- displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
- value32 = setDisplacementInArmBranch(*loc32, displacement,
- targetIsThumb);
- *loc32 = value32;
- break;
- case arm_movw:
- assert(!thumbMode);
- if (useExternalReloc)
- value16 = ref.addend() & 0xFFFF;
- else
- value16 = (targetAddress + ref.addend()) & 0xFFFF;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case arm_movt:
- assert(!thumbMode);
- if (useExternalReloc)
- value16 = ref.addend() >> 16;
- else
- value16 = (targetAddress + ref.addend()) >> 16;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case arm_movw_funcRel:
- assert(!thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case arm_movt_funcRel:
- assert(!thumbMode);
- value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
- *loc32 = setWordFromArmMov(*loc32, value16);
- break;
- case pointer32:
- *loc32 = targetAddress + ref.addend();
- break;
- case delta32:
- *loc32 = targetAddress - fixupAddress + ref.addend();
- break;
- case lazyPointer:
- case lazyImmediateLocation:
- // do nothing
- break;
- case invalid:
- llvm_unreachable("invalid ARM Reference Kind");
- break;
- }
-}
-
-void ArchHandler_arm::appendSectionRelocations(
- const DefinedAtom &atom,
- uint64_t atomSectionOffset,
- const Reference &ref,
- FindSymbolIndexForAtom symbolIndexForAtom,
- FindSectionIndexForAtom sectionIndexForAtom,
- FindAddressForAtom addressForAtom,
- normalized::Relocations &relocs) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return;
- assert(ref.kindArch() == Reference::KindArch::ARM);
- uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
- bool useExternalReloc = useExternalRelocationTo(*ref.target());
- uint32_t targetAtomAddress;
- uint32_t fromAtomAddress;
- uint16_t other16;
- switch (static_cast<ArmKind>(ref.kindValue())) {
- case modeThumbCode:
- case modeArmCode:
- case modeData:
- // Do nothing.
- break;
- case thumb_b22:
- case thumb_bl22:
- if (useExternalReloc) {
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_THUMB_RELOC_BR22 | rExtern | rPcRel | rLength4);
- } else {
- if (ref.addend() != 0)
- appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
- ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
- else
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_THUMB_RELOC_BR22 | rPcRel | rLength4);
- }
- break;
- case thumb_movw:
- if (useExternalReloc) {
- other16 = ref.addend() >> 16;
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_RELOC_HALF | rExtern | rLenThmbLo);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenThmbLo);
- } else {
- targetAtomAddress = addressForAtom(*ref.target());
- if (ref.addend() != 0) {
- other16 = (targetAtomAddress + ref.addend()) >> 16;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF | rScattered | rLenThmbLo);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenThmbLo);
- } else {
- other16 = (targetAtomAddress + ref.addend()) >> 16;
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_RELOC_HALF | rLenThmbLo);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenThmbLo);
- }
- }
- break;
- case thumb_movt:
- if (useExternalReloc) {
- other16 = ref.addend() & 0xFFFF;
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_RELOC_HALF | rExtern | rLenThmbHi);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenThmbHi);
- } else {
- targetAtomAddress = addressForAtom(*ref.target());
- if (ref.addend() != 0) {
- other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF | rScattered | rLenThmbHi);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenThmbHi);
- } else {
- other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_RELOC_HALF | rLenThmbHi);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenThmbHi);
- }
- }
- break;
- case thumb_movw_funcRel:
- fromAtomAddress = addressForAtom(atom);
- targetAtomAddress = addressForAtom(*ref.target());
- other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
- appendReloc(relocs, other16, 0, fromAtomAddress,
- ARM_RELOC_PAIR | rScattered | rLenThmbLo);
- break;
- case thumb_movt_funcRel:
- fromAtomAddress = addressForAtom(atom);
- targetAtomAddress = addressForAtom(*ref.target());
- other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
- appendReloc(relocs, other16, 0, fromAtomAddress,
- ARM_RELOC_PAIR | rScattered | rLenThmbHi);
- break;
- case arm_b24:
- case arm_bl24:
- if (useExternalReloc) {
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_RELOC_BR24 | rExtern | rPcRel | rLength4);
- } else {
- if (ref.addend() != 0)
- appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
- ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
- else
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_RELOC_BR24 | rPcRel | rLength4);
- }
- break;
- case arm_movw:
- if (useExternalReloc) {
- other16 = ref.addend() >> 16;
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_RELOC_HALF | rExtern | rLenArmLo);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenArmLo);
- } else {
- targetAtomAddress = addressForAtom(*ref.target());
- if (ref.addend() != 0) {
- other16 = (targetAtomAddress + ref.addend()) >> 16;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF | rScattered | rLenArmLo);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenArmLo);
- } else {
- other16 = (targetAtomAddress + ref.addend()) >> 16;
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_RELOC_HALF | rLenArmLo);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenArmLo);
- }
- }
- break;
- case arm_movt:
- if (useExternalReloc) {
- other16 = ref.addend() & 0xFFFF;
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_RELOC_HALF | rExtern | rLenArmHi);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenArmHi);
- } else {
- targetAtomAddress = addressForAtom(*ref.target());
- if (ref.addend() != 0) {
- other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF | rScattered | rLenArmHi);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenArmHi);
- } else {
- other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_RELOC_HALF | rLenArmHi);
- appendReloc(relocs, other16, 0, 0,
- ARM_RELOC_PAIR | rLenArmHi);
- }
- }
- break;
- case arm_movw_funcRel:
- fromAtomAddress = addressForAtom(atom);
- targetAtomAddress = addressForAtom(*ref.target());
- other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
- appendReloc(relocs, other16, 0, fromAtomAddress,
- ARM_RELOC_PAIR | rScattered | rLenArmLo);
- break;
- case arm_movt_funcRel:
- fromAtomAddress = addressForAtom(atom);
- targetAtomAddress = addressForAtom(*ref.target());
- other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
- appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
- ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
- appendReloc(relocs, other16, 0, fromAtomAddress,
- ARM_RELOC_PAIR | rScattered | rLenArmHi);
- break;
- case pointer32:
- if (useExternalReloc) {
- appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
- ARM_RELOC_VANILLA | rExtern | rLength4);
- }
- else {
- if (ref.addend() != 0)
- appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
- ARM_RELOC_VANILLA | rScattered | rLength4);
- else
- appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
- ARM_RELOC_VANILLA | rLength4);
- }
- break;
- case delta32:
- appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
- ARM_RELOC_SECTDIFF | rScattered | rLength4);
- appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
- ref.offsetInAtom(),
- ARM_RELOC_PAIR | rScattered | rLength4);
- break;
- case lazyPointer:
- case lazyImmediateLocation:
- // do nothing
- break;
- case invalid:
- llvm_unreachable("invalid ARM Reference Kind");
- break;
- }
-}
-
-void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
- if (atom.isThumb()) {
- atom.addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
- }
-}
-
-bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
- for (const Reference *ref : atom) {
- if (ref->offsetInAtom() != 0)
- return false;
- if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
- continue;
- assert(ref->kindArch() == Reference::KindArch::ARM);
- if (ref->kindValue() == modeThumbCode)
- return true;
- }
- return false;
-}
-
-class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
-public:
- Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
- const DefinedAtom &target)
- : SimpleDefinedAtom(file) {
- addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
- ArchHandler_arm::modeThumbCode, 0, this, 0);
- addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
- ArchHandler_arm::delta32, 8, &target, 0);
- std::string name = std::string(targetName) + "$shim";
- StringRef tmp(name);
- _name = tmp.copy(file.allocator());
- }
-
- ~Thumb2ToArmShimAtom() override = default;
-
- StringRef name() const override {
- return _name;
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeCode;
- }
-
- Alignment alignment() const override { return 4; }
-
- uint64_t size() const override {
- return 12;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t bytes[] =
- { 0xDF, 0xF8, 0x04, 0xC0, // ldr ip, pc + 4
- 0xFF, 0x44, // add ip, pc, ip
- 0x60, 0x47, // ldr pc, [ip]
- 0x00, 0x00, 0x00, 0x00 }; // .long target - this
- assert(sizeof(bytes) == size());
- return llvm::makeArrayRef(bytes, sizeof(bytes));
- }
-private:
- StringRef _name;
-};
-
-class ArmToThumbShimAtom : public SimpleDefinedAtom {
-public:
- ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
- const DefinedAtom &target)
- : SimpleDefinedAtom(file) {
- addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
- ArchHandler_arm::delta32, 12, &target, 0);
- std::string name = std::string(targetName) + "$shim";
- StringRef tmp(name);
- _name = tmp.copy(file.allocator());
- }
-
- ~ArmToThumbShimAtom() override = default;
-
- StringRef name() const override {
- return _name;
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeCode;
- }
-
- Alignment alignment() const override { return 4; }
-
- uint64_t size() const override {
- return 16;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t bytes[] =
- { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 4
- 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
- 0x1C, 0xFF, 0x2F, 0xE1, // ldr pc, [ip]
- 0x00, 0x00, 0x00, 0x00 }; // .long target - this
- assert(sizeof(bytes) == size());
- return llvm::makeArrayRef(bytes, sizeof(bytes));
- }
-private:
- StringRef _name;
-};
-
-const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
- bool thumbToArm,
- const DefinedAtom &target) {
- bool isStub = (target.contentType() == DefinedAtom::typeStub);
- StringRef targetName = isStub ? stubName(target) : target.name();
- if (thumbToArm)
- return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
- else
- return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
-}
-
-std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
- return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
-}
-
-} // namespace mach_o
-} // namespace lld