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