From: Nick Kledzik Date: Wed, 16 Jul 2014 19:49:02 +0000 (+0000) Subject: [mach-o] refactor KindHandler into ArchHandler and simplify passes. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2458bec7e740643bdfa3c0e89d60704e225b78cb;p=platform%2Fupstream%2Fllvm.git [mach-o] refactor KindHandler into ArchHandler and simplify passes. All architecture specific handling is now done in the appropriate ArchHandler subclass. The StubsPass and GOTPass have been simplified. All architecture specific variations in stubs are now encoded in a table which is vended by the current ArchHandler. llvm-svn: 213187 --- diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index 99ae4e0..82c7821 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -24,7 +24,7 @@ using llvm::MachO::HeaderFileType; namespace lld { namespace mach_o { -class KindHandler; // defined in lib. this header is in include. +class ArchHandler; } class MachOLinkingContext : public LinkingContext { @@ -68,7 +68,7 @@ public: virtual uint64_t pageZeroSize() const { return _pageZeroSize; } virtual uint64_t pageSize() const { return _pageSize; } - mach_o::KindHandler &kindHandler() const; + mach_o::ArchHandler &archHandler() const; HeaderFileType outputMachOType() const { return _outputMachOType; } @@ -168,6 +168,15 @@ public: StringRef dyldPath() const { return "/usr/lib/dyld"; } + /// Stub creation Pass should be run. + bool needsStubsPass() const; + + // GOT createion Pass should be run. + bool needsGOTPass() const; + + /// Magic symbol name stubs will need to help lazy bind. + StringRef binderSymbolName() const; + static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype); static Arch archFromName(StringRef archName); static StringRef nameFromArch(Arch arch); @@ -211,7 +220,7 @@ private: bool _printAtoms; bool _testingLibResolution; StringRef _bundleLoader; - mutable std::unique_ptr _kindHandler; + mutable std::unique_ptr _archHandler; mutable std::unique_ptr _writer; }; diff --git a/lld/include/lld/ReaderWriter/Reader.h b/lld/include/lld/ReaderWriter/Reader.h index 0bfe2ad..694b302 100644 --- a/lld/include/lld/ReaderWriter/Reader.h +++ b/lld/include/lld/ReaderWriter/Reader.h @@ -33,6 +33,7 @@ class File; class LinkingContext; class PECOFFLinkingContext; class TargetHandlerBase; +class MachOLinkingContext; /// \brief An abstract class for reading object files, library files, and /// executable files. @@ -122,7 +123,7 @@ public: void addSupportNativeObjects(); void addSupportCOFFObjects(PECOFFLinkingContext &); void addSupportCOFFImportLibraries(); - void addSupportMachOObjects(StringRef archName); + void addSupportMachOObjects(const MachOLinkingContext &); void addSupportELFObjects(bool atomizeStrings, TargetHandlerBase *handler); void addSupportELFDynamicSharedObjects(bool useShlibUndefines, TargetHandlerBase *handler); diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index 27946a7..64a7fd4 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -79,7 +79,7 @@ bool DarwinLdDriver::linkMachO(int argc, const char *argv[], return true; // Register possible input file parsers. - ctx.registry().addSupportMachOObjects(ctx.archName()); + ctx.registry().addSupportMachOObjects(ctx); ctx.registry().addSupportArchives(ctx.logInputFiles()); ctx.registry().addSupportNativeObjects(); ctx.registry().addSupportYamlFiles(); diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp new file mode 100644 index 0000000..8dfafc6 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp @@ -0,0 +1,109 @@ +//===- lib/FileFormat/MachO/ArchHandler.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/ErrorHandling.h" + +using namespace llvm::MachO; +using namespace lld::mach_o::normalized; + +namespace lld { +namespace mach_o { + + +ArchHandler::ArchHandler() { +} + +ArchHandler::~ArchHandler() { +} + +std::unique_ptr ArchHandler::create( + MachOLinkingContext::Arch arch) { + switch (arch) { + case MachOLinkingContext::arch_x86_64: + return create_x86_64(); + case MachOLinkingContext::arch_x86: + return create_x86(); + case MachOLinkingContext::arch_armv6: + case MachOLinkingContext::arch_armv7: + case MachOLinkingContext::arch_armv7s: + return create_arm(); + default: + llvm_unreachable("Unknown arch"); + } +} + + +bool ArchHandler::isLazyPointer(const Reference &ref) { + // A lazy bind entry is needed for a lazy pointer. + const StubInfo &info = stubInfo(); + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch) + return false; + return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind); +} + + +ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) { + assert((reloc.type & 0xFFF0) == 0); + uint16_t result = reloc.type; + if (reloc.scattered) + result |= rScattered; + if (reloc.pcRel) + result |= rPcRel; + if (reloc.isExtern) + result |= rExtern; + switch(reloc.length) { + case 0: + break; + case 1: + result |= rLength2; + break; + case 2: + result |= rLength4; + break; + case 3: + result |= rLength8; + break; + default: + llvm_unreachable("bad r_length"); + } + return result; +} + +int16_t ArchHandler::readS16(bool swap, const uint8_t *addr) { + return read16(swap, *reinterpret_cast(addr)); +} + +int32_t ArchHandler::readS32(bool swap, const uint8_t *addr) { + return read32(swap, *reinterpret_cast(addr)); +} + +uint32_t ArchHandler::readU32(bool swap, const uint8_t *addr) { + return read32(swap, *reinterpret_cast(addr)); +} + +int64_t ArchHandler::readS64(bool swap, const uint8_t *addr) { + return read64(swap, *reinterpret_cast(addr)); +} + +} // namespace mach_o +} // namespace lld + + + diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h new file mode 100644 index 0000000..8a097a0 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ArchHandler.h @@ -0,0 +1,175 @@ +//===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MachONormalizedFile.h" + +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "lld/Core/Simple.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" + +#include "llvm/ADT/Triple.h" + +#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H +#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H + +namespace lld { +namespace mach_o { + +/// +/// The ArchHandler class handles all architecture specific aspects of +/// mach-o linking. +/// +class ArchHandler { +public: + virtual ~ArchHandler(); + + /// There is no public interface to subclasses of ArchHandler, so this + /// is the only way to instantiate an ArchHandler. + static std::unique_ptr create(MachOLinkingContext::Arch arch); + + /// Get (arch specific) kind strings used by Registry. + virtual const Registry::KindStrings *kindStrings() = 0; + + /// Convert mach-o Arch to Reference::KindArch. + virtual Reference::KindArch kindArch() = 0; + + /// Used by StubPass to update References to shared library functions + /// to be references to a stub. + virtual bool isCallSite(const Reference &) = 0; + + /// Used by GOTPass to locate GOT References + virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) { + return false; + } + + /// Used by GOTPass to update GOT References + virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {} + + /// Used by normalizedFromAtoms() to know where to generated rebasing and + /// binding info in final executables. + virtual bool isPointer(const Reference &) = 0; + + /// Used by normalizedFromAtoms() to know where to generated lazy binding + /// info in final executables. + virtual bool isLazyPointer(const Reference &); + + /// Returns true if the specified relocation is paired to the next relocation. + virtual bool isPairedReloc(const normalized::Relocation &) = 0; + + /// Prototype for a helper function. Given a sectionIndex and address, + /// finds the atom and offset with that atom of that address. + typedef std::function + FindAtomBySectionAndAddress; + + /// Prototype for a helper function. Given a symbolIndex, finds the atom + /// representing that symbol. + typedef std::function FindAtomBySymbolIndex; + + /// Analyzes a relocation from a .o file and returns the info + /// (kind, target, addend) needed to instantiate a Reference. + /// Two helper functions are passed as parameters to find the target atom + /// given a symbol index or address. + virtual std::error_code + 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) = 0; + + /// Analyzes a pair of relocations from a .o file and returns the info + /// (kind, target, addend) needed to instantiate a Reference. + /// Two helper functions are passed as parameters to find the target atom + /// given a symbol index or address. + virtual std::error_code + getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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) = 0; + + /// Fixup an atom when generating a final linked binary. + virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t addend, + uint8_t *location, uint64_t fixupAddress, + uint64_t targetAddress, uint64_t inAtomAddress) = 0; + + struct ReferenceInfo { + Reference::KindArch arch; + uint16_t kind; + uint32_t offset; + int32_t addend; + }; + + /// Table of architecture specific information for creating stubs. + struct StubInfo { + const char* binderSymbolName; + ReferenceInfo lazyPointerReferenceToHelper; + ReferenceInfo lazyPointerReferenceToFinal; + ReferenceInfo nonLazyPointerReferenceToBinder; + uint8_t codeAlignment; + + uint32_t stubSize; + uint8_t stubBytes[16]; + ReferenceInfo stubReferenceToLP; + + uint32_t stubHelperSize; + uint8_t stubHelperBytes[16]; + ReferenceInfo stubHelperReferenceToImm; + ReferenceInfo stubHelperReferenceToHelperCommon; + + uint32_t stubHelperCommonSize; + uint8_t stubHelperCommonBytes[36]; + ReferenceInfo stubHelperCommonReferenceToCache; + ReferenceInfo stubHelperCommonReferenceToBinder; + }; + + virtual const StubInfo &stubInfo() = 0; + +protected: + ArchHandler(); + + static std::unique_ptr create_x86_64(); + static std::unique_ptr create_x86(); + static std::unique_ptr create_arm(); + + // Handy way to pack mach-o r_type and other bit fields into one 16-bit value. + typedef uint16_t RelocPattern; + enum { + rScattered = 0x8000, + rPcRel = 0x4000, + rExtern = 0x2000, + rLength1 = 0x0000, + rLength2 = 0x0100, + rLength4 = 0x0200, + rLength8 = 0x0300 + }; + static RelocPattern relocPattern(const normalized::Relocation &reloc); + + static int16_t readS16(bool swap, const uint8_t *addr); + static int32_t readS32(bool swap, const uint8_t *addr); + static uint32_t readU32(bool swap, const uint8_t *addr); + static int64_t readS64(bool swap, const uint8_t *addr); +}; + +} // namespace mach_o +} // namespace lld + +#endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp new file mode 100644 index 0000000..a1e6b83 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -0,0 +1,662 @@ +//===- 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/ErrorHandling.h" + +using namespace llvm::MachO; +using namespace lld::mach_o::normalized; + +namespace lld { +namespace mach_o { + +class ArchHandler_arm : public ArchHandler { +public: + ArchHandler_arm(); + virtual ~ArchHandler_arm(); + + 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; + std::error_code 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; + std::error_code + getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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; + + void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t addend, + uint8_t *location, uint64_t fixupAddress, + uint64_t targetAddress, uint64_t inAtomAddress) + override; + +private: + static const Registry::KindStrings _sKindStrings[]; + static const StubInfo _sStubInfoArmPIC; + + enum : Reference::KindValue { + invalid, /// for error condition + + // Kinds found in mach-o .o files: + thumb_b22, /// ex: bl _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_b24, /// ex: bl _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. + }; + + int32_t getDisplacementFromThumbBranch(uint32_t instruction); + int32_t getDisplacementFromArmBranch(uint32_t instruction); + uint16_t getWordFromThumbMov(uint32_t instruction); + uint16_t getWordFromArmMov(uint32_t instruction); + uint32_t clearThumbBit(uint32_t value, const Atom *target); + uint32_t setDisplacementInArmBranch(uint32_t instruction, int32_t disp); + + + const bool _swap; +}; + +//===----------------------------------------------------------------------===// +// ArchHandler_arm +//===----------------------------------------------------------------------===// + +ArchHandler_arm::ArchHandler_arm() : + _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_armv7)) {} + +ArchHandler_arm::~ArchHandler_arm() { } + +const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = { + 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_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 }, + + // 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-Common size and code + 36, + { // 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, 0 }, + { Reference::KindArch::ARM, delta32, 32, 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) { + return (ref.kindValue() == thumb_b22) || (ref.kindValue() == arm_b24); +} + +bool ArchHandler_arm::isPointer(const Reference &ref) { + return (ref.kindValue() == pointer32); +} + +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; + } +} + +int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) { + 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; + if (s) + return (sdis | 0xFE000000); + else + return sdis; +} + +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; +} + +uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction, + int32_t displacement) { + // FIXME: handle BLX and out-of-range. + uint32_t newInstruction = (instruction & 0xFF000000); + newInstruction |= ((displacement >> 2) & 0x00FFFFFF); + return newInstruction; +} + +uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t 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) { + uint32_t imm4 = ((instruction & 0x000F0000) >> 16); + uint32_t imm12 = (instruction & 0x00000FFF); + return (imm4 << 12) | 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(target)) { + const MachODefinedAtom *machoTarget = + reinterpret_cast(target); + if (machoTarget->isThumb()) + value &= -2; // mask off thumb-bit + } + } + return value; +} + +std::error_code ArchHandler_arm::getReferenceInfo( + const 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) { + typedef std::error_code E; + const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; + uint64_t targetAddress; + uint32_t instruction = readU32(swap, fixupContent); + int32_t displacement; + switch (relocPattern(reloc)) { + case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4: + // ex: bl _foo (and _foo is undefined) + *kind = thumb_b22; + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + // Instruction contains branch to addend. + displacement = getDisplacementFromThumbBranch(instruction); + *addend = fixupAddress + 4 + displacement; + return std::error_code(); + case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4: + // ex: bl _foo (and _foo is defined) + *kind = thumb_b22; + displacement = getDisplacementFromThumbBranch(instruction); + 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) + *kind = thumb_b22; + displacement = getDisplacementFromThumbBranch(instruction); + targetAddress = fixupAddress + 4 + displacement; + if (E 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 std::error_code(); + case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4: + // ex: bl _foo (and _foo is undefined) + *kind = arm_b24; + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + // Instruction contains branch to addend. + displacement = getDisplacementFromArmBranch(instruction); + *addend = fixupAddress + 8 + displacement; + return std::error_code(); + case ARM_RELOC_BR24 | rPcRel | rLength4: + // ex: bl _foo (and _foo is defined) + *kind = arm_b24; + 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) + *kind = arm_b24; + displacement = getDisplacementFromArmBranch(instruction); + targetAddress = fixupAddress + 8 + displacement; + if (E 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 std::error_code(); + case ARM_RELOC_VANILLA | rExtern | rLength4: + // ex: .long _foo (and _foo is undefined) + *kind = pointer32; + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = instruction; + return std::error_code(); + case ARM_RELOC_VANILLA | rLength4: + // ex: .long _foo (and _foo is defined) + *kind = pointer32; + if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend)) + return ec; + *addend = clearThumbBit((uint32_t) * addend, *target); + return std::error_code(); + case ARM_RELOC_VANILLA | rScattered | rLength4: + // ex: .long _foo+a (and _foo is defined) + *kind = pointer32; + if (E ec = atomFromAddress(0, reloc.value, target, addend)) + return ec; + *addend += (clearThumbBit(instruction, *target) - reloc.value); + return std::error_code(); + default: + return make_dynamic_error_code(Twine("unsupported arm relocation type")); + } + return std::error_code(); +} + +std::error_code +ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + const DefinedAtom *inAtom, + uint32_t offsetInAtom, + uint64_t fixupAddress, bool swap, + 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 | rLength4) << 16 | + ARM_RELOC_PAIR | rScattered | rLength4): + // 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 | rLength8) << 16 | + ARM_RELOC_PAIR | rScattered | rLength8): + // 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 | rLength1) << 16 | + ARM_RELOC_PAIR | rScattered | rLength1): + // 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 | rLength2) << 16 | + ARM_RELOC_PAIR | rScattered | rLength2): + // ex: movt r1, :upper16:(_x-L1) [arm mode] + *kind = arm_movt_funcRel; + funcRel = true; + top = true; + thumbReloc = false; + break; + case ((ARM_RELOC_HALF | rLength4) << 16 | + ARM_RELOC_PAIR | rLength4): + // ex: movw r1, :lower16:_x [thumb mode] + *kind = thumb_movw; + funcRel = false; + top = false; + thumbReloc = true; + break; + case ((ARM_RELOC_HALF | rLength8) << 16 | + ARM_RELOC_PAIR | rLength8): + // ex: movt r1, :upper16:_x [thumb mode] + *kind = thumb_movt; + funcRel = false; + top = true; + thumbReloc = true; + break; + case ((ARM_RELOC_HALF | rLength1) << 16 | + ARM_RELOC_PAIR | rLength1): + // ex: movw r1, :lower16:_x [arm mode] + *kind = arm_movw; + funcRel = false; + top = false; + thumbReloc = false; + break; + case ((ARM_RELOC_HALF | rLength2) << 16 | + ARM_RELOC_PAIR | rLength2): + // ex: movt r1, :upper16:_x [arm mode] + *kind = arm_movt; + funcRel = false; + top = true; + thumbReloc = false; + break; + case ((ARM_RELOC_HALF | rScattered | rLength4) << 16 | + ARM_RELOC_PAIR | rLength4): + // ex: movw r1, :lower16:_x+a [thumb mode] + *kind = thumb_movw; + funcRel = false; + top = false; + thumbReloc = true; + break; + case ((ARM_RELOC_HALF | rScattered | rLength8) << 16 | + ARM_RELOC_PAIR | rLength8): + // ex: movt r1, :upper16:_x+a [thumb mode] + *kind = thumb_movt; + funcRel = false; + top = true; + thumbReloc = true; + break; + case ((ARM_RELOC_HALF | rScattered | rLength1) << 16 | + ARM_RELOC_PAIR | rLength1): + // ex: movw r1, :lower16:_x+a [arm mode] + *kind = arm_movw; + funcRel = false; + top = false; + thumbReloc = false; + break; + case ((ARM_RELOC_HALF | rScattered | rLength2) << 16 | + ARM_RELOC_PAIR | rLength2): + // ex: movt r1, :upper16:_x+a [arm mode] + *kind = arm_movt; + funcRel = false; + top = true; + thumbReloc = false; + break; + case ((ARM_RELOC_HALF | rExtern | rLength4) << 16 | + ARM_RELOC_PAIR | rLength4): + // ex: movw r1, :lower16:_undef [thumb mode] + *kind = thumb_movw; + funcRel = false; + top = false; + thumbReloc = true; + break; + case ((ARM_RELOC_HALF | rExtern | rLength8) << 16 | + ARM_RELOC_PAIR | rLength8): + // ex: movt r1, :upper16:_undef [thumb mode] + *kind = thumb_movt; + funcRel = false; + top = true; + thumbReloc = true; + break; + case ((ARM_RELOC_HALF | rExtern | rLength1) << 16 | + ARM_RELOC_PAIR | rLength1): + // ex: movw r1, :lower16:_undef [arm mode] + *kind = arm_movw; + funcRel = false; + top = false; + thumbReloc = false; + break; + case ((ARM_RELOC_HALF | rExtern | rLength2) << 16 | + ARM_RELOC_PAIR | rLength2): + // 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 make_dynamic_error_code(Twine("unsupported arm relocation pair")); + } + const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; + std::error_code ec; + uint32_t instruction = readU32(swap, 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; + ec = atomFromAddr(0, toAddress, target, &offsetInTo); + if (ec) + return ec; + ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); + if (ec) + return ec; + if (fromTarget != inAtom) + return make_dynamic_error_code(Twine("SECTDIFF relocation where " + "subtrahend label is not in atom")); + *kind = delta32; + value = clearThumbBit(instruction, *target); + *addend = value - (toAddress - fromAddress); + } else if (funcRel) { + toAddress = reloc1.value; + fromAddress = reloc2.value; + ec = atomFromAddr(0, toAddress, target, &offsetInTo); + if (ec) + return ec; + ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); + if (ec) + return ec; + if (fromTarget != inAtom) + return make_dynamic_error_code( + Twine("ARM_RELOC_HALF_SECTDIFF relocation " + "where subtrahend label is not in atom")); + other16 = (reloc2.offset & 0xFFFF); + if (thumbReloc) + instruction16 = getWordFromThumbMov(instruction); + else + 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 std::error_code(); + } else { + uint32_t sectIndex; + if (thumbReloc) + instruction16 = getWordFromThumbMov(instruction); + else + instruction16 = getWordFromArmMov(instruction); + other16 = (reloc2.offset & 0xFFFF); + if (top) + value = (instruction16 << 16) | other16; + else + value = (other16 << 16) | instruction16; + if (reloc1.isExtern) { + ec = atomFromSymbolIndex(reloc1.symbol, target); + if (ec) + return ec; + *addend = value; + } else { + if (reloc1.scattered) { + toAddress = reloc1.value; + sectIndex = 0; + } else { + toAddress = value; + sectIndex = reloc1.symbol; + } + ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo); + if (ec) + return ec; + *addend = value - toAddress; + } + } + + return std::error_code(); +} + +void ArchHandler_arm::applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress, + uint64_t inAtomAddress) { + if (ns != Reference::KindNamespace::mach_o) + return; + assert(arch == Reference::KindArch::ARM); + int32_t *loc32 = reinterpret_cast(location); + int32_t displacement; + // FIXME: these writes may need a swap. + switch (kindValue) { + case thumb_b22: + // FIXME + break; + case thumb_movw: + // FIXME + break; + case thumb_movt: + // FIXME + break; + case thumb_movw_funcRel: + // FIXME + break; + case thumb_movt_funcRel: + // FIXME + break; + case arm_b24: + displacement = (targetAddress - (fixupAddress + 8)) + addend; + *loc32 = setDisplacementInArmBranch(*loc32, displacement); + break; + case arm_movw: + // FIXME + break; + case arm_movt: + // FIXME + break; + case arm_movw_funcRel: + // FIXME + break; + case arm_movt_funcRel: + // FIXME + break; + case pointer32: + // FIXME + break; + case delta32: + // FIXME + break; + case lazyPointer: + case lazyImmediateLocation: + // do nothing + break; + case invalid: + llvm_unreachable("invalid ARM Reference Kind"); + break; + } +} + +std::unique_ptr ArchHandler::create_arm() { + return std::unique_ptr(new ArchHandler_arm()); +} + +} // namespace mach_o +} // namespace lld diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp new file mode 100644 index 0000000..db7d036 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp @@ -0,0 +1,331 @@ +//===- lib/FileFormat/MachO/ArchHandler_x86.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/ErrorHandling.h" + +using namespace llvm::MachO; +using namespace lld::mach_o::normalized; + +namespace lld { +namespace mach_o { + +class ArchHandler_x86 : public ArchHandler { +public: + ArchHandler_x86(); + virtual ~ArchHandler_x86(); + + const Registry::KindStrings *kindStrings() override { return _sKindStrings; } + + Reference::KindArch kindArch() override { return Reference::KindArch::x86; } + + const StubInfo &stubInfo() override { return _sStubInfo; } + bool isCallSite(const Reference &) override; + bool isPointer(const Reference &) override; + bool isPairedReloc(const normalized::Relocation &) override; + std::error_code 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; + std::error_code + getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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; + + void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t addend, + uint8_t *location, uint64_t fixupAddress, + uint64_t targetAddress, uint64_t inAtomAddress) + override; + +private: + static const Registry::KindStrings _sKindStrings[]; + static const StubInfo _sStubInfo; + + enum : Reference::KindValue { + invalid, /// for error condition + + // Kinds found in mach-o .o files: + branch32, /// ex: call _foo + branch16, /// ex: callw _foo + abs32, /// ex: movl _foo, %eax + funcRel32, /// ex: movl _foo-L1(%eax), %eax + 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. + }; + + const bool _swap; +}; + +//===----------------------------------------------------------------------===// +// ArchHandler_x86 +//===----------------------------------------------------------------------===// + +ArchHandler_x86::ArchHandler_x86() : + _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86)) {} + +ArchHandler_x86::~ArchHandler_x86() { } + +const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = { + LLD_KIND_STRING_ENTRY(invalid), + LLD_KIND_STRING_ENTRY(branch32), + LLD_KIND_STRING_ENTRY(branch16), + LLD_KIND_STRING_ENTRY(abs32), + LLD_KIND_STRING_ENTRY(funcRel32), + 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_x86::_sStubInfo = { + "dyld_stub_binder", + + // Lazy pointer references + { Reference::KindArch::x86, pointer32, 0, 0 }, + { Reference::KindArch::x86, lazyPointer, 0, 0 }, + + // GOT pointer to dyld_stub_binder + { Reference::KindArch::x86, pointer32, 0, 0 }, + + // x86 code alignment + 1, + + // Stub size and code + 6, + { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer + { Reference::KindArch::x86, abs32, 2, 0 }, + + // Stub Helper size and code + 10, + { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset + 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper + { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 }, + { Reference::KindArch::x86, branch32, 6, 0 }, + + // Stub Helper-Common size and code + 12, + { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache + 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind + 0x90 }, // nop + { Reference::KindArch::x86, abs32, 1, 0 }, + { Reference::KindArch::x86, abs32, 7, 0 } +}; + +bool ArchHandler_x86::isCallSite(const Reference &ref) { + return (ref.kindValue() == branch32); +} + +bool ArchHandler_x86::isPointer(const Reference &ref) { + return (ref.kindValue() == pointer32); +} + +bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) { + if (!reloc.scattered) + return false; + return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) || + (reloc.type == GENERIC_RELOC_SECTDIFF); +} + +std::error_code +ArchHandler_x86::getReferenceInfo(const 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) { + typedef std::error_code E; + DefinedAtom::ContentPermissions perms; + const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; + uint64_t targetAddress; + switch (relocPattern(reloc)) { + case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4: + // ex: call _foo (and _foo undefined) + *kind = branch32; + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = fixupAddress + 4 + readS32(swap, fixupContent); + break; + case GENERIC_RELOC_VANILLA | rPcRel | rLength4: + // ex: call _foo (and _foo defined) + *kind = branch32; + targetAddress = fixupAddress + 4 + readS32(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + break; + case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2: + // ex: callw _foo (and _foo undefined) + *kind = branch16; + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = fixupAddress + 2 + readS16(swap, fixupContent); + break; + case GENERIC_RELOC_VANILLA | rPcRel | rLength2: + // ex: callw _foo (and _foo defined) + *kind = branch16; + targetAddress = fixupAddress + 2 + readS16(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + break; + case GENERIC_RELOC_VANILLA | rExtern | rLength4: + // ex: movl _foo, %eax (and _foo undefined) + // ex: .long _foo (and _foo undefined) + perms = inAtom->permissions(); + *kind = + ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32 + : pointer32; + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readU32(swap, fixupContent); + break; + case GENERIC_RELOC_VANILLA | rLength4: + // ex: movl _foo, %eax (and _foo defined) + // ex: .long _foo (and _foo defined) + perms = inAtom->permissions(); + *kind = + ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32 + : pointer32; + targetAddress = readU32(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + break; + default: + return make_dynamic_error_code(Twine("unsupported i386 relocation type")); + } + return std::error_code(); +} + +std::error_code +ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + const DefinedAtom *inAtom, + uint32_t offsetInAtom, + uint64_t fixupAddress, bool swap, + FindAtomBySectionAndAddress atomFromAddr, + FindAtomBySymbolIndex atomFromSymbolIndex, + Reference::KindValue *kind, + const lld::Atom **target, + Reference::Addend *addend) { + const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; + std::error_code ec; + DefinedAtom::ContentPermissions perms = inAtom->permissions(); + uint32_t fromAddress; + uint32_t toAddress; + uint32_t value; + const lld::Atom *fromTarget; + Reference::Addend offsetInTo; + Reference::Addend offsetInFrom; + switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) { + case((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 | + GENERIC_RELOC_PAIR | rScattered | rLength4) + : + case((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 | + GENERIC_RELOC_PAIR | rScattered | rLength4) + : + toAddress = reloc1.value; + fromAddress = reloc2.value; + value = readS32(swap, fixupContent); + ec = atomFromAddr(0, toAddress, target, &offsetInTo); + if (ec) + return ec; + ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); + if (ec) + return ec; + if (fromTarget != inAtom) + return make_dynamic_error_code(Twine("SECTDIFF relocation where " + "subtrahend label is not in atom")); + *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? funcRel32 + : delta32; + if (*kind == funcRel32) { + // SECTDIFF relocations are used in i386 codegen where the function + // prolog does a CALL to the next instruction which POPs the return + // address into EBX which becomes the pic-base register. The POP + // instruction is label the used for the subtrahend in expressions. + // The funcRel32 kind represents the 32-bit delta to some symbol from + // the start of the function (atom) containing the funcRel32. + uint32_t ta = fromAddress + value - toAddress; + *addend = ta - offsetInFrom; + } else { + *addend = fromAddress + value - toAddress; + } + return std::error_code(); + break; + default: + return make_dynamic_error_code(Twine("unsupported i386 relocation type")); + } +} + +void ArchHandler_x86::applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, uint64_t targetAddress, + uint64_t inAtomAddress) { + if (ns != Reference::KindNamespace::mach_o) + return; + assert(arch == Reference::KindArch::x86); + int32_t *loc32 = reinterpret_cast(location); + int16_t *loc16 = reinterpret_cast(location); + switch (kindValue) { + case branch32: + write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend); + break; + case branch16: + write16(*loc16, _swap, (targetAddress - (fixupAddress + 4)) + addend); + break; + case pointer32: + case abs32: + write32(*loc32, _swap, targetAddress + addend); + break; + case funcRel32: + write32(*loc32, _swap, targetAddress - inAtomAddress + addend); // FIXME + break; + case delta32: + write32(*loc32, _swap, targetAddress - fixupAddress + addend); + break; + case lazyPointer: + case lazyImmediateLocation: + // do nothing + break; + default: + llvm_unreachable("invalid x86 Reference Kind"); + break; + } +} + +std::unique_ptr ArchHandler::create_x86() { + return std::unique_ptr(new ArchHandler_x86()); +} + +} // namespace mach_o +} // namespace lld diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp new file mode 100644 index 0000000..5f1cddb --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -0,0 +1,421 @@ +//===- lib/FileFormat/MachO/ArchHandler_x86_64.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/ErrorHandling.h" + +using namespace llvm::MachO; +using namespace lld::mach_o::normalized; + +namespace lld { +namespace mach_o { + +class ArchHandler_x86_64 : public ArchHandler { +public: + ArchHandler_x86_64(); + virtual ~ArchHandler_x86_64(); + + const Registry::KindStrings *kindStrings() override { return _sKindStrings; } + + Reference::KindArch kindArch() override { + return Reference::KindArch::x86_64; + } + + /// Used by GOTPass to locate GOT References + bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + switch (ref.kindValue()) { + case ripRel32GotLoad: + canBypassGOT = true; + return true; + case ripRel32Got: + canBypassGOT = false; + return true; + default: + return false; + } + } + + /// Used by GOTPass to update GOT References + void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override { + assert(ref->kindNamespace() == Reference::KindNamespace::mach_o); + assert(ref->kindArch() == Reference::KindArch::x86_64); + const_cast(ref) + ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea); + } + + const StubInfo &stubInfo() override { return _sStubInfo; } + + bool isCallSite(const Reference &) override; + bool isPointer(const Reference &) override; + bool isPairedReloc(const normalized::Relocation &) override; + std::error_code 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; + std::error_code + getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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; + + virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, + Reference::KindValue kindValue, uint64_t addend, + uint8_t *location, uint64_t fixupAddress, + uint64_t targetAddress, uint64_t inAtomAddress) + override; + +private: + static const Registry::KindStrings _sKindStrings[]; + static const StubInfo _sStubInfo; + + enum : Reference::KindValue { + invalid, /// for error condition + + // Kinds found in mach-o .o files: + branch32, /// ex: call _foo + ripRel32, /// ex: movq _foo(%rip), %rax + ripRel32Minus1, /// ex: movb $0x12, _foo(%rip) + ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip) + ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip) + ripRel32Anon, /// ex: movq L1(%rip), %rax + ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax + ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip) + pointer64, /// ex: .quad _foo + pointer64Anon, /// ex: .quad L1 + delta64, /// ex: .quad _foo - . + delta32, /// ex: .long _foo - . + delta64Anon, /// ex: .quad L1 - . + delta32Anon, /// ex: .long L1 - . + + // Kinds introduced by Passes: + ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so + /// "movq _foo@GOTPCREL(%rip), %rax" can be changed + /// to "leaq _foo(%rip), %rax + lazyPointer, /// Location contains a lazy pointer. + lazyImmediateLocation, /// Location contains immediate value used in stub. + }; + + Reference::KindValue kindFromReloc(const normalized::Relocation &reloc); + Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2); + + const bool _swap; +}; + + +ArchHandler_x86_64::ArchHandler_x86_64() : + _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86_64)) {} + +ArchHandler_x86_64::~ArchHandler_x86_64() { } + +const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = { + LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32), + LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1), + LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4), + LLD_KIND_STRING_ENTRY(ripRel32Anon), LLD_KIND_STRING_ENTRY(ripRel32GotLoad), + LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea), + LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(lazyPointer), + LLD_KIND_STRING_ENTRY(lazyImmediateLocation), + LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon), + LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64), + LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon), + LLD_KIND_STRING_END +}; + +const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = { + "dyld_stub_binder", + + // Lazy pointer references + { Reference::KindArch::x86_64, pointer64, 0, 0 }, + { Reference::KindArch::x86_64, lazyPointer, 0, 0 }, + + // GOT pointer to dyld_stub_binder + { Reference::KindArch::x86_64, pointer64, 0, 0 }, + + // x86_64 code alignment 2^1 + 1, + + // Stub size and code + 6, + { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer + { Reference::KindArch::x86_64, ripRel32, 2, 0 }, + + // Stub Helper size and code + 10, + { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset + 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper + { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 }, + { Reference::KindArch::x86_64, branch32, 6, 0 }, + + // Stub Helper-Common size and code + 16, + { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11 + 0x41, 0x53, // push %r11 + 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip) + 0x90 }, // nop + { Reference::KindArch::x86_64, ripRel32, 3, 0 }, + { Reference::KindArch::x86_64, ripRel32, 11, 0 } + +}; + +bool ArchHandler_x86_64::isCallSite(const Reference &ref) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + return (ref.kindValue() == branch32); +} + +bool ArchHandler_x86_64::isPointer(const Reference &ref) { + if (ref.kindNamespace() != Reference::KindNamespace::mach_o) + return false; + assert(ref.kindArch() == Reference::KindArch::x86_64); + Reference::KindValue kind = ref.kindValue(); + return (kind == pointer64 || kind == pointer64Anon); +} + +bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) { + return (reloc.type == X86_64_RELOC_SUBTRACTOR); +} + +Reference::KindValue +ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) { + switch(relocPattern(reloc)) { + case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4: + return branch32; + case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4: + return ripRel32; + case X86_64_RELOC_SIGNED | rPcRel | rLength4: + return ripRel32Anon; + case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4: + return ripRel32Minus1; + case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4: + return ripRel32Minus2; + case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4: + return ripRel32Minus4; + case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4: + return ripRel32GotLoad; + case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4: + return ripRel32Got; + case X86_64_RELOC_UNSIGNED | rExtern | rLength8: + return pointer64; + case X86_64_RELOC_UNSIGNED | rLength8: + return pointer64Anon; + default: + return invalid; + } +} + +std::error_code +ArchHandler_x86_64::getReferenceInfo(const 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) { + typedef std::error_code E; + *kind = kindFromReloc(reloc); + if (*kind == invalid) + return make_dynamic_error_code(Twine("unknown type")); + const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; + uint64_t targetAddress; + switch (*kind) { + case branch32: + case ripRel32: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent); + return std::error_code(); + case ripRel32Minus1: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + 1; + return std::error_code(); + case ripRel32Minus2: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + 2; + return std::error_code(); + case ripRel32Minus4: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + 4; + return std::error_code(); + case ripRel32Anon: + targetAddress = fixupAddress + 4 + readS32(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + case ripRel32GotLoad: + case ripRel32Got: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = 0; + return std::error_code(); + case pointer64: + if (E ec = atomFromSymbolIndex(reloc.symbol, target)) + return ec; + *addend = readS64(swap, fixupContent); + return std::error_code(); + case pointer64Anon: + targetAddress = readS64(swap, fixupContent); + return atomFromAddress(reloc.symbol, targetAddress, target, addend); + default: + llvm_unreachable("bad reloc kind"); + } +} + +Reference::KindValue +ArchHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2) { + switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | + X86_64_RELOC_UNSIGNED | rExtern | rLength8): + return delta64; + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | + X86_64_RELOC_UNSIGNED | rExtern | rLength4): + return delta32; + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | + X86_64_RELOC_UNSIGNED | rLength8): + return delta64Anon; + case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | + X86_64_RELOC_UNSIGNED | rLength4): + return delta32Anon; + default: + llvm_unreachable("bad reloc pairs"); + } +} + +std::error_code +ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, + const normalized::Relocation &reloc2, + 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) { + *kind = kindFromRelocPair(reloc1, reloc2); + if (*kind == invalid) + return make_dynamic_error_code(Twine("unknown pair")); + const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; + typedef std::error_code E; + uint64_t targetAddress; + const lld::Atom *fromTarget; + if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget)) + return ec; + if (fromTarget != inAtom) + return make_dynamic_error_code(Twine("pointer diff not in base atom")); + switch (*kind) { + case delta64: + if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) + return ec; + *addend = readS64(swap, fixupContent) + offsetInAtom; + return std::error_code(); + case delta32: + if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) + return ec; + *addend = readS32(swap, fixupContent) + offsetInAtom; + return std::error_code(); + case delta64Anon: + targetAddress = offsetInAtom + readS64(swap, fixupContent); + return atomFromAddress(reloc2.symbol, targetAddress, target, addend); + case delta32Anon: + targetAddress = offsetInAtom + readS32(swap, fixupContent); + return atomFromAddress(reloc2.symbol, targetAddress, target, addend); + default: + llvm_unreachable("bad reloc pair kind"); + } +} + +void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue kindValue, + uint64_t addend, uint8_t *location, + uint64_t fixupAddress, + uint64_t targetAddress, + uint64_t inAtomAddress) { + if (ns != Reference::KindNamespace::mach_o) + return; + assert(arch == Reference::KindArch::x86_64); + int32_t *loc32 = reinterpret_cast(location); + uint64_t *loc64 = reinterpret_cast(location); + switch (kindValue) { + case branch32: + case ripRel32: + case ripRel32Got: + case ripRel32GotLoad: + write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend); + break; + case pointer64: + case pointer64Anon: + write64(*loc64, _swap, targetAddress + addend); + break; + case ripRel32Minus1: + write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + addend); + break; + case ripRel32Minus2: + write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + addend); + break; + case ripRel32Minus4: + write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + addend); + break; + case delta32: + case delta32Anon: + write32(*loc32, _swap, (targetAddress - fixupAddress) + addend); + break; + case delta64: + case delta64Anon: + write64(*loc64, _swap, (targetAddress - fixupAddress) + addend); + break; + case ripRel32GotLoadNowLea: + // Change MOVQ to LEA + assert(location[-2] == 0x8B); + location[-2] = 0x8D; + write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend); + break; + case lazyPointer: + case lazyImmediateLocation: + // do nothing + break; + default: + llvm_unreachable("invalid x86_64 Reference Kind"); + break; + } +} + +std::unique_ptr ArchHandler::create_x86_64() { + return std::unique_ptr(new ArchHandler_x86_64()); +} + +} // namespace mach_o +} // namespace lld diff --git a/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/lld/lib/ReaderWriter/MachO/CMakeLists.txt index 51a1f20..d0076c9 100644 --- a/lld/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lld/lib/ReaderWriter/MachO/CMakeLists.txt @@ -1,4 +1,8 @@ add_lld_library(lldMachO + ArchHandler.cpp + ArchHandler_arm.cpp + ArchHandler_x86.cpp + ArchHandler_x86_64.cpp GOTPass.cpp MachOLinkingContext.cpp MachONormalizedFileBinaryReader.cpp @@ -6,7 +10,6 @@ add_lld_library(lldMachO MachONormalizedFileFromAtoms.cpp MachONormalizedFileToAtoms.cpp MachONormalizedFileYAML.cpp - ReferenceKinds.cpp StubsPass.cpp WriterMachO.cpp ) diff --git a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp index 94d4fad..e12b881 100644 --- a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp +++ b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp @@ -31,15 +31,22 @@ namespace mach_o { class CRuntimeFile : public SimpleFile { public: CRuntimeFile(const MachOLinkingContext &context) - : SimpleFile("C runtime"), _undefMain(*this, context.entrySymbolName()) { + : SimpleFile("C runtime"), + _undefMain(*this, context.entrySymbolName()), + _undefBinder(*this, context.binderSymbolName()) { // only main executables need _main if (context.outputMachOType() == llvm::MachO::MH_EXECUTE) { this->addAtom(_undefMain); } + // only dynamic binaries use stubs + if (context.needsStubsPass()) { + this->addAtom(_undefBinder); + } } private: SimpleUndefinedAtom _undefMain; + SimpleUndefinedAtom _undefBinder; }; } // namespace mach_o diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index 0cafc4c..dffc149 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -10,13 +10,14 @@ #ifndef LLD_READER_WRITER_MACHO_FILE_H #define LLD_READER_WRITER_MACHO_FILE_H -#include "llvm/ADT/StringMap.h" - #include "Atoms.h" +#include "MachONormalizedFile.h" #include "lld/Core/Simple.h" #include "lld/Core/SharedLibraryFile.h" +#include "llvm/ADT/StringMap.h" + #include namespace lld { @@ -138,6 +139,8 @@ public: return pos->second; } + llvm::BumpPtrAllocator &allocator() { return _allocator; } + private: struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; }; diff --git a/lld/lib/ReaderWriter/MachO/GOTPass.cpp b/lld/lib/ReaderWriter/MachO/GOTPass.cpp index 1d5c6ee..d4cbaf0 100644 --- a/lld/lib/ReaderWriter/MachO/GOTPass.cpp +++ b/lld/lib/ReaderWriter/MachO/GOTPass.cpp @@ -32,77 +32,143 @@ /// //===----------------------------------------------------------------------===// +#include "ArchHandler.h" +#include "File.h" +#include "MachOPasses.h" + #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" +#include "lld/Core/Simple.h" + #include "llvm/ADT/DenseMap.h" -#include "MachOPasses.h" namespace lld { +namespace mach_o { + + +// +// GOT Entry Atom created by the GOT pass. +// +class GOTEntryAtom : public SimpleDefinedAtom { +public: + GOTEntryAtom(const File &file, bool is64) + : SimpleDefinedAtom(file), _is64(is64) { } -static bool shouldReplaceTargetWithGOTAtom(const Atom *target, - bool canBypassGOT) { - // Accesses to shared library symbols must go through GOT. - if (target->definition() == Atom::definitionSharedLibrary) - return true; - // Accesses to interposable symbols in same linkage unit must also go - // through GOT. - const DefinedAtom *defTarget = dyn_cast(target); - if (defTarget != nullptr && - defTarget->interposable() != DefinedAtom::interposeNo) { - assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); - return true; + ContentType contentType() const override { + return DefinedAtom::typeGOT; } - // Target does not require indirection. So, if instruction allows GOT to be - // by-passed, do that optimization and don't create GOT entry. - return !canBypassGOT; -} -static const DefinedAtom * -findGOTAtom(const Atom *target, - llvm::DenseMap &targetToGOT) { - auto pos = targetToGOT.find(target); - return (pos == targetToGOT.end()) ? nullptr : pos->second; -} + Alignment alignment() const override { + return Alignment(_is64 ? 3 : 2); + } -void GOTPass::perform(std::unique_ptr &mergedFile) { - // Use map so all pointers to same symbol use same GOT entry. - llvm::DenseMap targetToGOT; - - // Scan all references in all atoms. - for (const DefinedAtom *atom : mergedFile->defined()) { - for (const Reference *ref : *atom) { - // Look at instructions accessing the GOT. - bool canBypassGOT; - if (!isGOTAccess(*ref, canBypassGOT)) - continue; - const Atom *target = ref->target(); - assert(target != nullptr); - - if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) { - // Update reference kind to reflect that target is a direct accesss. - updateReferenceToGOT(ref, false); - continue; - } - // Replace the target with a reference to a GOT entry. - const DefinedAtom *gotEntry = findGOTAtom(target, targetToGOT); - if (!gotEntry) { - gotEntry = makeGOTEntry(*target); - assert(gotEntry != nullptr); - assert(gotEntry->contentType() == DefinedAtom::typeGOT); - targetToGOT[target] = gotEntry; + uint64_t size() const override { + return _is64 ? 8 : 4; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permRW_; + } + + ArrayRef rawContent() const override { + static const uint8_t zeros[] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + return llvm::makeArrayRef(zeros, size()); + } + +private: + const bool _is64; +}; + + +/// Pass for instantiating and optimizing GOT slots. +/// +class GOTPass : public Pass { +public: + GOTPass(const MachOLinkingContext &context) + : _context(context), _archHandler(_context.archHandler()), + _file("") { } + +private: + + void perform(std::unique_ptr &mergedFile) override { + // Scan all references in all atoms. + for (const DefinedAtom *atom : mergedFile->defined()) { + for (const Reference *ref : *atom) { + // Look at instructions accessing the GOT. + bool canBypassGOT; + if (!_archHandler.isGOTAccess(*ref, canBypassGOT)) + continue; + const Atom *target = ref->target(); + assert(target != nullptr); + + if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) { + // Update reference kind to reflect that target is a direct accesss. + _archHandler.updateReferenceToGOT(ref, false); + } else { + // Replace the target with a reference to a GOT entry. + const DefinedAtom *gotEntry = makeGOTEntry(target); + const_cast(ref)->setTarget(gotEntry); + // Update reference kind to reflect that target is now a GOT entry. + _archHandler.updateReferenceToGOT(ref, true); + } } - const_cast(ref)->setTarget(gotEntry); - // Update reference kind to reflect that target is now a GOT entry. - updateReferenceToGOT(ref, true); } + + // add all created GOT Atoms to master file + for (auto &it : _targetToGOT) + mergedFile->addAtom(*it.second); + } + + bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) { + // Accesses to shared library symbols must go through GOT. + if (target->definition() == Atom::definitionSharedLibrary) + return true; + // Accesses to interposable symbols in same linkage unit must also go + // through GOT. + const DefinedAtom *defTarget = dyn_cast(target); + if (defTarget != nullptr && + defTarget->interposable() != DefinedAtom::interposeNo) { + assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); + return true; + } + // Target does not require indirection. So, if instruction allows GOT to be + // by-passed, do that optimization and don't create GOT entry. + return !canBypassGOT; + } + + const DefinedAtom *makeGOTEntry(const Atom *target) { + auto pos = _targetToGOT.find(target); + if (pos == _targetToGOT.end()) { + GOTEntryAtom *gotEntry = new (_file.allocator()) + GOTEntryAtom(_file, _context.is64Bit()); + _targetToGOT[target] = gotEntry; + const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo(). + nonLazyPointerReferenceToBinder; + gotEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch, + nlInfo.kind, 0, target, 0); + return gotEntry; + } + return pos->second; } - // add all created GOT Atoms to master file - for (auto &it : targetToGOT) - mergedFile->addAtom(*it.second); + + const MachOLinkingContext &_context; + mach_o::ArchHandler &_archHandler; + MachOFile _file; + llvm::DenseMap _targetToGOT; +}; + + + +void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) { + assert(ctx.needsGOTPass()); + pm.add(std::unique_ptr(new GOTPass(ctx))); } + +} // end namesapce mach_o } // end namesapce lld diff --git a/lld/lib/ReaderWriter/MachO/GOTPass.hpp b/lld/lib/ReaderWriter/MachO/GOTPass.hpp index a7ab254..be3a789 100644 --- a/lld/lib/ReaderWriter/MachO/GOTPass.hpp +++ b/lld/lib/ReaderWriter/MachO/GOTPass.hpp @@ -24,27 +24,6 @@ namespace lld { namespace mach_o { -class GOTPass : public lld::GOTPass { -public: - bool noTextRelocs() override { - return true; - } - - bool isGOTAccess(const Reference &, bool &canBypassGOT) override { - return false; - } - - void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) override { - - } - - const DefinedAtom* makeGOTEntry(const Atom&) override { - return nullptr; - } - -}; - - } // namespace mach_o } // namespace lld diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 379d621..c05772b 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "lld/ReaderWriter/MachOLinkingContext.h" -#include "GOTPass.hpp" -#include "StubsPass.hpp" -#include "ReferenceKinds.h" + +#include "ArchHandler.h" +#include "MachOPasses.h" #include "lld/Core/PassManager.h" #include "lld/ReaderWriter/Reader.h" @@ -25,7 +25,7 @@ #include "llvm/Support/MachO.h" #include "llvm/Support/Path.h" -using lld::mach_o::KindHandler; +using lld::mach_o::ArchHandler; using namespace llvm::MachO; namespace lld { @@ -125,7 +125,7 @@ MachOLinkingContext::MachOLinkingContext() _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0), _pageZeroSize(0), _pageSize(4096), _compatibilityVersion(0), _currentVersion(0), _deadStrippableDylib(false), _printAtoms(false), - _testingLibResolution(false), _kindHandler(nullptr) {} + _testingLibResolution(false), _archHandler(nullptr) {} MachOLinkingContext::~MachOLinkingContext() {} @@ -223,6 +223,33 @@ bool MachOLinkingContext::outputTypeHasEntry() const { } } +bool MachOLinkingContext::needsStubsPass() const { + switch (_outputMachOType) { + case MH_EXECUTE: + return !_outputMachOTypeStatic; + case MH_DYLIB: + case MH_BUNDLE: + return true; + default: + return false; + } +} + +bool MachOLinkingContext::needsGOTPass() const { + // Only x86_64 uses GOT pass but not in -r mode. + if (_arch != arch_x86_64) + return false; + return (_outputMachOType != MH_OBJECT); +} + + +StringRef MachOLinkingContext::binderSymbolName() const { + return archHandler().stubInfo().binderSymbolName; +} + + + + bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const { uint32_t parsedVersion; switch (_os) { @@ -375,11 +402,11 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { } void MachOLinkingContext::addPasses(PassManager &pm) { - if (outputMachOType() != MH_OBJECT) { - pm.add(std::unique_ptr(new mach_o::GOTPass)); - pm.add(std::unique_ptr(new mach_o::StubsPass(*this))); - } pm.add(std::unique_ptr(new LayoutPass(registry()))); + if (needsStubsPass()) + mach_o::addStubsPass(pm, *this); + if (needsGOTPass()) + mach_o::addGOTPass(pm, *this); } Writer &MachOLinkingContext::writer() const { @@ -388,10 +415,10 @@ Writer &MachOLinkingContext::writer() const { return *_writer; } -KindHandler &MachOLinkingContext::kindHandler() const { - if (!_kindHandler) - _kindHandler = KindHandler::create(_arch); - return *_kindHandler; +ArchHandler &MachOLinkingContext::archHandler() const { + if (!_archHandler) + _archHandler = ArchHandler::create(_arch); + return *_archHandler; } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 7c59915..c96f325 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -22,8 +22,10 @@ /// +------------+ #include "MachONormalizedFile.h" + +#include "ArchHandler.h" #include "MachONormalizedFileBinaryUtils.h" -#include "ReferenceKinds.h" + #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/SmallString.h" @@ -442,27 +444,11 @@ private: } // namespace normalized } // namespace mach_o -void Registry::addSupportMachOObjects(StringRef archName) { - MachOLinkingContext::Arch arch = MachOLinkingContext::archFromName(archName); +void Registry::addSupportMachOObjects(const MachOLinkingContext &ctx) { + MachOLinkingContext::Arch arch = ctx.arch(); add(std::unique_ptr(new mach_o::normalized::MachOReader(arch))); - switch (arch) { - case MachOLinkingContext::arch_x86_64: - addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::x86_64, - mach_o::KindHandler_x86_64::kindStrings); - break; - case MachOLinkingContext::arch_x86: - addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::x86, - mach_o::KindHandler_x86::kindStrings); - break; - case MachOLinkingContext::arch_armv6: - case MachOLinkingContext::arch_armv7: - case MachOLinkingContext::arch_armv7s: - addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::ARM, - mach_o::KindHandler_arm::kindStrings); - break; - default: - llvm_unreachable("mach-o arch not supported"); - } + addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), + ctx.archHandler().kindStrings()); add(std::unique_ptr( new mach_o::MachOYamlIOTaggedDocumentHandler(arch))); } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h index 5a61314..fcc1879 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h @@ -194,7 +194,17 @@ inline uint64_t read64(bool swap, uint64_t value) { return (swap ? getSwappedBytes(value) : value); } +inline void write16(int16_t &loc, bool swap, int16_t value) { + loc = (swap ? getSwappedBytes(value) : value); +} + +inline void write32(int32_t &loc, bool swap, int32_t value) { + loc = (swap ? getSwappedBytes(value) : value); +} +inline void write64(uint64_t &loc, bool swap, uint64_t value) { + loc = (swap ? getSwappedBytes(value) : value); +} inline uint32_t bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit, diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 3befd6a..0a30680 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -21,8 +21,10 @@ /// +-------+ #include "MachONormalizedFile.h" + +#include "ArchHandler.h" #include "MachONormalizedFileBinaryUtils.h" -#include "ReferenceKinds.h" + #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/StringRef.h" @@ -542,7 +544,7 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) { // FIXME: Need a handler method to update content for .o file // output and any needed section relocations. } else { - _context.kindHandler().applyFixup( + _context.archHandler().applyFixup( ref->kindNamespace(), ref->kindArch(), ref->kindValue(), ref->addend(), &atomContent[offset], fixupAddress, targetAddress, atomAddress); @@ -713,7 +715,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) { const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) { for (const Reference *ref : *lpAtom) { - if (_context.kindHandler().isLazyTarget(*ref)) { + if (_context.archHandler().isLazyPointer(*ref)) { return ref->target(); } } @@ -871,7 +873,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile, uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom() - segmentStartAddr; const Atom* targ = ref->target(); - if (_context.kindHandler().isPointer(*ref)) { + if (_context.archHandler().isPointer(*ref)) { // A pointer to a DefinedAtom requires rebasing. if (dyn_cast(targ)) { RebaseLocation rebase; @@ -893,7 +895,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile, nFile.bindingInfo.push_back(bind); } } - if (_context.kindHandler().isLazyTarget(*ref)) { + if (_context.archHandler().isLazyPointer(*ref)) { BindLocation bind; bind.segIndex = segmentIndex; bind.segOffset = segmentOffset; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 7e8f6c3..cc0289e 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -21,10 +21,11 @@ /// +-------+ #include "MachONormalizedFile.h" -#include "MachONormalizedFileBinaryUtils.h" -#include "File.h" + +#include "ArchHandler.h" #include "Atoms.h" -#include "ReferenceKinds.h" +#include "File.h" +#include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" @@ -431,8 +432,8 @@ std::error_code processSection(DefinedAtom::ContentType atomType, std::error_code convertRelocs(const Section §ion, const NormalizedFile &normalizedFile, MachOFile &file, - KindHandler &handler) { - // Utility function for KindHandler to find atom by its address. + ArchHandler &handler) { + // Utility function for ArchHandler to find atom by its address. auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr, const lld::Atom **atom, Reference::Addend *addend) -> std::error_code { @@ -462,7 +463,7 @@ std::error_code convertRelocs(const Section §ion, return std::error_code(); }; - // Utility function for KindHandler to find atom by its symbol index. + // Utility function for ArchHandler to find atom by its symbol index. auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result) -> std::error_code { // Find symbol from index. @@ -536,7 +537,7 @@ std::error_code convertRelocs(const Section §ion, &target, &addend); } else { - // Use KindHandler to convert relocation record into information + // Use ArchHandler to convert relocation record into information // needed to instantiate an lld::Reference object. relocErr = handler.getReferenceInfo(reloc, inAtom, offsetInAtom, fixupAddress,swap, atomByAddr, @@ -558,27 +559,8 @@ std::error_code convertRelocs(const Section §ion, + ")" ); } else { // Instantiate an lld::Reference object and add to its atom. - Reference::KindArch arch = Reference::KindArch::all; - switch (normalizedFile.arch ) { - case lld::MachOLinkingContext::arch_x86_64: - arch = Reference::KindArch::x86_64; - break; - case lld::MachOLinkingContext::arch_x86: - arch = Reference::KindArch::x86; - break; - case lld::MachOLinkingContext::arch_ppc: - arch = Reference::KindArch::PowerPC; - break; - case lld::MachOLinkingContext::arch_armv6: - case lld::MachOLinkingContext::arch_armv7: - case lld::MachOLinkingContext::arch_armv7s: - arch = Reference::KindArch::ARM; - break; - case lld::MachOLinkingContext::arch_unknown: - return make_dynamic_error_code(Twine("unknown architecture")); - } - - inAtom->addReference(offsetInAtom, kind, target, addend, arch); + inAtom->addReference(offsetInAtom, kind, target, addend, + handler.kindArch()); } } return std::error_code(); @@ -616,8 +598,8 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path, } // Convert mach-o relocations to References - std::unique_ptr handler - = KindHandler::create(normalizedFile.arch); + std::unique_ptr handler + = ArchHandler::create(normalizedFile.arch); for (auto § : normalizedFile.sections) { if (isDebugInfoSection(sect)) continue; diff --git a/lld/lib/ReaderWriter/MachO/MachOPasses.h b/lld/lib/ReaderWriter/MachO/MachOPasses.h index d55fdf5..116563b 100644 --- a/lld/lib/ReaderWriter/MachO/MachOPasses.h +++ b/lld/lib/ReaderWriter/MachO/MachOPasses.h @@ -10,92 +10,16 @@ #ifndef LLD_READER_WRITER_MACHO_PASSES_H #define LLD_READER_WRITER_MACHO_PASSES_H -#include "lld/Core/Atom.h" -#include "lld/Core/File.h" -#include "lld/Core/Pass.h" -#include "lld/Core/range.h" -#include "lld/Core/Reference.h" - -#include +#include "lld/Core/PassManager.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" namespace lld { -class DefinedAtom; -class MutableFile; - - -/// Pass for adding stubs (PLT entries) for calls to functions -/// outside the linkage unit. This class is subclassed by each -/// file format Writer which implements the pure virtual methods. -class StubsPass : public Pass { -public: - StubsPass() : Pass() {} - - /// Scans all Atoms looking for call-site uses of SharedLibraryAtoms - /// and transfroms the call-site to call a stub instead using the - /// helper methods below. - void perform(std::unique_ptr &mergedFile) override; - - /// If true, the pass should use stubs for references - /// to shared library symbols. If false, the pass - /// will generate relocations on the text segment which the - /// runtime loader will use to patch the program at runtime. - virtual bool noTextRelocs() = 0; - - /// Returns whether the Reference kind is for a call site. The pass - /// uses this to find calls that need to be indirected through a stub. - virtual bool isCallSite(const Reference &) = 0; - - /// Returns a file format specific atom for a stub/PLT entry which contains - /// instructions which jump to the specified atom. May be called multiple - /// times for the same target atom, in which case this method should return - /// the same stub atom. - virtual const DefinedAtom *getStub(const Atom &target) = 0; - - /// After the default implementation of perform() is done calling getStub(), - /// it will call this method to add all the stub (and support) atoms to the - /// master file object. - virtual void addStubAtoms(MutableFile &masterFile) = 0; - -private: - void replaceCalleeWithStub(const Atom *target, const Reference *ref); -}; - -/// Pass for adding GOT entries for pointers to functions/data -/// outside the linkage unit. This class is subclassed by each -/// file format Writer which implements the pure virtual methods. -class GOTPass : public Pass { -public: - GOTPass() : Pass() {} - - /// Scans all Atoms looking for pointer to SharedLibraryAtoms - /// and transfroms them to a pointer to a GOT entry using the - /// helper methods below. - void perform(std::unique_ptr &mergedFile) override; - - /// If true, the pass will use GOT entries for references - /// to shared library symbols. If false, the pass - /// will generate relocations on the text segment which the - /// runtime loader will use to patch the program at runtime. - virtual bool noTextRelocs() = 0; - - /// Returns whether the Reference kind is a pre-instantiated GOT access. - /// The default implementation of perform() uses this to figure out - /// what GOT entries to instantiate. - virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) = 0; - - /// The file format Writer needs to alter the reference kind from a - /// pre-instantiated GOT access to an actual access. If targetIsNowGOT is - /// true, the pass has instantiated a GOT atom and altered the reference's - /// target to point to that atom. If targetIsNowGOT is false, the pass - /// determined a GOT entry is not needed because the reference site can - /// directly access the target. - virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0; +namespace mach_o { - /// Returns a file format specific atom for a GOT entry targeting - /// the specified atom. - virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0; -}; +void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx); +void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx); +} // namespace mach_o } // namespace lld #endif // LLD_READER_WRITER_MACHO_PASSES_H diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp deleted file mode 100644 index da15cfe..0000000 --- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -//===- lib/FileFormat/MachO/ReferenceKinds.cpp ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -#include "ReferenceKinds.h" -#include "MachONormalizedFileBinaryUtils.h" -#include "Atoms.h" - -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" - -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm::MachO; -using namespace lld::mach_o::normalized; - -namespace lld { -namespace mach_o { - -//===----------------------------------------------------------------------===// -// KindHandler -//===----------------------------------------------------------------------===// - -KindHandler::KindHandler() { -} - -KindHandler::~KindHandler() { -} - -std::unique_ptr -KindHandler::create(MachOLinkingContext::Arch arch) { - switch (arch) { - case MachOLinkingContext::arch_x86_64: - return std::unique_ptr(new KindHandler_x86_64()); - case MachOLinkingContext::arch_x86: - return std::unique_ptr(new KindHandler_x86()); - case MachOLinkingContext::arch_armv6: - case MachOLinkingContext::arch_armv7: - case MachOLinkingContext::arch_armv7s: - return std::unique_ptr(new KindHandler_arm()); - default: - llvm_unreachable("Unknown arch"); - } -} - -KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) { - assert((reloc.type & 0xFFF0) == 0); - uint16_t result = reloc.type; - if (reloc.scattered) - result |= rScattered; - if (reloc.pcRel) - result |= rPcRel; - if (reloc.isExtern) - result |= rExtern; - switch(reloc.length) { - case 0: - break; - case 1: - result |= rLength2; - break; - case 2: - result |= rLength4; - break; - case 3: - result |= rLength8; - break; - default: - llvm_unreachable("bad r_length"); - } - return result; -} - -int16_t KindHandler::readS16(bool swap, const uint8_t *addr) { - return read16(swap, *reinterpret_cast(addr)); -} - -int32_t KindHandler::readS32(bool swap, const uint8_t *addr) { - return read32(swap, *reinterpret_cast(addr)); -} - -uint32_t KindHandler::readU32(bool swap, const uint8_t *addr) { - return read32(swap, *reinterpret_cast(addr)); -} - -int64_t KindHandler::readS64(bool swap, const uint8_t *addr) { - return read64(swap, *reinterpret_cast(addr)); -} - - -//===----------------------------------------------------------------------===// -// KindHandler_x86_64 -//===----------------------------------------------------------------------===// - -KindHandler_x86_64::~KindHandler_x86_64() { -} - -const Registry::KindStrings KindHandler_x86_64::kindStrings[] = { - LLD_KIND_STRING_ENTRY(invalid), - LLD_KIND_STRING_ENTRY(branch32), - LLD_KIND_STRING_ENTRY(ripRel32), - LLD_KIND_STRING_ENTRY(ripRel32Minus1), - LLD_KIND_STRING_ENTRY(ripRel32Minus2), - LLD_KIND_STRING_ENTRY(ripRel32Minus4), - LLD_KIND_STRING_ENTRY(ripRel32Anon), - LLD_KIND_STRING_ENTRY(ripRel32GotLoad), - LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea), - LLD_KIND_STRING_ENTRY(ripRel32Got), - LLD_KIND_STRING_ENTRY(lazyPointer), - LLD_KIND_STRING_ENTRY(lazyImmediateLocation), - LLD_KIND_STRING_ENTRY(pointer64), - LLD_KIND_STRING_ENTRY(pointer64Anon), - LLD_KIND_STRING_ENTRY(delta32), - LLD_KIND_STRING_ENTRY(delta64), - LLD_KIND_STRING_ENTRY(delta32Anon), - LLD_KIND_STRING_ENTRY(delta64Anon), - LLD_KIND_STRING_END -}; - -bool KindHandler_x86_64::isCallSite(const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::mach_o) - return false; - assert(ref.kindArch() == Reference::KindArch::x86_64); - return (ref.kindValue() == branch32); -} - -bool KindHandler_x86_64::isPointer(const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::mach_o) - return false; - assert(ref.kindArch() == Reference::KindArch::x86_64); - Reference::KindValue kind = ref.kindValue(); - return (kind == pointer64 || kind == pointer64Anon); -} - -bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::mach_o) - return false; - assert(ref.kindArch() == Reference::KindArch::x86_64); - return (ref.kindValue() == lazyImmediateLocation); -} - -bool KindHandler_x86_64::isLazyTarget(const Reference &ref) { - if (ref.kindNamespace() != Reference::KindNamespace::mach_o) - return false; - assert(ref.kindArch() == Reference::KindArch::x86_64); - return (ref.kindValue() == lazyPointer); -} - -bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) { - return (reloc.type == X86_64_RELOC_SUBTRACTOR); -} - - -Reference::KindValue -KindHandler_x86_64::kindFromReloc(const Relocation &reloc) { - switch(relocPattern(reloc)) { - case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4: - return branch32; - case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4: - return ripRel32; - case X86_64_RELOC_SIGNED | rPcRel | rLength4: - return ripRel32Anon; - case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4: - return ripRel32Minus1; - case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4: - return ripRel32Minus2; - case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4: - return ripRel32Minus4; - case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4: - return ripRel32GotLoad; - case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4: - return ripRel32Got; - case X86_64_RELOC_UNSIGNED | rExtern | rLength8: - return pointer64; - case X86_64_RELOC_UNSIGNED | rLength8: - return pointer64Anon; - default: - return invalid; - } - -} - - -std::error_code -KindHandler_x86_64::getReferenceInfo(const 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) { - typedef std::error_code E; - *kind = kindFromReloc(reloc); - if (*kind == invalid) - return make_dynamic_error_code(Twine("unknown type")); - const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - uint64_t targetAddress; - switch (*kind) { - case branch32: - case ripRel32: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = readS32(swap, fixupContent); - return std::error_code(); - case ripRel32Minus1: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = readS32(swap, fixupContent) + 1; - return std::error_code(); - case ripRel32Minus2: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = readS32(swap, fixupContent) + 2; - return std::error_code(); - case ripRel32Minus4: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = readS32(swap, fixupContent) + 4; - return std::error_code(); - case ripRel32Anon: - targetAddress = fixupAddress + 4 + readS32(swap, fixupContent); - return atomFromAddress(reloc.symbol, targetAddress, target, addend); - case ripRel32GotLoad: - case ripRel32Got: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = 0; - return std::error_code(); - case pointer64: - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = readS64(swap, fixupContent); - return std::error_code(); - case pointer64Anon: - targetAddress = readS64(swap, fixupContent); - return atomFromAddress(reloc.symbol, targetAddress, target, addend); - default: - llvm_unreachable("bad reloc kind"); - } -} - - -Reference::KindValue -KindHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2) { - switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | - X86_64_RELOC_UNSIGNED | rExtern | rLength8): - return delta64; - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | - X86_64_RELOC_UNSIGNED | rExtern | rLength4): - return delta32; - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | - X86_64_RELOC_UNSIGNED | rLength8): - return delta64Anon; - case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | - X86_64_RELOC_UNSIGNED | rLength4): - return delta32Anon; - default: - llvm_unreachable("bad reloc pairs"); - } -} - - -std::error_code -KindHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - 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) { - *kind = kindFromRelocPair(reloc1, reloc2); - if (*kind == invalid) - return make_dynamic_error_code(Twine("unknown pair")); - const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - typedef std::error_code E; - uint64_t targetAddress; - const lld::Atom *fromTarget; - if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget)) - return ec; - if (fromTarget != inAtom) - return make_dynamic_error_code(Twine("pointer diff not in base atom")); - switch (*kind) { - case delta64: - if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) - return ec; - *addend = readS64(swap, fixupContent) + offsetInAtom; - return std::error_code(); - case delta32: - if (E ec = atomFromSymbolIndex(reloc2.symbol, target)) - return ec; - *addend = readS32(swap, fixupContent) + offsetInAtom; - return std::error_code(); - case delta64Anon: - targetAddress = offsetInAtom + readS64(swap, fixupContent); - return atomFromAddress(reloc2.symbol, targetAddress, target, addend); - case delta32Anon: - targetAddress = offsetInAtom + readS32(swap, fixupContent); - return atomFromAddress(reloc2.symbol, targetAddress, target, addend); - default: - llvm_unreachable("bad reloc pair kind"); - } -} - - - -void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue kindValue, - uint64_t addend, uint8_t *location, - uint64_t fixupAddress, - uint64_t targetAddress, - uint64_t inAtomAddress) { - if (ns != Reference::KindNamespace::mach_o) - return; - assert(arch == Reference::KindArch::x86_64); - int32_t *loc32 = reinterpret_cast(location); - uint64_t* loc64 = reinterpret_cast(location); - switch (kindValue) { - case branch32: - case ripRel32: - case ripRel32Got: - case ripRel32GotLoad: - *loc32 = (targetAddress - (fixupAddress+4)) + addend; - break; - case pointer64: - case pointer64Anon: - *loc64 = targetAddress + addend; - break; - case ripRel32Minus1: - *loc32 = (targetAddress - (fixupAddress+5)) + addend; - break; - case ripRel32Minus2: - *loc32 = (targetAddress - (fixupAddress+6)) + addend; - break; - case ripRel32Minus4: - *loc32 = (targetAddress - (fixupAddress+8)) + addend; - break; - case delta32: - case delta32Anon: - *loc32 = (targetAddress - fixupAddress) + addend; - break; - case delta64: - case delta64Anon: - *loc64 = (targetAddress - fixupAddress) + addend; - break; - case ripRel32GotLoadNowLea: - // Change MOVQ to LEA - assert(location[-2] == 0x8B); - location[-2] = 0x8D; - *loc32 = (targetAddress - (fixupAddress+4)) + addend; - break; - case lazyPointer: - case lazyImmediateLocation: - // do nothing - break; - default: - llvm_unreachable("invalid x86_64 Reference Kind"); - break; - } -} - - -//===----------------------------------------------------------------------===// -// KindHandler_x86 -//===----------------------------------------------------------------------===// - -KindHandler_x86::~KindHandler_x86() { -} - -const Registry::KindStrings KindHandler_x86::kindStrings[] = { - LLD_KIND_STRING_ENTRY(invalid), - LLD_KIND_STRING_ENTRY(branch32), - LLD_KIND_STRING_ENTRY(branch16), - LLD_KIND_STRING_ENTRY(abs32), - LLD_KIND_STRING_ENTRY(funcRel32), - LLD_KIND_STRING_ENTRY(pointer32), - LLD_KIND_STRING_ENTRY(delta32), - LLD_KIND_STRING_ENTRY(lazyPointer), - LLD_KIND_STRING_ENTRY(lazyImmediateLocation), - LLD_KIND_STRING_END -}; - -bool KindHandler_x86::isCallSite(const Reference &ref) { - return (ref.kindValue() == branch32); -} - -bool KindHandler_x86::isPointer(const Reference &ref) { - return (ref.kindValue() == pointer32); -} - -bool KindHandler_x86::isLazyImmediate(const Reference &ref) { - return (ref.kindValue() == lazyImmediateLocation); -} - -bool KindHandler_x86::isLazyTarget(const Reference &ref) { - return (ref.kindValue() == lazyPointer); -} - - -bool KindHandler_x86::isPairedReloc(const Relocation &reloc) { - if (!reloc.scattered) - return false; - return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) || - (reloc.type == GENERIC_RELOC_SECTDIFF); -} - - -std::error_code -KindHandler_x86::getReferenceInfo(const 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) { - typedef std::error_code E; - DefinedAtom::ContentPermissions perms; - const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - uint64_t targetAddress; - switch (relocPattern(reloc)) { - case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4: - // ex: call _foo (and _foo undefined) - *kind = branch32; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = fixupAddress + 4 + readS32(swap, fixupContent); - break; - case GENERIC_RELOC_VANILLA | rPcRel | rLength4: - // ex: call _foo (and _foo defined) - *kind = branch32; - targetAddress = fixupAddress + 4 + readS32(swap, fixupContent); - return atomFromAddress(reloc.symbol, targetAddress, target, addend); - break; - case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2: - // ex: callw _foo (and _foo undefined) - *kind = branch16; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = fixupAddress + 2 + readS16(swap, fixupContent); - break; - case GENERIC_RELOC_VANILLA | rPcRel | rLength2: - // ex: callw _foo (and _foo defined) - *kind = branch16; - targetAddress = fixupAddress + 2 + readS16(swap, fixupContent); - return atomFromAddress(reloc.symbol, targetAddress, target, addend); - break; - case GENERIC_RELOC_VANILLA | rExtern | rLength4: - // ex: movl _foo, %eax (and _foo undefined) - // ex: .long _foo (and _foo undefined) - perms = inAtom->permissions(); - *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) - ? abs32 : pointer32; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = readU32(swap, fixupContent); - break; - case GENERIC_RELOC_VANILLA | rLength4: - // ex: movl _foo, %eax (and _foo defined) - // ex: .long _foo (and _foo defined) - perms = inAtom->permissions(); - *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) - ? abs32 : pointer32; - targetAddress = readU32(swap, fixupContent); - return atomFromAddress(reloc.symbol, targetAddress, target, addend); - break; - default: - return make_dynamic_error_code(Twine("unsupported i386 relocation type")); - } - return std::error_code(); -} - - -std::error_code -KindHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - const DefinedAtom *inAtom, - uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, - FindAtomBySectionAndAddress atomFromAddr, - FindAtomBySymbolIndex atomFromSymbolIndex, - Reference::KindValue *kind, - const lld::Atom **target, - Reference::Addend *addend) { - const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - std::error_code ec; - DefinedAtom::ContentPermissions perms = inAtom->permissions(); - uint32_t fromAddress; - uint32_t toAddress; - uint32_t value; - const lld::Atom *fromTarget; - Reference::Addend offsetInTo; - Reference::Addend offsetInFrom; - switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { - case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 | - GENERIC_RELOC_PAIR | rScattered | rLength4): - case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 | - GENERIC_RELOC_PAIR | rScattered | rLength4): - toAddress = reloc1.value; - fromAddress = reloc2.value; - value = readS32(swap, fixupContent); - ec = atomFromAddr(0, toAddress, target, &offsetInTo); - if (ec) - return ec; - ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); - if (ec) - return ec; - if (fromTarget != inAtom) - return make_dynamic_error_code(Twine("SECTDIFF relocation where " - "subtrahend label is not in atom")); - *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) - ? funcRel32 : delta32; - if (*kind == funcRel32) { - // SECTDIFF relocations are used in i386 codegen where the function - // prolog does a CALL to the next instruction which POPs the return - // address into EBX which becomes the pic-base register. The POP - // instruction is label the used for the subtrahend in expressions. - // The funcRel32 kind represents the 32-bit delta to some symbol from - // the start of the function (atom) containing the funcRel32. - uint32_t ta = fromAddress + value - toAddress; - *addend = ta - offsetInFrom; - } else { - *addend = fromAddress + value - toAddress; - } - return std::error_code(); - break; - default: - return make_dynamic_error_code(Twine("unsupported i386 relocation type")); - } -} - -void KindHandler_x86::applyFixup(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue kindValue, - uint64_t addend, uint8_t *location, - uint64_t fixupAddress, - uint64_t targetAddress, - uint64_t inAtomAddress) { - if (ns != Reference::KindNamespace::mach_o) - return; - assert(arch == Reference::KindArch::x86); - int32_t *loc32 = reinterpret_cast(location); - int16_t *loc16 = reinterpret_cast(location); - // FIXME: these writes may need a swap. - switch (kindValue) { - case branch32: - *loc32 = (targetAddress - (fixupAddress+4)) + addend; - break; - case branch16: - *loc16 = (targetAddress - (fixupAddress+4)) + addend; - break; - case pointer32: - case abs32: - *loc32 = targetAddress + addend; - break; - case funcRel32: - *loc32 = targetAddress - inAtomAddress + addend; // FIXME - break; - case delta32: - *loc32 = targetAddress - fixupAddress + addend; - break; - case lazyPointer: - case lazyImmediateLocation: - // do nothing - break; - default: - llvm_unreachable("invalid x86 Reference Kind"); - break; - } -} - - -//===----------------------------------------------------------------------===// -// KindHandler_arm -//===----------------------------------------------------------------------===// - -KindHandler_arm::~KindHandler_arm() { -} - -const Registry::KindStrings KindHandler_arm::kindStrings[] = { - 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_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 -}; - -bool KindHandler_arm::isCallSite(const Reference &ref) { - return (ref.kindValue() == thumb_b22) || - (ref.kindValue() == arm_b24); -} - -bool KindHandler_arm::isPointer(const Reference &ref) { - return (ref.kindValue() == pointer32); -} - -bool KindHandler_arm::isLazyImmediate(const Reference &ref) { - return (ref.kindValue() == lazyImmediateLocation); -} - -bool KindHandler_arm::isLazyTarget(const Reference &ref) { - return (ref.kindValue() == lazyPointer); -} - -bool KindHandler_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; - } -} - - -int32_t KindHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) { - 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; - if (s) - return (sdis | 0xFE000000); - else - return sdis; -} - -int32_t KindHandler_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; -} - - -uint16_t KindHandler_arm::getWordFromThumbMov(uint32_t 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 KindHandler_arm::getWordFromArmMov(uint32_t instruction) { - uint32_t imm4 = ((instruction & 0x000F0000) >> 16); - uint32_t imm12 = (instruction & 0x00000FFF); - return (imm4 << 12) | imm12; -} - -uint32_t KindHandler_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(target)) { - const MachODefinedAtom *machoTarget = reinterpret_cast< - const MachODefinedAtom*>(target); - if (machoTarget->isThumb()) - value &= -2; // mask off thumb-bit - } - } - return value; -} - -std::error_code -KindHandler_arm::getReferenceInfo(const 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) { - typedef std::error_code E; - const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - uint64_t targetAddress; - uint32_t instruction = readU32(swap, fixupContent); - int32_t displacement; - switch (relocPattern(reloc)) { - case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4: - // ex: bl _foo (and _foo is undefined) - *kind = thumb_b22; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - // Instruction contains branch to addend. - displacement = getDisplacementFromThumbBranch(instruction); - *addend = fixupAddress + 4 + displacement; - return std::error_code(); - case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4: - // ex: bl _foo (and _foo is defined) - *kind = thumb_b22; - displacement = getDisplacementFromThumbBranch(instruction); - 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) - *kind = thumb_b22; - displacement = getDisplacementFromThumbBranch(instruction); - targetAddress = fixupAddress + 4 + displacement; - if (E 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 std::error_code(); - case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4: - // ex: bl _foo (and _foo is undefined) - *kind = arm_b24; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - // Instruction contains branch to addend. - displacement = getDisplacementFromArmBranch(instruction); - *addend = fixupAddress + 8 + displacement; - return std::error_code(); - case ARM_RELOC_BR24 | rPcRel | rLength4: - // ex: bl _foo (and _foo is defined) - *kind = arm_b24; - 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) - *kind = arm_b24; - displacement = getDisplacementFromArmBranch(instruction); - targetAddress = fixupAddress + 8 + displacement; - if (E 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 std::error_code(); - case ARM_RELOC_VANILLA | rExtern | rLength4: - // ex: .long _foo (and _foo is undefined) - *kind = pointer32; - if (E ec = atomFromSymbolIndex(reloc.symbol, target)) - return ec; - *addend = instruction; - return std::error_code(); - case ARM_RELOC_VANILLA | rLength4: - // ex: .long _foo (and _foo is defined) - *kind = pointer32; - if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend)) - return ec; - *addend = clearThumbBit((uint32_t)*addend, *target); - return std::error_code(); - case ARM_RELOC_VANILLA | rScattered | rLength4: - // ex: .long _foo+a (and _foo is defined) - *kind = pointer32; - if (E ec = atomFromAddress(0, reloc.value, target, addend)) - return ec; - *addend += (clearThumbBit(instruction, *target) - reloc.value); - return std::error_code(); - default: - return make_dynamic_error_code(Twine("unsupported arm relocation type")); - } - return std::error_code(); -} - - -std::error_code -KindHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - const DefinedAtom *inAtom, - uint32_t offsetInAtom, - uint64_t fixupAddress, bool swap, - 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 | rLength4) << 16 | - ARM_RELOC_PAIR | rScattered | rLength4): - // 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 | rLength8) << 16 | - ARM_RELOC_PAIR | rScattered | rLength8): - // 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 | rLength1) << 16 | - ARM_RELOC_PAIR | rScattered | rLength1): - // 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 | rLength2) << 16 | - ARM_RELOC_PAIR | rScattered | rLength2): - // ex: movt r1, :upper16:(_x-L1) [arm mode] - *kind = arm_movt_funcRel; - funcRel = true; - top = true; - thumbReloc = false; - break; - case ((ARM_RELOC_HALF | rLength4) << 16 | - ARM_RELOC_PAIR | rLength4): - // ex: movw r1, :lower16:_x [thumb mode] - *kind = thumb_movw; - funcRel = false; - top = false; - thumbReloc = true; - break; - case ((ARM_RELOC_HALF | rLength8) << 16 | - ARM_RELOC_PAIR | rLength8): - // ex: movt r1, :upper16:_x [thumb mode] - *kind = thumb_movt; - funcRel = false; - top = true; - thumbReloc = true; - break; - case ((ARM_RELOC_HALF | rLength1) << 16 | - ARM_RELOC_PAIR | rLength1): - // ex: movw r1, :lower16:_x [arm mode] - *kind = arm_movw; - funcRel = false; - top = false; - thumbReloc = false; - break; - case ((ARM_RELOC_HALF | rLength2) << 16 | - ARM_RELOC_PAIR | rLength2): - // ex: movt r1, :upper16:_x [arm mode] - *kind = arm_movt; - funcRel = false; - top = true; - thumbReloc = false; - break; - case ((ARM_RELOC_HALF | rScattered | rLength4) << 16 | - ARM_RELOC_PAIR | rLength4): - // ex: movw r1, :lower16:_x+a [thumb mode] - *kind = thumb_movw; - funcRel = false; - top = false; - thumbReloc = true; - break; - case ((ARM_RELOC_HALF | rScattered | rLength8) << 16 | - ARM_RELOC_PAIR | rLength8): - // ex: movt r1, :upper16:_x+a [thumb mode] - *kind = thumb_movt; - funcRel = false; - top = true; - thumbReloc = true; - break; - case ((ARM_RELOC_HALF | rScattered | rLength1) << 16 | - ARM_RELOC_PAIR | rLength1): - // ex: movw r1, :lower16:_x+a [arm mode] - *kind = arm_movw; - funcRel = false; - top = false; - thumbReloc = false; - break; - case ((ARM_RELOC_HALF | rScattered | rLength2) << 16 | - ARM_RELOC_PAIR | rLength2): - // ex: movt r1, :upper16:_x+a [arm mode] - *kind = arm_movt; - funcRel = false; - top = true; - thumbReloc = false; - break; - case ((ARM_RELOC_HALF | rExtern | rLength4) << 16 | - ARM_RELOC_PAIR | rLength4): - // ex: movw r1, :lower16:_undef [thumb mode] - *kind = thumb_movw; - funcRel = false; - top = false; - thumbReloc = true; - break; - case ((ARM_RELOC_HALF | rExtern | rLength8) << 16 | - ARM_RELOC_PAIR | rLength8): - // ex: movt r1, :upper16:_undef [thumb mode] - *kind = thumb_movt; - funcRel = false; - top = true; - thumbReloc = true; - break; - case ((ARM_RELOC_HALF | rExtern | rLength1) << 16 | - ARM_RELOC_PAIR | rLength1): - // ex: movw r1, :lower16:_undef [arm mode] - *kind = arm_movw; - funcRel = false; - top = false; - thumbReloc = false; - break; - case ((ARM_RELOC_HALF | rExtern | rLength2) << 16 | - ARM_RELOC_PAIR | rLength2): - // 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 make_dynamic_error_code(Twine("unsupported arm relocation pair")); - } - const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; - std::error_code ec; - uint32_t instruction = readU32(swap, 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; - ec = atomFromAddr(0, toAddress, target, &offsetInTo); - if (ec) - return ec; - ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); - if (ec) - return ec; - if (fromTarget != inAtom) - return make_dynamic_error_code(Twine("SECTDIFF relocation where " - "subtrahend label is not in atom")); - *kind = delta32; - value = clearThumbBit(instruction, *target); - *addend = value - (toAddress - fromAddress); - } else if (funcRel) { - toAddress = reloc1.value; - fromAddress = reloc2.value; - ec = atomFromAddr(0, toAddress, target, &offsetInTo); - if (ec) - return ec; - ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom); - if (ec) - return ec; - if (fromTarget != inAtom) - return make_dynamic_error_code(Twine("ARM_RELOC_HALF_SECTDIFF relocation " - "where subtrahend label is not in atom")); - other16 = (reloc2.offset & 0xFFFF); - if (thumbReloc) - instruction16 = getWordFromThumbMov(instruction); - else - 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 std::error_code(); - } else { - uint32_t sectIndex; - if (thumbReloc) - instruction16 = getWordFromThumbMov(instruction); - else - instruction16 = getWordFromArmMov(instruction); - other16 = (reloc2.offset & 0xFFFF); - if (top) - value = (instruction16 << 16) | other16; - else - value = (other16 << 16) | instruction16; - if (reloc1.isExtern) { - ec = atomFromSymbolIndex(reloc1.symbol, target); - if (ec) - return ec; - *addend = value; - } else { - if (reloc1.scattered) { - toAddress = reloc1.value; - sectIndex = 0; - } else { - toAddress = value; - sectIndex = reloc1.symbol; - } - ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo); - if (ec) - return ec; - *addend = value - toAddress; - } - } - - return std::error_code(); -} - - - -void KindHandler_arm::applyFixup(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue kindValue, - uint64_t addend, uint8_t *location, - uint64_t fixupAddress, - uint64_t targetAddress, - uint64_t inAtomAddress) { - if (ns != Reference::KindNamespace::mach_o) - return; - assert(arch == Reference::KindArch::ARM); - //int32_t *loc32 = reinterpret_cast(location); - // FIXME: these writes may need a swap. - switch (kindValue) { - case thumb_b22: - // FIXME - break; - case thumb_movw: - // FIXME - break; - case thumb_movt: - // FIXME - break; - case thumb_movw_funcRel: - // FIXME - break; - case thumb_movt_funcRel: - // FIXME - break; - case arm_b24: - // FIXME - break; - case arm_movw: - // FIXME - break; - case arm_movt: - // FIXME - break; - case arm_movw_funcRel: - // FIXME - break; - case arm_movt_funcRel: - // FIXME - break; - case pointer32: - // FIXME - break; - case delta32: - // FIXME - break; - case lazyPointer: - case lazyImmediateLocation: - // do nothing - break; - case invalid: - llvm_unreachable("invalid ARM Reference Kind"); - break; - } -} - - -} // namespace mach_o -} // namespace lld - - - diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h deleted file mode 100644 index f8a48b2..0000000 --- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h +++ /dev/null @@ -1,334 +0,0 @@ -//===- lib/FileFormat/MachO/ReferenceKinds.h ------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -#include "MachONormalizedFile.h" - -#include "lld/Core/LLVM.h" -#include "lld/Core/Reference.h" -#include "lld/ReaderWriter/MachOLinkingContext.h" - -#include "llvm/ADT/Triple.h" - -#ifndef LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H -#define LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H - -namespace lld { -namespace mach_o { - - -/// -/// The KindHandler class is the abstract interface to Reference::Kind -/// values for mach-o files. Particular Kind values (e.g. 3) has a different -/// meaning for each architecture. -/// -class KindHandler { -public: - - static std::unique_ptr create(MachOLinkingContext::Arch); - virtual ~KindHandler(); - - virtual bool isCallSite(const Reference &) = 0; - virtual bool isPointer(const Reference &) = 0; - virtual bool isLazyImmediate(const Reference &) = 0; - virtual bool isLazyTarget(const Reference &) = 0; - - /// Returns true if the specified relocation is paired to the next relocation. - virtual bool isPairedReloc(const normalized::Relocation &) = 0; - - /// Prototype for a helper function. Given a sectionIndex and address, - /// finds the atom and offset with that atom of that address. - typedef std::function - FindAtomBySectionAndAddress; - - /// Prototype for a helper function. Given a symbolIndex, finds the atom - /// representing that symbol. - typedef std::function FindAtomBySymbolIndex; - - /// Analyzes a relocation from a .o file and returns the info - /// (kind, target, addend) needed to instantiate a Reference. - /// Two helper functions are passed as parameters to find the target atom - /// given a symbol index or address. - virtual std::error_code - 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) = 0; - - /// Analyzes a pair of relocations from a .o file and returns the info - /// (kind, target, addend) needed to instantiate a Reference. - /// Two helper functions are passed as parameters to find the target atom - /// given a symbol index or address. - virtual std::error_code - getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - 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) = 0; - - /// Fixup an atom when generating a final linked binary. - virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) = 0; - -protected: - KindHandler(); - - // Handy way to pack mach-o r_type and other bit fields into one 16-bit value. - typedef uint16_t RelocPattern; - enum { - rScattered = 0x8000, - rPcRel = 0x4000, - rExtern = 0x2000, - rLength1 = 0x0000, - rLength2 = 0x0100, - rLength4 = 0x0200, - rLength8 = 0x0300 - }; - static RelocPattern relocPattern(const normalized::Relocation &reloc); - - static int16_t readS16(bool swap, const uint8_t *addr); - static int32_t readS32(bool swap, const uint8_t *addr); - static uint32_t readU32(bool swap, const uint8_t *addr); - static int64_t readS64(bool swap, const uint8_t *addr); -}; - - - -class KindHandler_x86_64 : public KindHandler { -public: - static const Registry::KindStrings kindStrings[]; - - virtual ~KindHandler_x86_64(); - bool isCallSite(const Reference &) override; - bool isPointer(const Reference &) override; - bool isLazyImmediate(const Reference &) override; - bool isLazyTarget(const Reference &) override; - bool isPairedReloc(const normalized::Relocation &) override; - std::error_code 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; - std::error_code - getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - 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; - - virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) - override; - -private: - friend class X86_64LazyPointerAtom; - friend class X86_64StubHelperAtom; - friend class X86_64StubAtom; - friend class X86_64StubHelperCommonAtom; - friend class X86_64NonLazyPointerAtom; - - enum : Reference::KindValue { - invalid, /// for error condition - - // Kinds found in mach-o .o files: - branch32, /// ex: call _foo - ripRel32, /// ex: movq _foo(%rip), %rax - ripRel32Minus1, /// ex: movb $0x12, _foo(%rip) - ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip) - ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip) - ripRel32Anon, /// ex: movq L1(%rip), %rax - ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax - ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip) - pointer64, /// ex: .quad _foo - pointer64Anon, /// ex: .quad L1 - delta64, /// ex: .quad _foo - . - delta32, /// ex: .long _foo - . - delta64Anon, /// ex: .quad L1 - . - delta32Anon, /// ex: .long L1 - . - - // Kinds introduced by Passes: - ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so - /// "movq _foo@GOTPCREL(%rip), %rax" can be changed - /// to "leaq _foo(%rip), %rax - lazyPointer, /// Location contains a lazy pointer. - lazyImmediateLocation, /// Location contains immediate value used in stub. - }; - - Reference::KindValue kindFromReloc(const normalized::Relocation &reloc); - Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2); - - -}; - -class KindHandler_x86 : public KindHandler { -public: - static const Registry::KindStrings kindStrings[]; - - virtual ~KindHandler_x86(); - bool isCallSite(const Reference &) override; - bool isPointer(const Reference &) override; - bool isLazyImmediate(const Reference &) override; - bool isLazyTarget(const Reference &) override; - bool isPairedReloc(const normalized::Relocation &) override; - std::error_code 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; - std::error_code - getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - 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; - - void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) - override; - -private: - friend class X86LazyPointerAtom; - friend class X86StubHelperAtom; - friend class X86StubAtom; - friend class X86StubHelperCommonAtom; - friend class X86NonLazyPointerAtom; - - enum : Reference::KindValue { - invalid, /// for error condition - - // Kinds found in mach-o .o files: - branch32, /// ex: call _foo - branch16, /// ex: callw _foo - abs32, /// ex: movl _foo, %eax - funcRel32, /// ex: movl _foo-L1(%eax), %eax - 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. - }; - - -}; - - - -class KindHandler_arm : public KindHandler { -public: - static const Registry::KindStrings kindStrings[]; - - virtual ~KindHandler_arm(); - bool isCallSite(const Reference &) override; - bool isPointer(const Reference &) override; - bool isLazyImmediate(const Reference &) override; - bool isLazyTarget(const Reference &) override; - bool isPairedReloc(const normalized::Relocation &) override; - std::error_code 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; - std::error_code - getPairReferenceInfo(const normalized::Relocation &reloc1, - const normalized::Relocation &reloc2, - 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; - - void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch, - Reference::KindValue kindValue, uint64_t addend, - uint8_t *location, uint64_t fixupAddress, - uint64_t targetAddress, uint64_t inAtomAddress) - override; - -private: - enum : Reference::KindValue { - invalid, /// for error condition - - // Kinds found in mach-o .o files: - thumb_b22, /// ex: bl _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_b24, /// ex: bl _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. - }; - - int32_t getDisplacementFromThumbBranch(uint32_t instruction); - int32_t getDisplacementFromArmBranch(uint32_t instruction); - uint16_t getWordFromThumbMov(uint32_t instruction); - uint16_t getWordFromArmMov(uint32_t instruction); - uint32_t clearThumbBit(uint32_t value, const Atom* target); - -}; - -} // namespace mach_o -} // namespace lld - - - -#endif // LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H - diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms.hpp deleted file mode 100644 index 64afd1a..0000000 --- a/lld/lib/ReaderWriter/MachO/StubAtoms.hpp +++ /dev/null @@ -1,71 +0,0 @@ -//===- lib/ReaderWriter/MachO/StubAtoms.hpp -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_H -#define LLD_READER_WRITER_MACHO_STUB_ATOMS_H - -#include "llvm/ADT/ArrayRef.h" - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Reference.h" -#include "lld/Core/SharedLibraryAtom.h" -#include "lld/Core/Simple.h" - -#include "ReferenceKinds.h" -#include "StubAtoms_x86_64.hpp" -#include "StubAtoms_x86.hpp" - -namespace lld { -namespace mach_o { - - -// -// StubBinderAtom created by the stubs pass. -// -class StubBinderAtom : public SharedLibraryAtom { -public: - StubBinderAtom(const File &f) : _file(f) { - } - - const File& file() const override { - return _file; - } - - StringRef name() const override { - return StringRef("dyld_stub_binder"); - } - - StringRef loadName() const override { - return StringRef("/usr/lib/libSystem.B.dylib"); - } - - bool canBeNullAtRuntime() const override { - return false; - } - - Type type() const override { - return Type::Unknown; - } - - uint64_t size() const override { - return 0; - } - -private: - const File &_file; -}; - - - -} // namespace mach_o -} // namespace lld - - -#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_H diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms_x86.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms_x86.hpp deleted file mode 100644 index 0d49454..0000000 --- a/lld/lib/ReaderWriter/MachO/StubAtoms_x86.hpp +++ /dev/null @@ -1,215 +0,0 @@ -//===- lib/ReaderWriter/MachO/StubAtoms_x86.hpp ---------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H -#define LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H - -#include "llvm/ADT/ArrayRef.h" - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/SharedLibraryAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Reference.h" - -#include "ReferenceKinds.h" - -using llvm::makeArrayRef; - -namespace lld { -namespace mach_o { - -// -// X86 Stub Atom created by the stubs pass. -// -class X86StubAtom : public SimpleDefinedAtom { -public: - X86StubAtom(const File &file, const Atom &lazyPointer) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::abs32, 2, - &lazyPointer, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeStub; - } - - uint64_t size() const override { - return 6; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permR_X; - } - - ArrayRef rawContent() const override { - static const uint8_t instructions[] = - { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer - assert(sizeof(instructions) == this->size()); - return makeArrayRef(instructions); - } -}; - - -// -// X86 Stub Helper Common Atom created by the stubs pass. -// -class X86StubHelperCommonAtom : public SimpleDefinedAtom { -public: - X86StubHelperCommonAtom(const File &file, const Atom &cache, - const Atom &binder) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::abs32, 1, - &cache, 0); - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::abs32, 7, - &binder, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeStubHelper; - } - - uint64_t size() const override { - return 12; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permR_X; - } - - ArrayRef rawContent() const override { - static const uint8_t instructions[] = - { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache - 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind - 0x90 }; // nop - assert(sizeof(instructions) == this->size()); - return makeArrayRef(instructions); - } -}; - - -// -// X86 Stub Helper Atom created by the stubs pass. -// -class X86StubHelperAtom : public SimpleDefinedAtom { -public: - X86StubHelperAtom(const File &file, const Atom &helperCommon) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, - KindHandler_x86::lazyImmediateLocation, 1, this, 0); - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::branch32, 6, - &helperCommon, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeStubHelper; - } - - uint64_t size() const override { - return 10; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permR_X; - } - - ArrayRef rawContent() const override { - static const uint8_t instructions[] = - { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset - 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper - assert(sizeof(instructions) == this->size()); - return makeArrayRef(instructions); - } -}; - - -// -// X86 Lazy Pointer Atom created by the stubs pass. -// -class X86LazyPointerAtom : public SimpleDefinedAtom { -public: - X86LazyPointerAtom(const File &file, const Atom &helper, const Atom &shlib) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::pointer32, 0, - &helper, 0); - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::lazyPointer, - 0, &shlib, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeLazyPointer; - } - - Alignment alignment() const override { - return Alignment(2); - } - - uint64_t size() const override { - return 4; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permRW_; - } - - ArrayRef rawContent() const override { - static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x00 }; - return makeArrayRef(bytes); - } -}; - - -// -// X86 NonLazy (GOT) Pointer Atom created by the stubs pass. -// -class X86NonLazyPointerAtom : public SimpleDefinedAtom { -public: - X86NonLazyPointerAtom(const File &file) - : SimpleDefinedAtom(file) {} - - X86NonLazyPointerAtom(const File &file, const Atom &shlib) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86, KindHandler_x86::pointer32, 0, - &shlib, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeGOT; - } - - Alignment alignment() const override { - return Alignment(2); - } - - uint64_t size() const override { - return 4; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permRW_; - } - - ArrayRef rawContent() const override { - static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x0 }; - return makeArrayRef(bytes); - } -}; - -} // namespace mach_o -} // namespace lld - - -#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp deleted file mode 100644 index 6608732..0000000 --- a/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp +++ /dev/null @@ -1,218 +0,0 @@ -//===- lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp ------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H -#define LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H - -#include "llvm/ADT/ArrayRef.h" - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/SharedLibraryAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Reference.h" - -#include "ReferenceKinds.h" - -using llvm::makeArrayRef; -using namespace llvm::MachO; - -namespace lld { -namespace mach_o { - -// -// X86_64 Stub Atom created by the stubs pass. -// -class X86_64StubAtom : public SimpleDefinedAtom { -public: - X86_64StubAtom(const File &file, const Atom &lazyPointer) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::ripRel32, 2, - &lazyPointer, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeStub; - } - - uint64_t size() const override { - return 6; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permR_X; - } - - ArrayRef rawContent() const override { - static const uint8_t instructions[] = - { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer - assert(sizeof(instructions) == this->size()); - return makeArrayRef(instructions); - } -}; - -// -// X86_64 Stub Helper Common Atom created by the stubs pass. -// -class X86_64StubHelperCommonAtom : public SimpleDefinedAtom { -public: - X86_64StubHelperCommonAtom(const File &file, const Atom &cache, - const Atom &binder) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::ripRel32, 3, &cache, 0); - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::ripRel32, 11, &binder, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeStubHelper; - } - - uint64_t size() const override { - return 16; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permR_X; - } - - ArrayRef rawContent() const override { - static const uint8_t instructions[] = - { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11 - 0x41, 0x53, // push %r11 - 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip) - 0x90 }; // nop - assert(sizeof(instructions) == this->size()); - return makeArrayRef(instructions); - } -}; - -// -// X86_64 Stub Helper Atom created by the stubs pass. -// -class X86_64StubHelperAtom : public SimpleDefinedAtom { -public: - X86_64StubHelperAtom(const File &file, const Atom &helperCommon) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::lazyImmediateLocation, 1, this, 0); - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::ripRel32, 6, - &helperCommon, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeStubHelper; - } - - uint64_t size() const override { - return 10; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permR_X; - } - - ArrayRef rawContent() const override { - static const uint8_t instructions[] = - { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset - 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper - assert(sizeof(instructions) == this->size()); - return makeArrayRef(instructions); - } -}; - -// -// X86_64 Lazy Pointer Atom created by the stubs pass. -// -class X86_64LazyPointerAtom : public SimpleDefinedAtom { -public: - X86_64LazyPointerAtom(const File &file, const Atom &helper, - const Atom &shlib) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::pointer64, 0, &helper, 0); - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::lazyPointer, 0, &shlib, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeLazyPointer; - } - - Alignment alignment() const override { - return Alignment(3); - } - - uint64_t size() const override { - return 8; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permRW_; - } - - ArrayRef rawContent() const override { - static const uint8_t bytes[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - return makeArrayRef(bytes); - } -}; - -// -// X86_64 NonLazy (GOT) Pointer Atom created by the stubs pass. -// -class X86_64NonLazyPointerAtom : public SimpleDefinedAtom { -public: - X86_64NonLazyPointerAtom(const File &file) - : SimpleDefinedAtom(file) {} - - X86_64NonLazyPointerAtom(const File &file, const Atom &shlib) - : SimpleDefinedAtom(file) { - this->addReference(Reference::KindNamespace::mach_o, - Reference::KindArch::x86_64, - KindHandler_x86_64::pointer64, 0, &shlib, 0); - } - - ContentType contentType() const override { - return DefinedAtom::typeGOT; - } - - Alignment alignment() const override { - return Alignment(3); - } - - uint64_t size() const override { - return 8; - } - - ContentPermissions permissions() const override { - return DefinedAtom::permRW_; - } - - ArrayRef rawContent() const override { - static const uint8_t bytes[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - return makeArrayRef(bytes); - } -}; - -} // namespace mach_o -} // namespace lld - - -#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.cpp b/lld/lib/ReaderWriter/MachO/StubsPass.cpp index 630e00b..4956102 100644 --- a/lld/lib/ReaderWriter/MachO/StubsPass.cpp +++ b/lld/lib/ReaderWriter/MachO/StubsPass.cpp @@ -14,54 +14,371 @@ // //===----------------------------------------------------------------------===// +#include "ArchHandler.h" +#include "File.h" +#include "MachOPasses.h" + #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" +#include "lld/Core/Simple.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" + #include "llvm/ADT/DenseMap.h" -#include "MachOPasses.h" namespace lld { +namespace mach_o { + + +// +// Lazy Pointer Atom created by the stubs pass. +// +class LazyPointerAtom : public SimpleDefinedAtom { +public: + LazyPointerAtom(const File &file, bool is64) + : SimpleDefinedAtom(file), _is64(is64) { } + + ContentType contentType() const override { + return DefinedAtom::typeLazyPointer; + } + + Alignment alignment() const override { + return Alignment(_is64 ? 3 : 2); + } + + uint64_t size() const override { + return _is64 ? 8 : 4; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permRW_; + } + + ArrayRef rawContent() const override { + static const uint8_t zeros[] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + return llvm::makeArrayRef(zeros, size()); + } + +private: + const bool _is64; +}; + + +// +// NonLazyPointer (GOT) Atom created by the stubs pass. +// +class NonLazyPointerAtom : public SimpleDefinedAtom { +public: + NonLazyPointerAtom(const File &file, bool is64) + : SimpleDefinedAtom(file), _is64(is64) { } + + ContentType contentType() const override { + return DefinedAtom::typeGOT; + } + + Alignment alignment() const override { + return Alignment(_is64 ? 3 : 2); + } + + uint64_t size() const override { + return _is64 ? 8 : 4; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permRW_; + } + + ArrayRef rawContent() const override { + static const uint8_t zeros[] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + return llvm::makeArrayRef(zeros, size()); + } + +private: + const bool _is64; +}; + + + +// +// Stub Atom created by the stubs pass. +// +class StubAtom : public SimpleDefinedAtom { +public: + StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo) + : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + + ContentType contentType() const override { + return DefinedAtom::typeStub; + } + + Alignment alignment() const override { + return Alignment(_stubInfo.codeAlignment); + } + + uint64_t size() const override { + return _stubInfo.stubSize; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permR_X; + } + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(_stubInfo.stubBytes, _stubInfo.stubSize); + } + +private: + const ArchHandler::StubInfo &_stubInfo; +}; + + +// +// Stub Helper Atom created by the stubs pass. +// +class StubHelperAtom : public SimpleDefinedAtom { +public: + StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo) + : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + + ContentType contentType() const override { + return DefinedAtom::typeStubHelper; + } + + Alignment alignment() const override { + return Alignment(_stubInfo.codeAlignment); + } + + uint64_t size() const override { + return _stubInfo.stubHelperSize; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permR_X; + } + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(_stubInfo.stubHelperBytes, + _stubInfo.stubHelperSize); + } + +private: + const ArchHandler::StubInfo &_stubInfo; +}; + + +// +// Stub Helper Common Atom created by the stubs pass. +// +class StubHelperCommonAtom : public SimpleDefinedAtom { +public: + StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo) + : SimpleDefinedAtom(file), _stubInfo(stubInfo) { } + + ContentType contentType() const override { + return DefinedAtom::typeStubHelper; + } + + Alignment alignment() const override { + return Alignment(_stubInfo.codeAlignment); + } + + uint64_t size() const override { + return _stubInfo.stubHelperCommonSize; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permR_X; + } + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(_stubInfo.stubHelperCommonBytes, + _stubInfo.stubHelperCommonSize); + } + +private: + const ArchHandler::StubInfo &_stubInfo; +}; + + +class StubsPass : public Pass { +public: + StubsPass(const MachOLinkingContext &context) + : _context(context) + , _archHandler(_context.archHandler()) + , _stubInfo(_archHandler.stubInfo()) + , _file("") + , _helperCommonAtom(nullptr) + , _helperCacheNLPAtom(nullptr) + , _helperBinderNLPAtom(nullptr) { + } -void StubsPass::perform(std::unique_ptr &mergedFile) { - // Skip this pass if output format uses text relocations instead of stubs. - if (!this->noTextRelocs()) - return; - - // Scan all references in all atoms. - for (const DefinedAtom *atom : mergedFile->defined()) { - for (const Reference *ref : *atom) { - // Look at call-sites. - if (!this->isCallSite(*ref)) - continue; - const Atom *target = ref->target(); - assert(target != nullptr); - if (target->definition() == Atom::definitionSharedLibrary) { - // Calls to shared libraries go through stubs. - replaceCalleeWithStub(target, ref); - continue; + + void perform(std::unique_ptr &mergedFile) override { + // Skip this pass if output format uses text relocations instead of stubs. + if (!this->noTextRelocs()) + return; + + // Scan all references in all atoms. + for (const DefinedAtom *atom : mergedFile->defined()) { + for (const Reference *ref : *atom) { + // Look at call-sites. + if (!this->isCallSite(*ref)) + continue; + const Atom *target = ref->target(); + assert(target != nullptr); + if (target->definition() == Atom::definitionSharedLibrary) { + // Calls to shared libraries go through stubs. + replaceCalleeWithStub(target, ref); + continue; + } + const DefinedAtom *defTarget = dyn_cast(target); + if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){ + // Calls to interposable functions in same linkage unit must also go + // through a stub. + assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); + replaceCalleeWithStub(target, ref); + } } - const DefinedAtom *defTarget = dyn_cast(target); - if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo) { - // Calls to interposable functions in same linkage unit must also go - // through a stub. - assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); - replaceCalleeWithStub(target, ref); + } + // Exit early if no stubs needed. + if (_targetToStub.empty()) + return; + + // Add reference to dyld_stub_binder in libSystem.dylib + if (_helperBinderNLPAtom) { + bool found = false; + for (const SharedLibraryAtom *atom : mergedFile->sharedLibrary()) { + if (atom->name().equals(_stubInfo.binderSymbolName)) { + addReference(_helperBinderNLPAtom, + _stubInfo.nonLazyPointerReferenceToBinder, atom); + found = true; + break; + } } + assert(found && "dyld_stub_binder not found"); + } + + // Add all stubs to master file. + for (auto it : _targetToStub) { + mergedFile->addAtom(*it.second); + } + // Add helper code atoms. + mergedFile->addAtom(*_helperCommonAtom); + for (const DefinedAtom *lp : _stubHelperAtoms) { + mergedFile->addAtom(*lp); + } + // Add GOT slots used for lazy binding. + mergedFile->addAtom(*_helperBinderNLPAtom); + mergedFile->addAtom(*_helperCacheNLPAtom); + // Add all lazy pointers to master file. + for (const DefinedAtom *lp : _lazyPointers) { + mergedFile->addAtom(*lp); } } - // Add all created stubs and support Atoms. - this->addStubAtoms(*mergedFile); -} -void StubsPass::replaceCalleeWithStub(const Atom *target, - const Reference *ref) { - // Make file-format specific stub and other support atoms. - const DefinedAtom *stub = this->getStub(*target); - assert(stub != nullptr); - // Switch call site to reference stub atom instead. - const_cast(ref)->setTarget(stub); + +private: + + bool noTextRelocs() { + return true; + } + + bool isCallSite(const Reference &ref) { + return _archHandler.isCallSite(ref); + } + + void replaceCalleeWithStub(const Atom *target, const Reference *ref) { + // Make file-format specific stub and other support atoms. + const DefinedAtom *stub = this->getStub(*target); + assert(stub != nullptr); + // Switch call site to reference stub atom instead. + const_cast(ref)->setTarget(stub); + } + + const DefinedAtom* getStub(const Atom& target) { + auto pos = _targetToStub.find(&target); + if ( pos != _targetToStub.end() ) { + // Reuse an existing stub. + assert(pos->second != nullptr); + return pos->second; + } + else { + // There is no existing stub, so create a new one. + return this->makeStub(target); + } + } + + const DefinedAtom* makeStub(const Atom &target) { + SimpleDefinedAtom* stub = new (_file.allocator()) + StubAtom(_file, _stubInfo); + SimpleDefinedAtom* lp = new (_file.allocator()) + LazyPointerAtom(_file, _context.is64Bit()); + SimpleDefinedAtom* helper = new (_file.allocator()) + StubHelperAtom(_file, _stubInfo); + + addReference(stub, _stubInfo.stubReferenceToLP, lp); + addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper); + addReference(lp, _stubInfo.lazyPointerReferenceToFinal, &target); + addReference(helper, _stubInfo.stubHelperReferenceToImm, helper); + addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon, + helperCommon()); + + _stubHelperAtoms.push_back(helper); + _targetToStub[&target] = stub; + _lazyPointers.push_back(lp); + + return stub; + } + + void addReference(SimpleDefinedAtom* atom, + const ArchHandler::ReferenceInfo &refInfo, + const lld::Atom* target) { + atom->addReference(Reference::KindNamespace::mach_o, + refInfo.arch, refInfo.kind, refInfo.offset, + target, refInfo.addend); + } + + const DefinedAtom* helperCommon() { + if ( !_helperCommonAtom ) { + // Lazily create common helper code and data. + _helperCommonAtom = new (_file.allocator()) + StubHelperCommonAtom(_file, _stubInfo); + _helperCacheNLPAtom = new (_file.allocator()) + NonLazyPointerAtom(_file, _context.is64Bit()); + _helperBinderNLPAtom = new (_file.allocator()) + NonLazyPointerAtom(_file, _context.is64Bit()); + addReference(_helperCommonAtom, + _stubInfo.stubHelperCommonReferenceToCache, + _helperCacheNLPAtom); + addReference(_helperCommonAtom, + _stubInfo.stubHelperCommonReferenceToBinder, + _helperBinderNLPAtom); + } + return _helperCommonAtom; + } + + + const MachOLinkingContext &_context; + mach_o::ArchHandler &_archHandler; + const ArchHandler::StubInfo &_stubInfo; + MachOFile _file; + llvm::DenseMap _targetToStub; + std::vector _lazyPointers; + std::vector _stubHelperAtoms; + SimpleDefinedAtom *_helperCommonAtom; + SimpleDefinedAtom *_helperCacheNLPAtom; + SimpleDefinedAtom *_helperBinderNLPAtom; +}; + + + +void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) { + pm.add(std::unique_ptr(new StubsPass(ctx))); } +} // end namespace mach_o } // end namespace lld diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.hpp b/lld/lib/ReaderWriter/MachO/StubsPass.hpp deleted file mode 100644 index 0e70589..0000000 --- a/lld/lib/ReaderWriter/MachO/StubsPass.hpp +++ /dev/null @@ -1,173 +0,0 @@ -//===- lib/ReaderWriter/MachO/StubsPass.hpp -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_MACHO_STUBS_PASS_H -#define LLD_READER_WRITER_MACHO_STUBS_PASS_H - -#include "llvm/ADT/DenseMap.h" - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Pass.h" -#include "lld/Core/Reference.h" -#include "lld/Core/SharedLibraryAtom.h" -#include "lld/Core/Simple.h" - -#include "MachOPasses.h" -#include "ReferenceKinds.h" -#include "StubAtoms.hpp" - -namespace lld { -namespace mach_o { - - -class StubsPass : public lld::StubsPass { -public: - StubsPass(const MachOLinkingContext &context) - : _context(context) - , _kindHandler(_context.kindHandler()) - , _file(context) - , _helperCommonAtom(nullptr) - , _helperCacheAtom(nullptr) - , _helperBinderAtom(nullptr) { - } - - bool noTextRelocs() override { - return true; - } - - bool isCallSite(const Reference &ref) override { - return _kindHandler.isCallSite(ref); - } - - const DefinedAtom* getStub(const Atom& target) override { - auto pos = _targetToStub.find(&target); - if ( pos != _targetToStub.end() ) { - // Reuse an existing stub. - assert(pos->second != nullptr); - return pos->second; - } - else { - // There is no existing stub, so create a new one. - return this->makeStub(target); - } - } - - const DefinedAtom* makeStub(const Atom& target) { - switch (_context.arch()) { - case MachOLinkingContext::arch_x86_64: - return makeStub_x86_64(target); - case MachOLinkingContext::arch_x86: - return makeStub_x86(target); - case MachOLinkingContext::arch_armv6: - case MachOLinkingContext::arch_armv7: - case MachOLinkingContext::arch_armv7s: - return makeStub_arm(target); - default: - llvm_unreachable("Unknown mach-o arch"); - } - } - - const DefinedAtom* makeStub_x86_64(const Atom& target) { - if ( _helperCommonAtom == nullptr ) { - // Lazily create common helper code and data. - _helperCacheAtom = new X86_64NonLazyPointerAtom(_file); - _binderAtom = new StubBinderAtom(_file); - _helperBinderAtom = new X86_64NonLazyPointerAtom(_file, *_binderAtom); - _helperCommonAtom = new X86_64StubHelperCommonAtom(_file, - *_helperCacheAtom, *_helperBinderAtom); - } - const DefinedAtom* helper = new X86_64StubHelperAtom(_file, - *_helperCommonAtom); - _stubHelperAtoms.push_back(helper); - const DefinedAtom* lp = new X86_64LazyPointerAtom(_file, *helper, target); - assert(lp->contentType() == DefinedAtom::typeLazyPointer); - _lazyPointers.push_back(lp); - const DefinedAtom* stub = new X86_64StubAtom(_file, *lp); - assert(stub->contentType() == DefinedAtom::typeStub); - _targetToStub[&target] = stub; - return stub; - } - - const DefinedAtom* makeStub_x86(const Atom& target) { - if ( _helperCommonAtom == nullptr ) { - // Lazily create common helper code and data. - _helperCacheAtom = new X86NonLazyPointerAtom(_file); - _binderAtom = new StubBinderAtom(_file); - _helperBinderAtom = new X86NonLazyPointerAtom(_file, *_binderAtom); - _helperCommonAtom = new X86StubHelperCommonAtom(_file, - *_helperCacheAtom, *_helperBinderAtom); - } - const DefinedAtom* helper = new X86StubHelperAtom(_file, - *_helperCommonAtom); - _stubHelperAtoms.push_back(helper); - const DefinedAtom* lp = new X86LazyPointerAtom(_file, *helper, target); - assert(lp->contentType() == DefinedAtom::typeLazyPointer); - _lazyPointers.push_back(lp); - const DefinedAtom* stub = new X86StubAtom(_file, *lp); - assert(stub->contentType() == DefinedAtom::typeStub); - _targetToStub[&target] = stub; - return stub; - } - - const DefinedAtom* makeStub_arm(const Atom& target) { - assert(0 && "stubs not yet implemented for arm"); - return nullptr; - } - - - void addStubAtoms(MutableFile &mergedFile) override { - // Exit early if no stubs needed. - if (_targetToStub.empty()) - return; - // Add all stubs to master file. - for (auto it : _targetToStub) { - mergedFile.addAtom(*it.second); - } - // Add helper code atoms. - mergedFile.addAtom(*_helperCommonAtom); - for (const DefinedAtom *lp : _stubHelperAtoms) { - mergedFile.addAtom(*lp); - } - // Add GOT slots used for lazy binding. - mergedFile.addAtom(*_helperBinderAtom); - mergedFile.addAtom(*_helperCacheAtom); - // Add all lazy pointers to master file. - for (const DefinedAtom *lp : _lazyPointers) { - mergedFile.addAtom(*lp); - } - // Add sharedlibrary atom - mergedFile.addAtom(*_binderAtom); - } - -private: - - class File : public SimpleFile { - public: - File(const MachOLinkingContext &context) : SimpleFile("MachO Stubs pass") {} - }; - - const MachOLinkingContext &_context; - mach_o::KindHandler &_kindHandler; - File _file; - llvm::DenseMap _targetToStub; - std::vector _lazyPointers; - std::vector _stubHelperAtoms; - const SharedLibraryAtom *_binderAtom; - const DefinedAtom* _helperCommonAtom; - const DefinedAtom* _helperCacheAtom; - const DefinedAtom* _helperBinderAtom; -}; - - -} // namespace mach_o -} // namespace lld - - -#endif // LLD_READER_WRITER_MACHO_STUBS_PASS_H diff --git a/lld/test/darwin/hello-world.objtxt b/lld/test/darwin/hello-world.objtxt deleted file mode 100644 index 7d13b4b..0000000 --- a/lld/test/darwin/hello-world.objtxt +++ /dev/null @@ -1,36 +0,0 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \ -# RUN: llvm-nm %t | FileCheck %s -# -# Test that hello-world can be linked into a mach-o executable -# - ---- !native -defined-atoms: - - name: _main - type: code - scope: global - content: [ 55, 48, 89, E5, 48, 8D, 3D, 00, - 00, 00, 00, E8, 00, 00, 00, 00, - 31, C0, 5D, C3 ] - references: - - offset: 7 - kind: ripRel32 - target: LC1 - - offset: 12 - kind: branch32 - target: _printf - - - ref-name: LC1 - type: c-string - merge: by-content - content: [ 68, 65, 6C, 6C, 6F, 0A, 00 ] - -shared-library-atoms: - - name: _printf - load-name: /usr/lib/libSystem.B.dylib - -... - -# CHECK: {{[0-9a-f]+}} T _main -# CHECK: U _printf -# CHECK: U dyld_stub_binder diff --git a/lld/test/darwin/native-and-mach-o.objtxt b/lld/test/darwin/native-and-mach-o.objtxt index f8e118d..20f2d0b 100644 --- a/lld/test/darwin/native-and-mach-o.objtxt +++ b/lld/test/darwin/native-and-mach-o.objtxt @@ -38,6 +38,27 @@ global-symbols: desc: [ ] value: 0 +--- !mach-o +arch: x86_64 +file-type: MH_DYLIB +flags: [ ] +install-name: /usr/lib/libSystem.B.dylib +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55 ] + +global-symbols: + - name: dyld_stub_binder + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + + ... # CHECK: {{[0-9a-f]+}} T _foo diff --git a/lld/test/mach-o/exe-offsets.yaml b/lld/test/mach-o/exe-offsets.yaml index 12f0815..f06ec7a 100644 --- a/lld/test/mach-o/exe-offsets.yaml +++ b/lld/test/mach-o/exe-offsets.yaml @@ -25,6 +25,28 @@ defined-atoms: type: data content: [ 01 ] +--- !mach-o +arch: x86_64 +file-type: MH_DYLIB +flags: [ ] +install-name: /usr/lib/libSystem.B.dylib +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55 ] + +global-symbols: + - name: dyld_stub_binder + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + + + # CHECK-LABEL: Section { # CHECK: Name: __text # CHECK: Segment: __TEXT diff --git a/lld/test/mach-o/exe-segment-overlap.yaml b/lld/test/mach-o/exe-segment-overlap.yaml index b0ed762..4d70b00 100644 --- a/lld/test/mach-o/exe-segment-overlap.yaml +++ b/lld/test/mach-o/exe-segment-overlap.yaml @@ -19,6 +19,26 @@ defined-atoms: section-name: __CUST/__custom +--- !mach-o +arch: x86_64 +file-type: MH_DYLIB +flags: [ ] +install-name: /usr/lib/libSystem.B.dylib +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55 ] + +global-symbols: + - name: dyld_stub_binder + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + # CHECK-LABEL: Section { # CHECK: Name: __text # CHECK: Segment: __TEXT diff --git a/lld/test/mach-o/hello-world-x86.yaml b/lld/test/mach-o/hello-world-x86.yaml index 8bb3909..f19e3ea 100644 --- a/lld/test/mach-o/hello-world-x86.yaml +++ b/lld/test/mach-o/hello-world-x86.yaml @@ -75,6 +75,11 @@ global-symbols: scope: [ N_EXT ] sect: 1 value: 0x0000000000000001 + - name: dyld_stub_binder + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000001 ... diff --git a/lld/test/mach-o/hello-world-x86_64.yaml b/lld/test/mach-o/hello-world-x86_64.yaml new file mode 100644 index 0000000..4ab4be9 --- /dev/null +++ b/lld/test/mach-o/hello-world-x86_64.yaml @@ -0,0 +1,144 @@ +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \ +# RUN: llvm-nm %t | FileCheck %s +# +# Test that x86_64 hello-world can be linked into a mach-o executable +# + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +has-UUID: false +OS: unknown +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x8B, 0x38, 0x48, 0x8D, + 0x35, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8, + 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x5D, 0xC3 ] + relocations: + - offset: 0x00000018 + type: X86_64_RELOC_BRANCH + length: 2 + pc-rel: true + extern: true + symbol: 5 + - offset: 0x00000011 + type: X86_64_RELOC_SIGNED + length: 2 + pc-rel: true + extern: true + symbol: 0 + - offset: 0x00000007 + type: X86_64_RELOC_GOT_LOAD + length: 2 + pc-rel: true + extern: true + symbol: 4 + - segment: __TEXT + section: __cstring + type: S_CSTRING_LITERALS + attributes: [ ] + address: 0x0000000000000020 + content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ] + - segment: __LD + section: __compact_unwind + type: S_REGULAR + attributes: [ ] + alignment: 3 + address: 0x0000000000000028 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - segment: __TEXT + section: __eh_frame + type: S_COALESCED + attributes: [ ] + alignment: 3 + address: 0x0000000000000048 + content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01, + 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] +local-symbols: + - name: L1 + type: N_SECT + sect: 2 + value: 0x0000000000000020 + - name: EH_frame0 + type: N_SECT + sect: 4 + value: 0x0000000000000048 +global-symbols: + - name: _main + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + - name: _main.eh + type: N_SECT + scope: [ N_EXT ] + sect: 4 + value: 0x0000000000000060 +undefined-symbols: + - name: ___stdoutp + type: N_UNDF + scope: [ N_EXT ] + value: 0x0000000000000000 + - name: _fprintf + type: N_UNDF + scope: [ N_EXT ] + value: 0x0000000000000000 + +--- !mach-o +arch: x86_64 +file-type: MH_DYLIB +flags: [ ] +install-name: /usr/lib/libSystem.B.dylib +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55 ] + +global-symbols: + - name: _fprintf + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + - name: dyld_stub_binder + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + - name: ___stdoutp + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + +... + +# CHECK: U ___stdoutp +# CHECK: U _fprintf +# CHECK: {{[0-9a-f]+}} T _main +# CHECK: U dyld_stub_binder diff --git a/lld/test/mach-o/write-final-sections.yaml b/lld/test/mach-o/write-final-sections.yaml index 2f8ddca..8701f40 100644 --- a/lld/test/mach-o/write-final-sections.yaml +++ b/lld/test/mach-o/write-final-sections.yaml @@ -151,3 +151,25 @@ defined-atoms: # CHECK: SectionData ( # CHECK-NEXT: 0000: 0E000000 00000000 # CHECK-NEXT: ) + + +--- !mach-o +arch: x86_64 +file-type: MH_DYLIB +flags: [ ] +install-name: /usr/lib/libSystem.B.dylib +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55 ] + +global-symbols: + - name: dyld_stub_binder + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 +