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