1 //===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H 11 #define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H 12 13 #include "Atoms.h" 14 #include "File.h" 15 #include "MachONormalizedFile.h" 16 #include "lld/Common/LLVM.h" 17 #include "lld/Core/Error.h" 18 #include "lld/Core/Reference.h" 19 #include "lld/Core/Simple.h" 20 #include "lld/ReaderWriter/MachOLinkingContext.h" 21 #include "llvm/ADT/Triple.h" 22 23 namespace lld { 24 namespace mach_o { 25 26 /// 27 /// The ArchHandler class handles all architecture specific aspects of 28 /// mach-o linking. 29 /// 30 class ArchHandler { 31 public: 32 virtual ~ArchHandler(); 33 34 /// There is no public interface to subclasses of ArchHandler, so this 35 /// is the only way to instantiate an ArchHandler. 36 static std::unique_ptr<ArchHandler> create(MachOLinkingContext::Arch arch); 37 38 /// Get (arch specific) kind strings used by Registry. 39 virtual const Registry::KindStrings *kindStrings() = 0; 40 41 /// Convert mach-o Arch to Reference::KindArch. 42 virtual Reference::KindArch kindArch() = 0; 43 44 /// Used by StubPass to update References to shared library functions 45 /// to be references to a stub. 46 virtual bool isCallSite(const Reference &) = 0; 47 48 /// Used by GOTPass to locate GOT References isGOTAccess(const Reference &,bool & canBypassGOT)49 virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) { 50 return false; 51 } 52 53 /// Used by TLVPass to locate TLV References. isTLVAccess(const Reference &)54 virtual bool isTLVAccess(const Reference &) const { return false; } 55 56 /// Used by the TLVPass to update TLV References. updateReferenceToTLV(const Reference *)57 virtual void updateReferenceToTLV(const Reference *) {} 58 59 /// Used by ShimPass to insert shims in branches that switch mode. 60 virtual bool isNonCallBranch(const Reference &) = 0; 61 62 /// Used by GOTPass to update GOT References updateReferenceToGOT(const Reference *,bool targetIsNowGOT)63 virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {} 64 65 /// Does this architecture make use of __unwind_info sections for exception 66 /// handling? If so, it will need a separate pass to create them. 67 virtual bool needsCompactUnwind() = 0; 68 69 /// Returns the kind of reference to use to synthesize a 32-bit image-offset 70 /// value, used in the __unwind_info section. 71 virtual Reference::KindValue imageOffsetKind() = 0; 72 73 /// Returns the kind of reference to use to synthesize a 32-bit image-offset 74 /// indirect value. Used for personality functions in the __unwind_info 75 /// section. 76 virtual Reference::KindValue imageOffsetKindIndirect() = 0; 77 78 /// Architecture specific compact unwind type that signals __eh_frame should 79 /// actually be used. 80 virtual uint32_t dwarfCompactUnwindType() = 0; 81 82 /// Reference from an __eh_frame CIE atom to its personality function it's 83 /// describing. Usually pointer-sized and PC-relative, but differs in whether 84 /// it needs to be in relocatable objects. 85 virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0; 86 87 /// Reference from an __eh_frame FDE to the CIE it's based on. 88 virtual Reference::KindValue unwindRefToCIEKind() = 0; 89 90 /// Reference from an __eh_frame FDE atom to the function it's 91 /// describing. Usually pointer-sized and PC-relative, but differs in whether 92 /// it needs to be in relocatable objects. 93 virtual Reference::KindValue unwindRefToFunctionKind() = 0; 94 95 /// Reference from an __unwind_info entry of dwarfCompactUnwindType to the 96 /// required __eh_frame entry. On current architectures, the low 24 bits 97 /// represent the offset of the function's FDE entry from the start of 98 /// __eh_frame. 99 virtual Reference::KindValue unwindRefToEhFrameKind() = 0; 100 101 /// Returns a pointer sized reference kind. On 64-bit targets this will 102 /// likely be something like pointer64, and pointer32 on 32-bit targets. 103 virtual Reference::KindValue pointerKind() = 0; 104 105 virtual const Atom *fdeTargetFunction(const DefinedAtom *fde); 106 107 /// Used by normalizedFromAtoms() to know where to generated rebasing and 108 /// binding info in final executables. 109 virtual bool isPointer(const Reference &) = 0; 110 111 /// Used by normalizedFromAtoms() to know where to generated lazy binding 112 /// info in final executables. 113 virtual bool isLazyPointer(const Reference &); 114 115 /// Reference from an __stub_helper entry to the required offset of the 116 /// lazy bind commands. 117 virtual Reference::KindValue lazyImmediateLocationKind() = 0; 118 119 /// Returns true if the specified relocation is paired to the next relocation. 120 virtual bool isPairedReloc(const normalized::Relocation &) = 0; 121 122 /// Prototype for a helper function. Given a sectionIndex and address, 123 /// finds the atom and offset with that atom of that address. 124 typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr, 125 const lld::Atom **, Reference::Addend *)> 126 FindAtomBySectionAndAddress; 127 128 /// Prototype for a helper function. Given a symbolIndex, finds the atom 129 /// representing that symbol. 130 typedef std::function<llvm::Error (uint32_t symbolIndex, 131 const lld::Atom **)> FindAtomBySymbolIndex; 132 133 /// Analyzes a relocation from a .o file and returns the info 134 /// (kind, target, addend) needed to instantiate a Reference. 135 /// Two helper functions are passed as parameters to find the target atom 136 /// given a symbol index or address. 137 virtual llvm::Error 138 getReferenceInfo(const normalized::Relocation &reloc, 139 const DefinedAtom *inAtom, 140 uint32_t offsetInAtom, 141 uint64_t fixupAddress, bool isBigEndian, 142 FindAtomBySectionAndAddress atomFromAddress, 143 FindAtomBySymbolIndex atomFromSymbolIndex, 144 Reference::KindValue *kind, 145 const lld::Atom **target, 146 Reference::Addend *addend) = 0; 147 148 /// Analyzes a pair of relocations from a .o file and returns the info 149 /// (kind, target, addend) needed to instantiate a Reference. 150 /// Two helper functions are passed as parameters to find the target atom 151 /// given a symbol index or address. 152 virtual llvm::Error 153 getPairReferenceInfo(const normalized::Relocation &reloc1, 154 const normalized::Relocation &reloc2, 155 const DefinedAtom *inAtom, 156 uint32_t offsetInAtom, 157 uint64_t fixupAddress, bool isBig, bool scatterable, 158 FindAtomBySectionAndAddress atomFromAddress, 159 FindAtomBySymbolIndex atomFromSymbolIndex, 160 Reference::KindValue *kind, 161 const lld::Atom **target, 162 Reference::Addend *addend) = 0; 163 164 /// Prototype for a helper function. Given an atom, finds the symbol table 165 /// index for it in the output file. 166 typedef std::function<uint32_t (const Atom &atom)> FindSymbolIndexForAtom; 167 168 /// Prototype for a helper function. Given an atom, finds the index 169 /// of the section that will contain the atom. 170 typedef std::function<uint32_t (const Atom &atom)> FindSectionIndexForAtom; 171 172 /// Prototype for a helper function. Given an atom, finds the address 173 /// assigned to it in the output file. 174 typedef std::function<uint64_t (const Atom &atom)> FindAddressForAtom; 175 176 /// Some architectures require local symbols on anonymous atoms. needsLocalSymbolInRelocatableFile(const DefinedAtom * atom)177 virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) { 178 return false; 179 } 180 181 /// Copy raw content then apply all fixup References on an Atom. 182 virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable, 183 FindAddressForAtom findAddress, 184 FindAddressForAtom findSectionAddress, 185 uint64_t imageBaseAddress, 186 llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0; 187 188 /// Used in -r mode to convert a Reference to a mach-o relocation. 189 virtual void appendSectionRelocations(const DefinedAtom &atom, 190 uint64_t atomSectionOffset, 191 const Reference &ref, 192 FindSymbolIndexForAtom, 193 FindSectionIndexForAtom, 194 FindAddressForAtom, 195 normalized::Relocations&) = 0; 196 197 /// Add arch-specific References. addAdditionalReferences(MachODefinedAtom & atom)198 virtual void addAdditionalReferences(MachODefinedAtom &atom) { } 199 200 // Add Reference for data-in-code marker. addDataInCodeReference(MachODefinedAtom & atom,uint32_t atomOff,uint16_t length,uint16_t kind)201 virtual void addDataInCodeReference(MachODefinedAtom &atom, uint32_t atomOff, 202 uint16_t length, uint16_t kind) { } 203 204 /// Returns true if the specificed Reference value marks the start or end 205 /// of a data-in-code range in an atom. isDataInCodeTransition(Reference::KindValue refKind)206 virtual bool isDataInCodeTransition(Reference::KindValue refKind) { 207 return false; 208 } 209 210 /// Returns the Reference value for a Reference that marks that start of 211 /// a data-in-code range. dataInCodeTransitionStart(const MachODefinedAtom & atom)212 virtual Reference::KindValue dataInCodeTransitionStart( 213 const MachODefinedAtom &atom) { 214 return 0; 215 } 216 217 /// Returns the Reference value for a Reference that marks that end of 218 /// a data-in-code range. dataInCodeTransitionEnd(const MachODefinedAtom & atom)219 virtual Reference::KindValue dataInCodeTransitionEnd( 220 const MachODefinedAtom &atom) { 221 return 0; 222 } 223 224 /// Only relevant for 32-bit arm archs. isThumbFunction(const DefinedAtom & atom)225 virtual bool isThumbFunction(const DefinedAtom &atom) { return false; } 226 227 /// Only relevant for 32-bit arm archs. createShim(MachOFile & file,bool thumbToArm,const DefinedAtom &)228 virtual const DefinedAtom *createShim(MachOFile &file, bool thumbToArm, 229 const DefinedAtom &) { 230 llvm_unreachable("shims only support on arm"); 231 } 232 233 /// Does a given unwind-cfi atom represent a CIE (as opposed to an FDE). 234 static bool isDwarfCIE(bool isBig, const DefinedAtom *atom); 235 236 struct ReferenceInfo { 237 Reference::KindArch arch; 238 uint16_t kind; 239 uint32_t offset; 240 int32_t addend; 241 }; 242 243 struct OptionalRefInfo { 244 bool used; 245 uint16_t kind; 246 uint32_t offset; 247 int32_t addend; 248 }; 249 250 /// Table of architecture specific information for creating stubs. 251 struct StubInfo { 252 const char* binderSymbolName; 253 ReferenceInfo lazyPointerReferenceToHelper; 254 ReferenceInfo lazyPointerReferenceToFinal; 255 ReferenceInfo nonLazyPointerReferenceToBinder; 256 uint8_t codeAlignment; 257 258 uint32_t stubSize; 259 uint8_t stubBytes[16]; 260 ReferenceInfo stubReferenceToLP; 261 OptionalRefInfo optStubReferenceToLP; 262 263 uint32_t stubHelperSize; 264 uint8_t stubHelperBytes[16]; 265 ReferenceInfo stubHelperReferenceToImm; 266 ReferenceInfo stubHelperReferenceToHelperCommon; 267 268 DefinedAtom::ContentType stubHelperImageCacheContentType; 269 270 uint32_t stubHelperCommonSize; 271 uint8_t stubHelperCommonAlignment; 272 uint8_t stubHelperCommonBytes[36]; 273 ReferenceInfo stubHelperCommonReferenceToCache; 274 OptionalRefInfo optStubHelperCommonReferenceToCache; 275 ReferenceInfo stubHelperCommonReferenceToBinder; 276 OptionalRefInfo optStubHelperCommonReferenceToBinder; 277 }; 278 279 virtual const StubInfo &stubInfo() = 0; 280 281 protected: 282 ArchHandler(); 283 284 static std::unique_ptr<mach_o::ArchHandler> create_x86_64(); 285 static std::unique_ptr<mach_o::ArchHandler> create_x86(); 286 static std::unique_ptr<mach_o::ArchHandler> create_arm(); 287 static std::unique_ptr<mach_o::ArchHandler> create_arm64(); 288 289 // Handy way to pack mach-o r_type and other bit fields into one 16-bit value. 290 typedef uint16_t RelocPattern; 291 enum { 292 rScattered = 0x8000, 293 rPcRel = 0x4000, 294 rExtern = 0x2000, 295 rLength1 = 0x0000, 296 rLength2 = 0x0100, 297 rLength4 = 0x0200, 298 rLength8 = 0x0300, 299 rLenArmLo = rLength1, 300 rLenArmHi = rLength2, 301 rLenThmbLo = rLength4, 302 rLenThmbHi = rLength8 303 }; 304 /// Extract RelocPattern from normalized mach-o relocation. 305 static RelocPattern relocPattern(const normalized::Relocation &reloc); 306 /// Create normalized Relocation initialized from pattern. 307 static normalized::Relocation relocFromPattern(RelocPattern pattern); 308 /// One liner to add a relocation. 309 static void appendReloc(normalized::Relocations &relocs, uint32_t offset, 310 uint32_t symbol, uint32_t value, 311 RelocPattern pattern); 312 313 314 static int16_t readS16(const uint8_t *addr, bool isBig); 315 static int32_t readS32(const uint8_t *addr, bool isBig); 316 static uint32_t readU32(const uint8_t *addr, bool isBig); 317 static int64_t readS64(const uint8_t *addr, bool isBig); 318 }; 319 320 } // namespace mach_o 321 } // namespace lld 322 323 #endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H 324