//===- 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. // //===----------------------------------------------------------------------===// #ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H #define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H #include "Atoms.h" #include "File.h" #include "MachONormalizedFile.h" #include "lld/Common/LLVM.h" #include "lld/Core/Error.h" #include "lld/Core/Reference.h" #include "lld/Core/Simple.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/Triple.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 TLVPass to locate TLV References. virtual bool isTLVAccess(const Reference &) const { return false; } /// Used by the TLVPass to update TLV References. virtual void updateReferenceToTLV(const Reference *) {} /// Used by ShimPass to insert shims in branches that switch mode. virtual bool isNonCallBranch(const Reference &) = 0; /// Used by GOTPass to update GOT References virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {} /// Does this architecture make use of __unwind_info sections for exception /// handling? If so, it will need a separate pass to create them. virtual bool needsCompactUnwind() = 0; /// Returns the kind of reference to use to synthesize a 32-bit image-offset /// value, used in the __unwind_info section. virtual Reference::KindValue imageOffsetKind() = 0; /// Returns the kind of reference to use to synthesize a 32-bit image-offset /// indirect value. Used for personality functions in the __unwind_info /// section. virtual Reference::KindValue imageOffsetKindIndirect() = 0; /// Architecture specific compact unwind type that signals __eh_frame should /// actually be used. virtual uint32_t dwarfCompactUnwindType() = 0; /// Reference from an __eh_frame CIE atom to its personality function it's /// describing. Usually pointer-sized and PC-relative, but differs in whether /// it needs to be in relocatable objects. virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0; /// Reference from an __eh_frame FDE to the CIE it's based on. virtual Reference::KindValue unwindRefToCIEKind() = 0; /// Reference from an __eh_frame FDE atom to the function it's /// describing. Usually pointer-sized and PC-relative, but differs in whether /// it needs to be in relocatable objects. virtual Reference::KindValue unwindRefToFunctionKind() = 0; /// Reference from an __unwind_info entry of dwarfCompactUnwindType to the /// required __eh_frame entry. On current architectures, the low 24 bits /// represent the offset of the function's FDE entry from the start of /// __eh_frame. virtual Reference::KindValue unwindRefToEhFrameKind() = 0; /// Returns a pointer sized reference kind. On 64-bit targets this will /// likely be something like pointer64, and pointer32 on 32-bit targets. virtual Reference::KindValue pointerKind() = 0; virtual const Atom *fdeTargetFunction(const DefinedAtom *fde); /// 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 &); /// Reference from an __stub_helper entry to the required offset of the /// lazy bind commands. virtual Reference::KindValue lazyImmediateLocationKind() = 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 llvm::Error getReferenceInfo(const normalized::Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool isBigEndian, 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 llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool isBig, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) = 0; /// Prototype for a helper function. Given an atom, finds the symbol table /// index for it in the output file. typedef std::function FindSymbolIndexForAtom; /// Prototype for a helper function. Given an atom, finds the index /// of the section that will contain the atom. typedef std::function FindSectionIndexForAtom; /// Prototype for a helper function. Given an atom, finds the address /// assigned to it in the output file. typedef std::function FindAddressForAtom; /// Some architectures require local symbols on anonymous atoms. virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) { return false; } /// Copy raw content then apply all fixup References on an Atom. virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, llvm::MutableArrayRef atomContentBuffer) = 0; /// Used in -r mode to convert a Reference to a mach-o relocation. virtual void appendSectionRelocations(const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref, FindSymbolIndexForAtom, FindSectionIndexForAtom, FindAddressForAtom, normalized::Relocations&) = 0; /// Add arch-specific References. virtual void addAdditionalReferences(MachODefinedAtom &atom) { } // Add Reference for data-in-code marker. virtual void addDataInCodeReference(MachODefinedAtom &atom, uint32_t atomOff, uint16_t length, uint16_t kind) { } /// Returns true if the specificed Reference value marks the start or end /// of a data-in-code range in an atom. virtual bool isDataInCodeTransition(Reference::KindValue refKind) { return false; } /// Returns the Reference value for a Reference that marks that start of /// a data-in-code range. virtual Reference::KindValue dataInCodeTransitionStart( const MachODefinedAtom &atom) { return 0; } /// Returns the Reference value for a Reference that marks that end of /// a data-in-code range. virtual Reference::KindValue dataInCodeTransitionEnd( const MachODefinedAtom &atom) { return 0; } /// Only relevant for 32-bit arm archs. virtual bool isThumbFunction(const DefinedAtom &atom) { return false; } /// Only relevant for 32-bit arm archs. virtual const DefinedAtom *createShim(MachOFile &file, bool thumbToArm, const DefinedAtom &) { llvm_unreachable("shims only support on arm"); } /// Does a given unwind-cfi atom represent a CIE (as opposed to an FDE). static bool isDwarfCIE(bool isBig, const DefinedAtom *atom); struct ReferenceInfo { Reference::KindArch arch; uint16_t kind; uint32_t offset; int32_t addend; }; struct OptionalRefInfo { bool used; 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; OptionalRefInfo optStubReferenceToLP; uint32_t stubHelperSize; uint8_t stubHelperBytes[16]; ReferenceInfo stubHelperReferenceToImm; ReferenceInfo stubHelperReferenceToHelperCommon; DefinedAtom::ContentType stubHelperImageCacheContentType; uint32_t stubHelperCommonSize; uint8_t stubHelperCommonAlignment; uint8_t stubHelperCommonBytes[36]; ReferenceInfo stubHelperCommonReferenceToCache; OptionalRefInfo optStubHelperCommonReferenceToCache; ReferenceInfo stubHelperCommonReferenceToBinder; OptionalRefInfo optStubHelperCommonReferenceToBinder; }; 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(); static std::unique_ptr create_arm64(); // 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, rLenArmLo = rLength1, rLenArmHi = rLength2, rLenThmbLo = rLength4, rLenThmbHi = rLength8 }; /// Extract RelocPattern from normalized mach-o relocation. static RelocPattern relocPattern(const normalized::Relocation &reloc); /// Create normalized Relocation initialized from pattern. static normalized::Relocation relocFromPattern(RelocPattern pattern); /// One liner to add a relocation. static void appendReloc(normalized::Relocations &relocs, uint32_t offset, uint32_t symbol, uint32_t value, RelocPattern pattern); static int16_t readS16(const uint8_t *addr, bool isBig); static int32_t readS32(const uint8_t *addr, bool isBig); static uint32_t readU32(const uint8_t *addr, bool isBig); static int64_t readS64(const uint8_t *addr, bool isBig); }; } // namespace mach_o } // namespace lld #endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H