• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
10 #define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
11 
12 #include "lld/Core/LinkingContext.h"
13 #include "lld/Core/Reader.h"
14 #include "lld/Core/Writer.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/StringSet.h"
18 #include "llvm/BinaryFormat/MachO.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include <set>
21 
22 using llvm::MachO::HeaderFileType;
23 
24 namespace lld {
25 
26 namespace mach_o {
27 class ArchHandler;
28 class MachODylibFile;
29 class MachOFile;
30 class SectCreateFile;
31 }
32 
33 class MachOLinkingContext : public LinkingContext {
34 public:
35   MachOLinkingContext();
36   ~MachOLinkingContext() override;
37 
38   enum Arch {
39     arch_unknown,
40     arch_ppc,
41     arch_x86,
42     arch_x86_64,
43     arch_armv6,
44     arch_armv7,
45     arch_armv7s,
46     arch_arm64,
47   };
48 
49   enum class OS {
50     unknown,
51     macOSX,
52     iOS,
53     iOS_simulator
54   };
55 
56   enum class ExportMode {
57     globals,    // Default, all global symbols exported.
58     exported,   // -exported_symbol[s_list], only listed symbols exported.
59     unexported  // -unexported_symbol[s_list], no listed symbol exported.
60   };
61 
62   enum class DebugInfoMode {
63     addDebugMap,    // Default
64     noDebugMap      // -S option
65   };
66 
67   enum class UndefinedMode {
68     error,
69     warning,
70     suppress,
71     dynamicLookup
72   };
73 
74   enum ObjCConstraint {
75     objc_unknown = 0,
76     objc_supports_gc = 2,
77     objc_gc_only = 4,
78     // Image optimized by dyld = 8
79     // GC compaction = 16
80     objc_retainReleaseForSimulator = 32,
81     objc_retainRelease
82   };
83 
84   /// Initializes the context to sane default values given the specified output
85   /// file type, arch, os, and minimum os version.  This should be called before
86   /// other setXXX() methods.
87   void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion,
88                  bool exportDynamicSymbols);
89 
90   void addPasses(PassManager &pm) override;
91   bool validateImpl() override;
92   std::string demangle(StringRef symbolName) const override;
93 
94   void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
95 
96   /// Creates a new file which is owned by the context.  Returns a pointer to
97   /// the new file.
98   template <class T, class... Args>
99   typename std::enable_if<!std::is_array<T>::value, T *>::type
make_file(Args &&...args)100   make_file(Args &&... args) const {
101     auto file = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
102     auto *filePtr = file.get();
103     auto *ctx = const_cast<MachOLinkingContext *>(this);
104     ctx->getNodes().push_back(std::make_unique<FileNode>(std::move(file)));
105     return filePtr;
106   }
107 
108   uint32_t getCPUType() const;
109   uint32_t getCPUSubType() const;
110 
111   bool addEntryPointLoadCommand() const;
112   bool addUnixThreadLoadCommand() const;
113   bool outputTypeHasEntry() const;
114   bool is64Bit() const;
115 
pageZeroSize()116   virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
pageSize()117   virtual uint64_t pageSize() const { return _pageSize; }
118 
119   mach_o::ArchHandler &archHandler() const;
120 
outputMachOType()121   HeaderFileType outputMachOType() const { return _outputMachOType; }
122 
arch()123   Arch arch() const { return _arch; }
archName()124   StringRef archName() const { return nameFromArch(_arch); }
os()125   OS os() const { return _os; }
126 
exportMode()127   ExportMode exportMode() const { return _exportMode; }
setExportMode(ExportMode mode)128   void setExportMode(ExportMode mode) { _exportMode = mode; }
129   void addExportSymbol(StringRef sym);
exportRestrictMode()130   bool exportRestrictMode() const { return _exportMode != ExportMode::globals; }
131   bool exportSymbolNamed(StringRef sym) const;
132 
debugInfoMode()133   DebugInfoMode debugInfoMode() const { return _debugInfoMode; }
setDebugInfoMode(DebugInfoMode mode)134   void setDebugInfoMode(DebugInfoMode mode) {
135     _debugInfoMode = mode;
136   }
137 
138   void appendOrderedSymbol(StringRef symbol, StringRef filename);
139 
keepPrivateExterns()140   bool keepPrivateExterns() const { return _keepPrivateExterns; }
setKeepPrivateExterns(bool v)141   void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; }
demangleSymbols()142   bool demangleSymbols() const { return _demangle; }
setDemangleSymbols(bool d)143   void setDemangleSymbols(bool d) { _demangle = d; }
mergeObjCCategories()144   bool mergeObjCCategories() const { return _mergeObjCCategories; }
setMergeObjCCategories(bool v)145   void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; }
146   /// Create file at specified path which will contain a binary encoding
147   /// of all input and output file paths.
148   std::error_code createDependencyFile(StringRef path);
149   void addInputFileDependency(StringRef path) const;
150   void addInputFileNotFound(StringRef path) const;
151   void addOutputFileDependency(StringRef path) const;
152 
153   bool minOS(StringRef mac, StringRef iOS) const;
setDoNothing(bool value)154   void setDoNothing(bool value) { _doNothing = value; }
doNothing()155   bool doNothing() const { return _doNothing; }
printAtoms()156   bool printAtoms() const { return _printAtoms; }
testingFileUsage()157   bool testingFileUsage() const { return _testingFileUsage; }
searchDirs()158   const StringRefVector &searchDirs() const { return _searchDirs; }
frameworkDirs()159   const StringRefVector &frameworkDirs() const { return _frameworkDirs; }
160   void setSysLibRoots(const StringRefVector &paths);
sysLibRoots()161   const StringRefVector &sysLibRoots() const { return _syslibRoots; }
PIE()162   bool PIE() const { return _pie; }
setPIE(bool pie)163   void setPIE(bool pie) { _pie = pie; }
generateVersionLoadCommand()164   bool generateVersionLoadCommand() const {
165     return _generateVersionLoadCommand;
166   }
setGenerateVersionLoadCommand(bool v)167   void setGenerateVersionLoadCommand(bool v) {
168     _generateVersionLoadCommand = v;
169   }
170 
generateFunctionStartsLoadCommand()171   bool generateFunctionStartsLoadCommand() const {
172     return _generateFunctionStartsLoadCommand;
173   }
setGenerateFunctionStartsLoadCommand(bool v)174   void setGenerateFunctionStartsLoadCommand(bool v) {
175     _generateFunctionStartsLoadCommand = v;
176   }
177 
generateDataInCodeLoadCommand()178   bool generateDataInCodeLoadCommand() const {
179     return _generateDataInCodeLoadCommand;
180   }
setGenerateDataInCodeLoadCommand(bool v)181   void setGenerateDataInCodeLoadCommand(bool v) {
182     _generateDataInCodeLoadCommand = v;
183   }
184 
stackSize()185   uint64_t stackSize() const { return _stackSize; }
setStackSize(uint64_t stackSize)186   void setStackSize(uint64_t stackSize) { _stackSize = stackSize; }
187 
baseAddress()188   uint64_t baseAddress() const { return _baseAddress; }
setBaseAddress(uint64_t baseAddress)189   void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; }
190 
objcConstraint()191   ObjCConstraint objcConstraint() const { return _objcConstraint; }
192 
osMinVersion()193   uint32_t osMinVersion() const { return _osMinVersion; }
194 
sdkVersion()195   uint32_t sdkVersion() const { return _sdkVersion; }
setSdkVersion(uint64_t v)196   void setSdkVersion(uint64_t v) { _sdkVersion = v; }
197 
sourceVersion()198   uint64_t sourceVersion() const { return _sourceVersion; }
setSourceVersion(uint64_t v)199   void setSourceVersion(uint64_t v) { _sourceVersion = v; }
200 
swiftVersion()201   uint32_t swiftVersion() const { return _swiftVersion; }
202 
203   /// Checks whether a given path on the filesystem exists.
204   ///
205   /// When running in -test_file_usage mode, this method consults an
206   /// internally maintained list of files that exist (provided by -path_exists)
207   /// instead of the actual filesystem.
208   bool pathExists(StringRef path) const;
209 
210   /// Like pathExists() but only used on files - not directories.
211   bool fileExists(StringRef path) const;
212 
213   /// Adds any library search paths derived from the given base, possibly
214   /// modified by -syslibroots.
215   ///
216   /// The set of paths added consists of approximately all syslibroot-prepended
217   /// versions of libPath that exist, or the original libPath if there are none
218   /// for whatever reason. With various edge-cases for compatibility.
219   void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false);
220 
221   /// Determine whether -lFoo can be resolve within the given path, and
222   /// return the filename if so.
223   ///
224   /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in
225   /// that order, unless Foo ends in ".o", in which case only the exact file
226   /// matches (e.g. -lfoo.o would only find foo.o).
227   llvm::Optional<StringRef> searchDirForLibrary(StringRef path,
228                                                 StringRef libName) const;
229 
230   /// Iterates through all search path entries looking for libName (as
231   /// specified by -lFoo).
232   llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
233 
234   /// Add a framework search path.  Internally, this method may be prepended
235   /// the path with syslibroot.
236   void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
237 
238   /// Iterates through all framework directories looking for
239   /// Foo.framework/Foo (when fwName = "Foo").
240   llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const;
241 
242   /// The dylib's binary compatibility version, in the raw uint32 format.
243   ///
244   /// When building a dynamic library, this is the compatibility version that
245   /// gets embedded into the result. Other Mach-O binaries that link against
246   /// this library will store the compatibility version in its load command. At
247   /// runtime, the loader will verify that the binary is compatible with the
248   /// installed dynamic library.
compatibilityVersion()249   uint32_t compatibilityVersion() const { return _compatibilityVersion; }
250 
251   /// The dylib's current version, in the raw uint32 format.
252   ///
253   /// When building a dynamic library, this is the current version that gets
254   /// embedded into the result. Other Mach-O binaries that link against
255   /// this library will store the compatibility version in its load command.
currentVersion()256   uint32_t currentVersion() const { return _currentVersion; }
257 
258   /// The dylib's install name.
259   ///
260   /// Binaries that link against the dylib will embed this path into the dylib
261   /// load command. When loading the binaries at runtime, this is the location
262   /// on disk that the loader will look for the dylib.
installName()263   StringRef installName() const { return _installName; }
264 
265   /// Whether or not the dylib has side effects during initialization.
266   ///
267   /// Dylibs marked as being dead strippable provide the guarantee that loading
268   /// the dylib has no side effects, allowing the linker to strip out the dylib
269   /// when linking a binary that does not use any of its symbols.
deadStrippableDylib()270   bool deadStrippableDylib() const { return _deadStrippableDylib; }
271 
272   /// Whether or not to use flat namespace.
273   ///
274   /// MachO usually uses a two-level namespace, where each external symbol
275   /// referenced by the target is associated with the dylib that will provide
276   /// the symbol's definition at runtime. Using flat namespace overrides this
277   /// behavior: the linker searches all dylibs on the command line and all
278   /// dylibs those original dylibs depend on, but does not record which dylib
279   /// an external symbol came from. At runtime dyld again searches all images
280   /// and uses the first definition it finds. In addition, any undefines in
281   /// loaded flat_namespace dylibs must be resolvable at build time.
useFlatNamespace()282   bool useFlatNamespace() const { return _flatNamespace; }
283 
284   /// How to handle undefined symbols.
285   ///
286   /// Options are:
287   ///  * error: Report an error and terminate linking.
288   ///  * warning: Report a warning, but continue linking.
289   ///  * suppress: Ignore and continue linking.
290   ///  * dynamic_lookup: For use with -twolevel namespace: Records source dylibs
291   ///    for symbols that are defined in a linked dylib at static link time.
292   ///    Undefined symbols are handled by searching all loaded images at
293   ///    runtime.
undefinedMode()294   UndefinedMode undefinedMode() const { return _undefinedMode; }
295 
296   /// The path to the executable that will load the bundle at runtime.
297   ///
298   /// When building a Mach-O bundle, this executable will be examined if there
299   /// are undefined symbols after the main link phase. It is expected that this
300   /// binary will be loading the bundle at runtime and will provide the symbols
301   /// at that point.
bundleLoader()302   StringRef bundleLoader() const { return _bundleLoader; }
303 
setCompatibilityVersion(uint32_t vers)304   void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; }
setCurrentVersion(uint32_t vers)305   void setCurrentVersion(uint32_t vers) { _currentVersion = vers; }
setInstallName(StringRef name)306   void setInstallName(StringRef name) { _installName = name; }
setDeadStrippableDylib(bool deadStrippable)307   void setDeadStrippableDylib(bool deadStrippable) {
308     _deadStrippableDylib = deadStrippable;
309   }
setUseFlatNamespace(bool flatNamespace)310   void setUseFlatNamespace(bool flatNamespace) {
311     _flatNamespace = flatNamespace;
312   }
313 
setUndefinedMode(UndefinedMode undefinedMode)314   void setUndefinedMode(UndefinedMode undefinedMode) {
315     _undefinedMode = undefinedMode;
316   }
317 
setBundleLoader(StringRef loader)318   void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
319   void setPrintAtoms(bool value=true) { _printAtoms = value; }
320   void setTestingFileUsage(bool value = true) {
321     _testingFileUsage = value;
322   }
addExistingPathForDebug(StringRef path)323   void addExistingPathForDebug(StringRef path) {
324     _existingPaths.insert(path);
325   }
326 
327   void addRpath(StringRef rpath);
rpaths()328   const StringRefVector &rpaths() const { return _rpaths; }
329 
330   /// Add section alignment constraint on final layout.
331   void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align);
332 
333   /// Add a section based on a command-line sectcreate option.
334   void addSectCreateSection(StringRef seg, StringRef sect,
335                             std::unique_ptr<MemoryBuffer> content);
336 
337   /// Returns true if specified section had alignment constraints.
338   bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const;
339 
dyldPath()340   StringRef dyldPath() const { return "/usr/lib/dyld"; }
341 
342   /// Stub creation Pass should be run.
343   bool needsStubsPass() const;
344 
345   // GOT creation Pass should be run.
346   bool needsGOTPass() const;
347 
348   /// Pass to add TLV sections.
349   bool needsTLVPass() const;
350 
351   /// Pass to transform __compact_unwind into __unwind_info should be run.
352   bool needsCompactUnwindPass() const;
353 
354   /// Pass to add shims switching between thumb and arm mode.
355   bool needsShimPass() const;
356 
357   /// Pass to add objc image info and optimized objc data.
358   bool needsObjCPass() const;
359 
360   /// Magic symbol name stubs will need to help lazy bind.
361   StringRef binderSymbolName() const;
362 
363   /// Used to keep track of direct and indirect dylibs.
364   void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const;
365 
366   // Reads a file from disk to memory. Returns only a needed chunk
367   // if a fat binary.
368   ErrorOr<std::unique_ptr<MemoryBuffer>> getMemoryBuffer(StringRef path);
369 
370   /// Used to find indirect dylibs. Instantiates a MachODylibFile if one
371   /// has not already been made for the requested dylib.  Uses -L and -F
372   /// search paths to allow indirect dylibs to be overridden.
373   mach_o::MachODylibFile* findIndirectDylib(StringRef path);
374 
375   uint32_t dylibCurrentVersion(StringRef installName) const;
376 
377   uint32_t dylibCompatVersion(StringRef installName) const;
378 
allDylibs()379   ArrayRef<mach_o::MachODylibFile*> allDylibs() const {
380     return _allDylibs;
381   }
382 
383   /// Creates a copy (owned by this MachOLinkingContext) of a string.
copy(StringRef str)384   StringRef copy(StringRef str) { return str.copy(_allocator); }
385 
386   /// If the memoryBuffer is a fat file with a slice for the current arch,
387   /// this method will return the offset and size of that slice.
388   bool sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size);
389 
390   /// Returns if a command line option specified dylib is an upward link.
391   bool isUpwardDylib(StringRef installName) const;
392 
393   static bool isThinObjectFile(StringRef path, Arch &arch);
394   static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
395   static Arch archFromName(StringRef archName);
396   static StringRef nameFromArch(Arch arch);
397   static uint32_t cpuTypeFromArch(Arch arch);
398   static uint32_t cpuSubtypeFromArch(Arch arch);
399   static bool is64Bit(Arch arch);
400   static bool isHostEndian(Arch arch);
401   static bool isBigEndian(Arch arch);
402 
403   /// Construct 32-bit value from string "X.Y.Z" where
404   /// bits are xxxx.yy.zz.  Largest number is 65535.255.255
405   static bool parsePackedVersion(StringRef str, uint32_t &result);
406 
407   /// Construct 64-bit value from string "A.B.C.D.E" where
408   /// bits are aaaa.bb.cc.dd.ee.  Largest number is 16777215.1023.1023.1023.1023
409   static bool parsePackedVersion(StringRef str, uint64_t &result);
410 
411   void finalizeInputFiles() override;
412 
413   llvm::Error handleLoadedFile(File &file) override;
414 
415   bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
416                          bool &leftBeforeRight) const;
417 
418   /// Return the 'flat namespace' file. This is the file that supplies
419   /// atoms for otherwise undefined symbols when the -flat_namespace or
420   /// -undefined dynamic_lookup options are used.
flatNamespaceFile()421   File* flatNamespaceFile() const { return _flatNamespaceFile; }
422 
423 private:
424   Writer &writer() const override;
425   mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
426   struct ArchInfo {
427     StringRef                 archName;
428     MachOLinkingContext::Arch arch;
429     bool                      littleEndian;
430     uint32_t                  cputype;
431     uint32_t                  cpusubtype;
432   };
433 
434   struct SectionAlign {
435     StringRef segmentName;
436     StringRef sectionName;
437     uint16_t  align;
438   };
439 
440   struct OrderFileNode {
441     StringRef fileFilter;
442     unsigned  order;
443   };
444 
445   static bool findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
446                              const DefinedAtom *atom, unsigned &ordinal);
447 
448   static ArchInfo _s_archInfos[];
449 
450   std::set<StringRef> _existingPaths; // For testing only.
451   StringRefVector _searchDirs;
452   StringRefVector _syslibRoots;
453   StringRefVector _frameworkDirs;
454   HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE;
455   bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog
456   bool _doNothing = false;             // for -help and -v which just print info
457   bool _pie = false;
458   Arch _arch = arch_unknown;
459   OS _os = OS::macOSX;
460   uint32_t _osMinVersion = 0;
461   uint32_t _sdkVersion = 0;
462   uint64_t _sourceVersion = 0;
463   uint64_t _pageZeroSize = 0;
464   uint64_t _pageSize = 4096;
465   uint64_t _baseAddress = 0;
466   uint64_t _stackSize = 0;
467   uint32_t _compatibilityVersion = 0;
468   uint32_t _currentVersion = 0;
469   ObjCConstraint _objcConstraint = objc_unknown;
470   uint32_t _swiftVersion = 0;
471   StringRef _installName;
472   StringRefVector _rpaths;
473   bool _flatNamespace = false;
474   UndefinedMode _undefinedMode = UndefinedMode::error;
475   bool _deadStrippableDylib = false;
476   bool _printAtoms = false;
477   bool _testingFileUsage = false;
478   bool _keepPrivateExterns = false;
479   bool _demangle = false;
480   bool _mergeObjCCategories = true;
481   bool _generateVersionLoadCommand = false;
482   bool _generateFunctionStartsLoadCommand = false;
483   bool _generateDataInCodeLoadCommand = false;
484   StringRef _bundleLoader;
485   mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
486   mutable std::unique_ptr<Writer> _writer;
487   std::vector<SectionAlign> _sectAligns;
488   mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
489   mutable std::vector<mach_o::MachODylibFile*> _allDylibs;
490   mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
491   mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
492   mutable std::mutex _dylibsMutex;
493   ExportMode _exportMode = ExportMode::globals;
494   llvm::StringSet<> _exportedSymbols;
495   DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap;
496   std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
497   llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
498   unsigned _orderFileEntries = 0;
499   File *_flatNamespaceFile = nullptr;
500   mach_o::SectCreateFile *_sectCreateFile = nullptr;
501 };
502 
503 } // end namespace lld
504 
505 #endif // LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
506