diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -195,12 +195,10 @@ endif() add_subdirectory(Common) -add_subdirectory(lib) add_subdirectory(tools/lld) if (LLVM_INCLUDE_TESTS) add_subdirectory(test) - add_subdirectory(unittests) endif() add_subdirectory(docs) diff --git a/lld/include/lld/Common/Driver.h b/lld/include/lld/Common/Driver.h --- a/lld/include/lld/Common/Driver.h +++ b/lld/include/lld/Common/Driver.h @@ -42,11 +42,6 @@ llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); } -namespace mach_o { -bool link(llvm::ArrayRef args, bool canExitEarly, - llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); -} - namespace macho { bool link(llvm::ArrayRef args, bool canExitEarly, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS); diff --git a/lld/include/lld/Core/Reference.h b/lld/include/lld/Core/Reference.h --- a/lld/include/lld/Core/Reference.h +++ b/lld/include/lld/Core/Reference.h @@ -42,9 +42,8 @@ public: /// Which universe defines the kindValue(). enum class KindNamespace { - all = 0, + all = 0, testing = 1, - mach_o = 2, }; KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; } diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h deleted file mode 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ /dev/null @@ -1,505 +0,0 @@ -//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H -#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H - -#include "lld/Core/LinkingContext.h" -#include "lld/Core/Reader.h" -#include "lld/Core/Writer.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/Support/ErrorHandling.h" -#include - -using llvm::MachO::HeaderFileType; - -namespace lld { - -namespace mach_o { -class ArchHandler; -class MachODylibFile; -class MachOFile; -class SectCreateFile; -} - -class MachOLinkingContext : public LinkingContext { -public: - MachOLinkingContext(); - ~MachOLinkingContext() override; - - enum Arch { - arch_unknown, - arch_ppc, - arch_x86, - arch_x86_64, - arch_armv6, - arch_armv7, - arch_armv7s, - arch_arm64, - }; - - enum class OS { - unknown, - macOSX, - iOS, - iOS_simulator - }; - - enum class ExportMode { - globals, // Default, all global symbols exported. - exported, // -exported_symbol[s_list], only listed symbols exported. - unexported // -unexported_symbol[s_list], no listed symbol exported. - }; - - enum class DebugInfoMode { - addDebugMap, // Default - noDebugMap // -S option - }; - - enum class UndefinedMode { - error, - warning, - suppress, - dynamicLookup - }; - - enum ObjCConstraint { - objc_unknown = 0, - objc_supports_gc = 2, - objc_gc_only = 4, - // Image optimized by dyld = 8 - // GC compaction = 16 - objc_retainReleaseForSimulator = 32, - objc_retainRelease - }; - - /// Initializes the context to sane default values given the specified output - /// file type, arch, os, and minimum os version. This should be called before - /// other setXXX() methods. - void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion, - bool exportDynamicSymbols); - - void addPasses(PassManager &pm) override; - bool validateImpl() override; - std::string demangle(StringRef symbolName) const override; - - void createImplicitFiles(std::vector> &) override; - - /// Creates a new file which is owned by the context. Returns a pointer to - /// the new file. - template - typename std::enable_if::value, T *>::type - make_file(Args &&... args) const { - auto file = std::unique_ptr(new T(std::forward(args)...)); - auto *filePtr = file.get(); - auto *ctx = const_cast(this); - ctx->getNodes().push_back(std::make_unique(std::move(file))); - return filePtr; - } - - uint32_t getCPUType() const; - uint32_t getCPUSubType() const; - - bool addEntryPointLoadCommand() const; - bool addUnixThreadLoadCommand() const; - bool outputTypeHasEntry() const; - bool is64Bit() const; - - virtual uint64_t pageZeroSize() const { return _pageZeroSize; } - virtual uint64_t pageSize() const { return _pageSize; } - - mach_o::ArchHandler &archHandler() const; - - HeaderFileType outputMachOType() const { return _outputMachOType; } - - Arch arch() const { return _arch; } - StringRef archName() const { return nameFromArch(_arch); } - OS os() const { return _os; } - - ExportMode exportMode() const { return _exportMode; } - void setExportMode(ExportMode mode) { _exportMode = mode; } - void addExportSymbol(StringRef sym); - bool exportRestrictMode() const { return _exportMode != ExportMode::globals; } - bool exportSymbolNamed(StringRef sym) const; - - DebugInfoMode debugInfoMode() const { return _debugInfoMode; } - void setDebugInfoMode(DebugInfoMode mode) { - _debugInfoMode = mode; - } - - void appendOrderedSymbol(StringRef symbol, StringRef filename); - - bool keepPrivateExterns() const { return _keepPrivateExterns; } - void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; } - bool demangleSymbols() const { return _demangle; } - void setDemangleSymbols(bool d) { _demangle = d; } - bool mergeObjCCategories() const { return _mergeObjCCategories; } - void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; } - /// Create file at specified path which will contain a binary encoding - /// of all input and output file paths. - std::error_code createDependencyFile(StringRef path); - void addInputFileDependency(StringRef path) const; - void addInputFileNotFound(StringRef path) const; - void addOutputFileDependency(StringRef path) const; - - bool minOS(StringRef mac, StringRef iOS) const; - void setDoNothing(bool value) { _doNothing = value; } - bool doNothing() const { return _doNothing; } - bool printAtoms() const { return _printAtoms; } - bool testingFileUsage() const { return _testingFileUsage; } - const StringRefVector &searchDirs() const { return _searchDirs; } - const StringRefVector &frameworkDirs() const { return _frameworkDirs; } - void setSysLibRoots(const StringRefVector &paths); - const StringRefVector &sysLibRoots() const { return _syslibRoots; } - bool PIE() const { return _pie; } - void setPIE(bool pie) { _pie = pie; } - bool generateVersionLoadCommand() const { - return _generateVersionLoadCommand; - } - void setGenerateVersionLoadCommand(bool v) { - _generateVersionLoadCommand = v; - } - - bool generateFunctionStartsLoadCommand() const { - return _generateFunctionStartsLoadCommand; - } - void setGenerateFunctionStartsLoadCommand(bool v) { - _generateFunctionStartsLoadCommand = v; - } - - bool generateDataInCodeLoadCommand() const { - return _generateDataInCodeLoadCommand; - } - void setGenerateDataInCodeLoadCommand(bool v) { - _generateDataInCodeLoadCommand = v; - } - - uint64_t stackSize() const { return _stackSize; } - void setStackSize(uint64_t stackSize) { _stackSize = stackSize; } - - uint64_t baseAddress() const { return _baseAddress; } - void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; } - - ObjCConstraint objcConstraint() const { return _objcConstraint; } - - uint32_t osMinVersion() const { return _osMinVersion; } - - uint32_t sdkVersion() const { return _sdkVersion; } - void setSdkVersion(uint64_t v) { _sdkVersion = v; } - - uint64_t sourceVersion() const { return _sourceVersion; } - void setSourceVersion(uint64_t v) { _sourceVersion = v; } - - uint32_t swiftVersion() const { return _swiftVersion; } - - /// Checks whether a given path on the filesystem exists. - /// - /// When running in -test_file_usage mode, this method consults an - /// internally maintained list of files that exist (provided by -path_exists) - /// instead of the actual filesystem. - bool pathExists(StringRef path) const; - - /// Like pathExists() but only used on files - not directories. - bool fileExists(StringRef path) const; - - /// Adds any library search paths derived from the given base, possibly - /// modified by -syslibroots. - /// - /// The set of paths added consists of approximately all syslibroot-prepended - /// versions of libPath that exist, or the original libPath if there are none - /// for whatever reason. With various edge-cases for compatibility. - void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false); - - /// Determine whether -lFoo can be resolve within the given path, and - /// return the filename if so. - /// - /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in - /// that order, unless Foo ends in ".o", in which case only the exact file - /// matches (e.g. -lfoo.o would only find foo.o). - llvm::Optional searchDirForLibrary(StringRef path, - StringRef libName) const; - - /// Iterates through all search path entries looking for libName (as - /// specified by -lFoo). - llvm::Optional searchLibrary(StringRef libName) const; - - /// Add a framework search path. Internally, this method may be prepended - /// the path with syslibroot. - void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false); - - /// Iterates through all framework directories looking for - /// Foo.framework/Foo (when fwName = "Foo"). - llvm::Optional findPathForFramework(StringRef fwName) const; - - /// The dylib's binary compatibility version, in the raw uint32 format. - /// - /// When building a dynamic library, this is the compatibility version that - /// gets embedded into the result. Other Mach-O binaries that link against - /// this library will store the compatibility version in its load command. At - /// runtime, the loader will verify that the binary is compatible with the - /// installed dynamic library. - uint32_t compatibilityVersion() const { return _compatibilityVersion; } - - /// The dylib's current version, in the raw uint32 format. - /// - /// When building a dynamic library, this is the current version that gets - /// embedded into the result. Other Mach-O binaries that link against - /// this library will store the compatibility version in its load command. - uint32_t currentVersion() const { return _currentVersion; } - - /// The dylib's install name. - /// - /// Binaries that link against the dylib will embed this path into the dylib - /// load command. When loading the binaries at runtime, this is the location - /// on disk that the loader will look for the dylib. - StringRef installName() const { return _installName; } - - /// Whether or not the dylib has side effects during initialization. - /// - /// Dylibs marked as being dead strippable provide the guarantee that loading - /// the dylib has no side effects, allowing the linker to strip out the dylib - /// when linking a binary that does not use any of its symbols. - bool deadStrippableDylib() const { return _deadStrippableDylib; } - - /// Whether or not to use flat namespace. - /// - /// MachO usually uses a two-level namespace, where each external symbol - /// referenced by the target is associated with the dylib that will provide - /// the symbol's definition at runtime. Using flat namespace overrides this - /// behavior: the linker searches all dylibs on the command line and all - /// dylibs those original dylibs depend on, but does not record which dylib - /// an external symbol came from. At runtime dyld again searches all images - /// and uses the first definition it finds. In addition, any undefines in - /// loaded flat_namespace dylibs must be resolvable at build time. - bool useFlatNamespace() const { return _flatNamespace; } - - /// How to handle undefined symbols. - /// - /// Options are: - /// * error: Report an error and terminate linking. - /// * warning: Report a warning, but continue linking. - /// * suppress: Ignore and continue linking. - /// * dynamic_lookup: For use with -twolevel namespace: Records source dylibs - /// for symbols that are defined in a linked dylib at static link time. - /// Undefined symbols are handled by searching all loaded images at - /// runtime. - UndefinedMode undefinedMode() const { return _undefinedMode; } - - /// The path to the executable that will load the bundle at runtime. - /// - /// When building a Mach-O bundle, this executable will be examined if there - /// are undefined symbols after the main link phase. It is expected that this - /// binary will be loading the bundle at runtime and will provide the symbols - /// at that point. - StringRef bundleLoader() const { return _bundleLoader; } - - void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; } - void setCurrentVersion(uint32_t vers) { _currentVersion = vers; } - void setInstallName(StringRef name) { _installName = name; } - void setDeadStrippableDylib(bool deadStrippable) { - _deadStrippableDylib = deadStrippable; - } - void setUseFlatNamespace(bool flatNamespace) { - _flatNamespace = flatNamespace; - } - - void setUndefinedMode(UndefinedMode undefinedMode) { - _undefinedMode = undefinedMode; - } - - void setBundleLoader(StringRef loader) { _bundleLoader = loader; } - void setPrintAtoms(bool value=true) { _printAtoms = value; } - void setTestingFileUsage(bool value = true) { - _testingFileUsage = value; - } - void addExistingPathForDebug(StringRef path) { - _existingPaths.insert(path); - } - - void addRpath(StringRef rpath); - const StringRefVector &rpaths() const { return _rpaths; } - - /// Add section alignment constraint on final layout. - void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align); - - /// Add a section based on a command-line sectcreate option. - void addSectCreateSection(StringRef seg, StringRef sect, - std::unique_ptr content); - - /// Returns true if specified section had alignment constraints. - bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const; - - StringRef dyldPath() const { return "/usr/lib/dyld"; } - - /// Stub creation Pass should be run. - bool needsStubsPass() const; - - // GOT creation Pass should be run. - bool needsGOTPass() const; - - /// Pass to add TLV sections. - bool needsTLVPass() const; - - /// Pass to transform __compact_unwind into __unwind_info should be run. - bool needsCompactUnwindPass() const; - - /// Pass to add shims switching between thumb and arm mode. - bool needsShimPass() const; - - /// Pass to add objc image info and optimized objc data. - bool needsObjCPass() const; - - /// Magic symbol name stubs will need to help lazy bind. - StringRef binderSymbolName() const; - - /// Used to keep track of direct and indirect dylibs. - void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const; - - // Reads a file from disk to memory. Returns only a needed chunk - // if a fat binary. - ErrorOr> getMemoryBuffer(StringRef path); - - /// Used to find indirect dylibs. Instantiates a MachODylibFile if one - /// has not already been made for the requested dylib. Uses -L and -F - /// search paths to allow indirect dylibs to be overridden. - mach_o::MachODylibFile* findIndirectDylib(StringRef path); - - uint32_t dylibCurrentVersion(StringRef installName) const; - - uint32_t dylibCompatVersion(StringRef installName) const; - - ArrayRef allDylibs() const { - return _allDylibs; - } - - /// Creates a copy (owned by this MachOLinkingContext) of a string. - StringRef copy(StringRef str) { return str.copy(_allocator); } - - /// If the memoryBuffer is a fat file with a slice for the current arch, - /// this method will return the offset and size of that slice. - bool sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size); - - /// Returns if a command line option specified dylib is an upward link. - bool isUpwardDylib(StringRef installName) const; - - static bool isThinObjectFile(StringRef path, Arch &arch); - static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype); - static Arch archFromName(StringRef archName); - static StringRef nameFromArch(Arch arch); - static uint32_t cpuTypeFromArch(Arch arch); - static uint32_t cpuSubtypeFromArch(Arch arch); - static bool is64Bit(Arch arch); - static bool isHostEndian(Arch arch); - static bool isBigEndian(Arch arch); - - /// Construct 32-bit value from string "X.Y.Z" where - /// bits are xxxx.yy.zz. Largest number is 65535.255.255 - static bool parsePackedVersion(StringRef str, uint32_t &result); - - /// Construct 64-bit value from string "A.B.C.D.E" where - /// bits are aaaa.bb.cc.dd.ee. Largest number is 16777215.1023.1023.1023.1023 - static bool parsePackedVersion(StringRef str, uint64_t &result); - - void finalizeInputFiles() override; - - llvm::Error handleLoadedFile(File &file) override; - - bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right, - bool &leftBeforeRight) const; - - /// Return the 'flat namespace' file. This is the file that supplies - /// atoms for otherwise undefined symbols when the -flat_namespace or - /// -undefined dynamic_lookup options are used. - File* flatNamespaceFile() const { return _flatNamespaceFile; } - -private: - Writer &writer() const override; - mach_o::MachODylibFile* loadIndirectDylib(StringRef path); - struct ArchInfo { - StringRef archName; - MachOLinkingContext::Arch arch; - bool littleEndian; - uint32_t cputype; - uint32_t cpusubtype; - }; - - struct SectionAlign { - StringRef segmentName; - StringRef sectionName; - uint16_t align; - }; - - struct OrderFileNode { - StringRef fileFilter; - unsigned order; - }; - - static bool findOrderOrdinal(const std::vector &nodes, - const DefinedAtom *atom, unsigned &ordinal); - - static ArchInfo _s_archInfos[]; - - std::set _existingPaths; // For testing only. - StringRefVector _searchDirs; - StringRefVector _syslibRoots; - StringRefVector _frameworkDirs; - HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE; - bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog - bool _doNothing = false; // for -help and -v which just print info - bool _pie = false; - Arch _arch = arch_unknown; - OS _os = OS::macOSX; - uint32_t _osMinVersion = 0; - uint32_t _sdkVersion = 0; - uint64_t _sourceVersion = 0; - uint64_t _pageZeroSize = 0; - uint64_t _pageSize = 4096; - uint64_t _baseAddress = 0; - uint64_t _stackSize = 0; - uint32_t _compatibilityVersion = 0; - uint32_t _currentVersion = 0; - ObjCConstraint _objcConstraint = objc_unknown; - uint32_t _swiftVersion = 0; - StringRef _installName; - StringRefVector _rpaths; - bool _flatNamespace = false; - UndefinedMode _undefinedMode = UndefinedMode::error; - bool _deadStrippableDylib = false; - bool _printAtoms = false; - bool _testingFileUsage = false; - bool _keepPrivateExterns = false; - bool _demangle = false; - bool _mergeObjCCategories = true; - bool _generateVersionLoadCommand = false; - bool _generateFunctionStartsLoadCommand = false; - bool _generateDataInCodeLoadCommand = false; - StringRef _bundleLoader; - mutable std::unique_ptr _archHandler; - mutable std::unique_ptr _writer; - std::vector _sectAligns; - mutable llvm::StringMap _pathToDylibMap; - mutable std::vector _allDylibs; - mutable std::set _upwardDylibs; - mutable std::vector> _indirectDylibs; - mutable std::mutex _dylibsMutex; - ExportMode _exportMode = ExportMode::globals; - llvm::StringSet<> _exportedSymbols; - DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap; - std::unique_ptr _dependencyInfo; - llvm::StringMap> _orderFiles; - unsigned _orderFileEntries = 0; - File *_flatNamespaceFile = nullptr; - mach_o::SectCreateFile *_sectCreateFile = nullptr; -}; - -} // end namespace lld - -#endif // LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H diff --git a/lld/include/lld/ReaderWriter/YamlContext.h b/lld/include/lld/ReaderWriter/YamlContext.h deleted file mode 100644 --- a/lld/include/lld/ReaderWriter/YamlContext.h +++ /dev/null @@ -1,42 +0,0 @@ -//===- lld/ReaderWriter/YamlContext.h - object used in YAML I/O context ---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_YAML_CONTEXT_H -#define LLD_READER_WRITER_YAML_CONTEXT_H - -#include "lld/Common/LLVM.h" -#include -#include -#include - -namespace lld { -class File; -class LinkingContext; -class Registry; -namespace mach_o { -namespace normalized { -struct NormalizedFile; -} -} - -using lld::mach_o::normalized::NormalizedFile; - -/// When YAML I/O is used in lld, the yaml context always holds a YamlContext -/// object. We need to support hetergenous yaml documents which each require -/// different context info. This struct supports all clients. -struct YamlContext { - const LinkingContext *_ctx = nullptr; - const Registry *_registry = nullptr; - File *_file = nullptr; - NormalizedFile *_normalizeMachOFile = nullptr; - StringRef _path; -}; - -} // end namespace lld - -#endif // LLD_READER_WRITER_YAML_CONTEXT_H diff --git a/lld/lib/CMakeLists.txt b/lld/lib/CMakeLists.txt deleted file mode 100644 --- a/lld/lib/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(Core) -add_subdirectory(Driver) -add_subdirectory(ReaderWriter) diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt deleted file mode 100644 --- a/lld/lib/Core/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_lld_library(lldCore - DefinedAtom.cpp - Error.cpp - File.cpp - LinkingContext.cpp - Reader.cpp - Resolver.cpp - SymbolTable.cpp - Writer.cpp - - ADDITIONAL_HEADER_DIRS - ${LLD_INCLUDE_DIR}/lld/Core - - LINK_COMPONENTS - BinaryFormat - MC - Support - - LINK_LIBS - ${LLVM_PTHREAD_LIB} - - DEPENDS - intrinsics_gen - ) diff --git a/lld/lib/Core/DefinedAtom.cpp b/lld/lib/Core/DefinedAtom.cpp deleted file mode 100644 --- a/lld/lib/Core/DefinedAtom.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/ErrorHandling.h" -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" - -namespace lld { - -DefinedAtom::ContentPermissions DefinedAtom::permissions() const { - // By default base permissions on content type. - return permissions(this->contentType()); -} - -// Utility function for deriving permissions from content type -DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { - switch (type) { - case typeCode: - case typeResolver: - case typeBranchIsland: - case typeBranchShim: - case typeStub: - case typeStubHelper: - case typeMachHeader: - return permR_X; - - case typeConstant: - case typeCString: - case typeUTF16String: - case typeCFI: - case typeLSDA: - case typeLiteral4: - case typeLiteral8: - case typeLiteral16: - case typeDTraceDOF: - case typeCompactUnwindInfo: - case typeProcessedUnwindInfo: - case typeObjCImageInfo: - case typeObjCMethodList: - return permR__; - - case typeData: - case typeDataFast: - case typeZeroFill: - case typeZeroFillFast: - case typeObjC1Class: - case typeLazyPointer: - case typeLazyDylibPointer: - case typeNonLazyPointer: - case typeThunkTLV: - return permRW_; - - case typeGOT: - case typeConstData: - case typeCFString: - case typeInitializerPtr: - case typeTerminatorPtr: - case typeCStringPtr: - case typeObjCClassPtr: - case typeObjC2CategoryList: - case typeInterposingTuples: - case typeTLVInitialData: - case typeTLVInitialZeroFill: - case typeTLVInitializerPtr: - return permRW_L; - - case typeUnknown: - case typeTempLTO: - case typeSectCreate: - case typeDSOHandle: - return permUnknown; - } - llvm_unreachable("unknown content type"); -} - -} // namespace diff --git a/lld/lib/Core/Error.cpp b/lld/lib/Core/Error.cpp deleted file mode 100644 --- a/lld/lib/Core/Error.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Error.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/ErrorHandling.h" -#include -#include -#include - -using namespace lld; - -namespace { -class _YamlReaderErrorCategory : public std::error_category { -public: - const char* name() const noexcept override { - return "lld.yaml.reader"; - } - - std::string message(int ev) const override { - switch (static_cast(ev)) { - case YamlReaderError::unknown_keyword: - return "Unknown keyword found in yaml file"; - case YamlReaderError::illegal_value: - return "Bad value found in yaml file"; - } - llvm_unreachable("An enumerator of YamlReaderError does not have a " - "message defined."); - } -}; -} // end anonymous namespace - -const std::error_category &lld::YamlReaderCategory() { - static _YamlReaderErrorCategory o; - return o; -} - -namespace lld { - -/// Temporary class to enable make_dynamic_error_code() until -/// llvm::ErrorOr<> is updated to work with error encapsulations -/// other than error_code. -class dynamic_error_category : public std::error_category { -public: - ~dynamic_error_category() override = default; - - const char *name() const noexcept override { - return "lld.dynamic_error"; - } - - std::string message(int ev) const override { - assert(ev >= 0); - assert(ev < (int)_messages.size()); - // The value is an index into the string vector. - return _messages[ev]; - } - - int add(std::string msg) { - std::lock_guard lock(_mutex); - // Value zero is always the success value. - if (_messages.empty()) - _messages.push_back("Success"); - _messages.push_back(msg); - // Return the index of the string just appended. - return _messages.size() - 1; - } - -private: - std::vector _messages; - std::recursive_mutex _mutex; -}; - -static dynamic_error_category categorySingleton; - -std::error_code make_dynamic_error_code(StringRef msg) { - return std::error_code(categorySingleton.add(std::string(msg)), - categorySingleton); -} - -char GenericError::ID = 0; - -GenericError::GenericError(Twine Msg) : Msg(Msg.str()) { } - -void GenericError::log(raw_ostream &OS) const { - OS << Msg; -} - -} // namespace lld diff --git a/lld/lib/Core/File.cpp b/lld/lib/Core/File.cpp deleted file mode 100644 --- a/lld/lib/Core/File.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===- Core/File.cpp - A Container of Atoms -------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/File.h" -#include - -namespace lld { - -File::~File() = default; - -File::AtomVector File::_noDefinedAtoms; -File::AtomVector File::_noUndefinedAtoms; -File::AtomVector File::_noSharedLibraryAtoms; -File::AtomVector File::_noAbsoluteAtoms; - -std::error_code File::parse() { - std::lock_guard lock(_parseMutex); - if (!_lastError.hasValue()) - _lastError = doParse(); - return _lastError.getValue(); -} - -} // end namespace lld diff --git a/lld/lib/Core/LinkingContext.cpp b/lld/lib/Core/LinkingContext.cpp deleted file mode 100644 --- a/lld/lib/Core/LinkingContext.cpp +++ /dev/null @@ -1,69 +0,0 @@ -//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/LinkingContext.h" -#include "lld/Core/File.h" -#include "lld/Core/Node.h" -#include "lld/Core/Simple.h" -#include "lld/Core/Writer.h" -#include - -namespace lld { - -LinkingContext::LinkingContext() = default; - -LinkingContext::~LinkingContext() = default; - -bool LinkingContext::validate() { - return validateImpl(); -} - -llvm::Error LinkingContext::writeFile(const File &linkedFile) const { - return this->writer().writeFile(linkedFile, _outputPath); -} - -std::unique_ptr LinkingContext::createEntrySymbolFile() const { - return createEntrySymbolFile(""); -} - -std::unique_ptr -LinkingContext::createEntrySymbolFile(StringRef filename) const { - if (entrySymbolName().empty()) - return nullptr; - std::unique_ptr entryFile(new SimpleFile(filename, - File::kindEntryObject)); - entryFile->addAtom( - *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); - return std::move(entryFile); -} - -std::unique_ptr LinkingContext::createUndefinedSymbolFile() const { - return createUndefinedSymbolFile(""); -} - -std::unique_ptr -LinkingContext::createUndefinedSymbolFile(StringRef filename) const { - if (_initialUndefinedSymbols.empty()) - return nullptr; - std::unique_ptr undefinedSymFile( - new SimpleFile(filename, File::kindUndefinedSymsObject)); - for (StringRef undefSym : _initialUndefinedSymbols) - undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( - *undefinedSymFile, undefSym))); - return std::move(undefinedSymFile); -} - -void LinkingContext::createInternalFiles( - std::vector> &result) const { - if (std::unique_ptr file = createEntrySymbolFile()) - result.push_back(std::move(file)); - if (std::unique_ptr file = createUndefinedSymbolFile()) - result.push_back(std::move(file)); -} - -} // end namespace lld diff --git a/lld/lib/Core/Reader.cpp b/lld/lib/Core/Reader.cpp deleted file mode 100644 --- a/lld/lib/Core/Reader.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//===- lib/Core/Reader.cpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Reader.h" -#include "lld/Core/File.h" -#include "lld/Core/Reference.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Magic.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include -#include - -using llvm::file_magic; -using llvm::identify_magic; - -namespace lld { - -YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default; - -void Registry::add(std::unique_ptr reader) { - _readers.push_back(std::move(reader)); -} - -void Registry::add(std::unique_ptr handler) { - _yamlHandlers.push_back(std::move(handler)); -} - -ErrorOr> -Registry::loadFile(std::unique_ptr mb) const { - // Get file magic. - StringRef content(mb->getBufferStart(), mb->getBufferSize()); - file_magic fileType = identify_magic(content); - - // Ask each registered reader if it can handle this file type or extension. - for (const std::unique_ptr &reader : _readers) { - if (!reader->canParse(fileType, mb->getMemBufferRef())) - continue; - return reader->loadFile(std::move(mb), *this); - } - - // No Reader could parse this file. - return make_error_code(llvm::errc::executable_format_error); -} - -static const Registry::KindStrings kindStrings[] = { - {Reference::kindLayoutAfter, "layout-after"}, - {Reference::kindAssociate, "associate"}, - LLD_KIND_STRING_END}; - -Registry::Registry() { - addKindTable(Reference::KindNamespace::all, Reference::KindArch::all, - kindStrings); -} - -bool Registry::handleTaggedDoc(llvm::yaml::IO &io, - const lld::File *&file) const { - for (const std::unique_ptr &h : _yamlHandlers) - if (h->handledDocTag(io, file)) - return true; - return false; -} - -void Registry::addKindTable(Reference::KindNamespace ns, - Reference::KindArch arch, - const KindStrings array[]) { - KindEntry entry = { ns, arch, array }; - _kindEntries.push_back(entry); -} - -bool Registry::referenceKindFromString(StringRef inputStr, - Reference::KindNamespace &ns, - Reference::KindArch &arch, - Reference::KindValue &value) const { - for (const KindEntry &entry : _kindEntries) { - for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) { - if (!inputStr.equals(pair->name)) - continue; - ns = entry.ns; - arch = entry.arch; - value = pair->value; - return true; - } - } - return false; -} - -bool Registry::referenceKindToString(Reference::KindNamespace ns, - Reference::KindArch arch, - Reference::KindValue value, - StringRef &str) const { - for (const KindEntry &entry : _kindEntries) { - if (entry.ns != ns) - continue; - if (entry.arch != arch) - continue; - for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) { - if (pair->value != value) - continue; - str = pair->name; - return true; - } - } - return false; -} - -} // end namespace lld diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp deleted file mode 100644 --- a/lld/lib/Core/Resolver.cpp +++ /dev/null @@ -1,496 +0,0 @@ -//===- Core/Resolver.cpp - Resolves Atom References -----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Resolver.h" -#include "lld/Common/LLVM.h" -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/Atom.h" -#include "lld/Core/File.h" -#include "lld/Core/Instrumentation.h" -#include "lld/Core/LinkingContext.h" -#include "lld/Core/SharedLibraryFile.h" -#include "lld/Core/SymbolTable.h" -#include "lld/Core/UndefinedAtom.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include - -namespace lld { - -llvm::Expected Resolver::handleFile(File &file) { - if (auto ec = _ctx.handleLoadedFile(file)) - return std::move(ec); - bool undefAdded = false; - for (auto &atom : file.defined().owning_ptrs()) - doDefinedAtom(std::move(atom)); - for (auto &atom : file.undefined().owning_ptrs()) { - if (doUndefinedAtom(std::move(atom))) - undefAdded = true; - } - for (auto &atom : file.sharedLibrary().owning_ptrs()) - doSharedLibraryAtom(std::move(atom)); - for (auto &atom : file.absolute().owning_ptrs()) - doAbsoluteAtom(std::move(atom)); - return undefAdded; -} - -llvm::Expected Resolver::forEachUndefines(File &file, - UndefCallback callback) { - size_t i = _undefineIndex[&file]; - bool undefAdded = false; - do { - for (; i < _undefines.size(); ++i) { - StringRef undefName = _undefines[i]; - if (undefName.empty()) - continue; - const Atom *atom = _symbolTable.findByName(undefName); - if (!isa(atom) || _symbolTable.isCoalescedAway(atom)) { - // The symbol was resolved by some other file. Cache the result. - _undefines[i] = ""; - continue; - } - auto undefAddedOrError = callback(undefName); - if (auto ec = undefAddedOrError.takeError()) - return std::move(ec); - undefAdded |= undefAddedOrError.get(); - } - } while (i < _undefines.size()); - _undefineIndex[&file] = i; - return undefAdded; -} - -llvm::Expected Resolver::handleArchiveFile(File &file) { - ArchiveLibraryFile *archiveFile = cast(&file); - return forEachUndefines(file, - [&](StringRef undefName) -> llvm::Expected { - if (File *member = archiveFile->find(undefName)) { - member->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - return handleFile(*member); - } - return false; - }); -} - -llvm::Error Resolver::handleSharedLibrary(File &file) { - // Add all the atoms from the shared library - SharedLibraryFile *sharedLibrary = cast(&file); - auto undefAddedOrError = handleFile(*sharedLibrary); - if (auto ec = undefAddedOrError.takeError()) - return ec; - undefAddedOrError = - forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected { - auto atom = sharedLibrary->exports(undefName); - if (atom.get()) - doSharedLibraryAtom(std::move(atom)); - return false; - }); - - if (auto ec = undefAddedOrError.takeError()) - return ec; - return llvm::Error::success(); -} - -bool Resolver::doUndefinedAtom(OwningAtomPtr atom) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << " UndefinedAtom: " - << llvm::format("0x%09lX", atom.get()) - << ", name=" << atom.get()->name() << "\n"); - - // tell symbol table - bool newUndefAdded = _symbolTable.add(*atom.get()); - if (newUndefAdded) - _undefines.push_back(atom.get()->name()); - - // add to list of known atoms - _atoms.push_back(OwningAtomPtr(atom.release())); - - return newUndefAdded; -} - -// Called on each atom when a file is added. Returns true if a given -// atom is added to the symbol table. -void Resolver::doDefinedAtom(OwningAtomPtr atom) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << " DefinedAtom: " - << llvm::format("0x%09lX", atom.get()) - << ", file=#" - << atom.get()->file().ordinal() - << ", atom=#" - << atom.get()->ordinal() - << ", name=" - << atom.get()->name() - << ", type=" - << atom.get()->contentType() - << "\n"); - - // An atom that should never be dead-stripped is a dead-strip root. - if (_ctx.deadStrip() && - atom.get()->deadStrip() == DefinedAtom::deadStripNever) { - _deadStripRoots.insert(atom.get()); - } - - // add to list of known atoms - _symbolTable.add(*atom.get()); - _atoms.push_back(OwningAtomPtr(atom.release())); -} - -void Resolver::doSharedLibraryAtom(OwningAtomPtr atom) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << " SharedLibraryAtom: " - << llvm::format("0x%09lX", atom.get()) - << ", name=" - << atom.get()->name() - << "\n"); - - // tell symbol table - _symbolTable.add(*atom.get()); - - // add to list of known atoms - _atoms.push_back(OwningAtomPtr(atom.release())); -} - -void Resolver::doAbsoluteAtom(OwningAtomPtr atom) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << " AbsoluteAtom: " - << llvm::format("0x%09lX", atom.get()) - << ", name=" - << atom.get()->name() - << "\n"); - - // tell symbol table - if (atom.get()->scope() != Atom::scopeTranslationUnit) - _symbolTable.add(*atom.get()); - - // add to list of known atoms - _atoms.push_back(OwningAtomPtr(atom.release())); -} - -// Returns true if at least one of N previous files has created an -// undefined symbol. -bool Resolver::undefinesAdded(int begin, int end) { - std::vector> &inputs = _ctx.getNodes(); - for (int i = begin; i < end; ++i) - if (FileNode *node = dyn_cast(inputs[i].get())) - if (_newUndefinesAdded[node->getFile()]) - return true; - return false; -} - -File *Resolver::getFile(int &index) { - std::vector> &inputs = _ctx.getNodes(); - if ((size_t)index >= inputs.size()) - return nullptr; - if (GroupEnd *group = dyn_cast(inputs[index].get())) { - // We are at the end of the current group. If one or more new - // undefined atom has been added in the last groupSize files, we - // reiterate over the files. - int size = group->getSize(); - if (undefinesAdded(index - size, index)) { - index -= size; - return getFile(index); - } - ++index; - return getFile(index); - } - return cast(inputs[index++].get())->getFile(); -} - -// Keep adding atoms until _ctx.getNextFile() returns an error. This -// function is where undefined atoms are resolved. -bool Resolver::resolveUndefines() { - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "******** Resolving undefines:\n"); - ScopedTask task(getDefaultDomain(), "resolveUndefines"); - int index = 0; - std::set seen; - for (;;) { - bool undefAdded = false; - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "Loading file #" << index << "\n"); - File *file = getFile(index); - if (!file) - return true; - if (std::error_code ec = file->parse()) { - llvm::errs() << "Cannot open " + file->path() << ": " << ec.message() - << "\n"; - return false; - } - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "Loaded file: " << file->path() << "\n"); - switch (file->kind()) { - case File::kindErrorObject: - case File::kindNormalizedObject: - case File::kindMachObject: - case File::kindCEntryObject: - case File::kindHeaderObject: - case File::kindEntryObject: - case File::kindUndefinedSymsObject: - case File::kindStubHelperObject: - case File::kindResolverMergedObject: - case File::kindSectCreateObject: { - // The same file may be visited more than once if the file is - // in --start-group and --end-group. Only library files should - // be processed more than once. - if (seen.count(file)) - break; - seen.insert(file); - assert(!file->hasOrdinal()); - file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - auto undefAddedOrError = handleFile(*file); - if (auto EC = undefAddedOrError.takeError()) { - // FIXME: This should be passed to logAllUnhandledErrors but it needs - // to be passed a Twine instead of a string. - llvm::errs() << "Error in " + file->path() << ": "; - logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); - return false; - } - undefAdded = undefAddedOrError.get(); - break; - } - case File::kindArchiveLibrary: { - if (!file->hasOrdinal()) - file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - auto undefAddedOrError = handleArchiveFile(*file); - if (auto EC = undefAddedOrError.takeError()) { - // FIXME: This should be passed to logAllUnhandledErrors but it needs - // to be passed a Twine instead of a string. - llvm::errs() << "Error in " + file->path() << ": "; - logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); - return false; - } - undefAdded = undefAddedOrError.get(); - break; - } - case File::kindSharedLibrary: - if (!file->hasOrdinal()) - file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - if (auto EC = handleSharedLibrary(*file)) { - // FIXME: This should be passed to logAllUnhandledErrors but it needs - // to be passed a Twine instead of a string. - llvm::errs() << "Error in " + file->path() << ": "; - logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); - return false; - } - break; - } - _newUndefinesAdded[file] = undefAdded; - } -} - -// switch all references to undefined or coalesced away atoms -// to the new defined atom -void Resolver::updateReferences() { - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "******** Updating references:\n"); - ScopedTask task(getDefaultDomain(), "updateReferences"); - for (const OwningAtomPtr &atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast(atom.get())) { - for (const Reference *ref : *defAtom) { - // A reference of type kindAssociate shouldn't be updated. - // Instead, an atom having such reference will be removed - // if the target atom is coalesced away, so that they will - // go away as a group. - if (ref->kindNamespace() == lld::Reference::KindNamespace::all && - ref->kindValue() == lld::Reference::kindAssociate) { - if (_symbolTable.isCoalescedAway(atom.get())) - _deadAtoms.insert(ref->target()); - continue; - } - const Atom *newTarget = _symbolTable.replacement(ref->target()); - const_cast(ref)->setTarget(newTarget); - } - } - } -} - -// For dead code stripping, recursively mark atoms "live" -void Resolver::markLive(const Atom *atom) { - // Mark the atom is live. If it's already marked live, then stop recursion. - auto exists = _liveAtoms.insert(atom); - if (!exists.second) - return; - - // Mark all atoms it references as live - if (const DefinedAtom *defAtom = dyn_cast(atom)) { - for (const Reference *ref : *defAtom) - markLive(ref->target()); - for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) { - const Atom *target = p.second; - markLive(target); - } - } -} - -static bool isBackref(const Reference *ref) { - if (ref->kindNamespace() != lld::Reference::KindNamespace::all) - return false; - return (ref->kindValue() == lld::Reference::kindLayoutAfter); -} - -// remove all atoms not actually used -void Resolver::deadStripOptimize() { - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "******** Dead stripping unused atoms:\n"); - ScopedTask task(getDefaultDomain(), "deadStripOptimize"); - // only do this optimization with -dead_strip - if (!_ctx.deadStrip()) - return; - - // Some type of references prevent referring atoms to be dead-striped. - // Make a reverse map of such references before traversing the graph. - // While traversing the list of atoms, mark AbsoluteAtoms as live - // in order to avoid reclaim. - for (const OwningAtomPtr &atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast(atom.get())) - for (const Reference *ref : *defAtom) - if (isBackref(ref)) - _reverseRef.insert(std::make_pair(ref->target(), atom.get())); - if (const AbsoluteAtom *absAtom = dyn_cast(atom.get())) - markLive(absAtom); - } - - // By default, shared libraries are built with all globals as dead strip roots - if (_ctx.globalsAreDeadStripRoots()) - for (const OwningAtomPtr &atom : _atoms) - if (const DefinedAtom *defAtom = dyn_cast(atom.get())) - if (defAtom->scope() == DefinedAtom::scopeGlobal) - _deadStripRoots.insert(defAtom); - - // Or, use list of names that are dead strip roots. - for (const StringRef &name : _ctx.deadStripRoots()) { - const Atom *symAtom = _symbolTable.findByName(name); - assert(symAtom); - _deadStripRoots.insert(symAtom); - } - - // mark all roots as live, and recursively all atoms they reference - for (const Atom *dsrAtom : _deadStripRoots) - markLive(dsrAtom); - - // now remove all non-live atoms from _atoms - llvm::erase_if(_atoms, [&](OwningAtomPtr &a) { - return _liveAtoms.count(a.get()) == 0; - }); -} - -// error out if some undefines remain -bool Resolver::checkUndefines() { - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "******** Checking for undefines:\n"); - - // build vector of remaining undefined symbols - std::vector undefinedAtoms = _symbolTable.undefines(); - if (_ctx.deadStrip()) { - // When dead code stripping, we don't care if dead atoms are undefined. - llvm::erase_if(undefinedAtoms, - [&](const Atom *a) { return _liveAtoms.count(a) == 0; }); - } - - if (undefinedAtoms.empty()) - return false; - - // Warn about unresolved symbols. - bool foundUndefines = false; - for (const UndefinedAtom *undef : undefinedAtoms) { - // Skip over a weak symbol. - if (undef->canBeNull() != UndefinedAtom::canBeNullNever) - continue; - - // If this is a library and undefined symbols are allowed on the - // target platform, skip over it. - if (isa(undef->file()) && _ctx.allowShlibUndefines()) - continue; - - // If the undefine is coalesced away, skip over it. - if (_symbolTable.isCoalescedAway(undef)) - continue; - - // Seems like this symbol is undefined. Warn that. - foundUndefines = true; - if (_ctx.printRemainingUndefines()) { - llvm::errs() << "Undefined symbol: " << undef->file().path() << ": " - << _ctx.demangle(undef->name()) << "\n"; - } - } - if (!foundUndefines) - return false; - if (_ctx.printRemainingUndefines()) - llvm::errs() << "symbol(s) not found\n"; - return true; -} - -// Remove from _atoms all coalesced away atoms. -void Resolver::removeCoalescedAwayAtoms() { - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "******** Removing coalesced away atoms:\n"); - ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); - llvm::erase_if(_atoms, [&](OwningAtomPtr &a) { - return _symbolTable.isCoalescedAway(a.get()) || _deadAtoms.count(a.get()); - }); -} - -bool Resolver::resolve() { - DEBUG_WITH_TYPE("resolver", - llvm::dbgs() << "******** Resolving atom references:\n"); - if (!resolveUndefines()) - return false; - updateReferences(); - deadStripOptimize(); - if (checkUndefines()) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Found undefines... "); - if (!_ctx.allowRemainingUndefines()) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we don't allow\n"); - return false; - } - DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we are ok with\n"); - } - removeCoalescedAwayAtoms(); - _result->addAtoms(_atoms); - DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Finished resolver\n"); - return true; -} - -void Resolver::MergedFile::addAtoms( - llvm::MutableArrayRef> all) { - ScopedTask task(getDefaultDomain(), "addAtoms"); - DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); - - for (OwningAtomPtr &atom : all) { -#ifndef NDEBUG - if (auto *definedAtom = dyn_cast(atom.get())) { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", definedAtom) - << ", file=#" - << definedAtom->file().ordinal() - << ", atom=#" - << definedAtom->ordinal() - << ", name=" - << definedAtom->name() - << ", type=" - << definedAtom->contentType() - << "\n"); - } else { - DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom.get()) - << ", name=" - << atom.get()->name() - << "\n"); - } -#endif - addAtom(*atom.release()); - } -} - -} // namespace lld diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp deleted file mode 100644 --- a/lld/lib/Core/SymbolTable.cpp +++ /dev/null @@ -1,284 +0,0 @@ -//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/SymbolTable.h" -#include "lld/Common/LLVM.h" -#include "lld/Core/AbsoluteAtom.h" -#include "lld/Core/Atom.h" -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/LinkingContext.h" -#include "lld/Core/Resolver.h" -#include "lld/Core/SharedLibraryAtom.h" -#include "lld/Core/UndefinedAtom.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/Hashing.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include - -namespace lld { -bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); } - -bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); } - -bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); } - -bool SymbolTable::add(const DefinedAtom &atom) { - if (!atom.name().empty() && - atom.scope() != DefinedAtom::scopeTranslationUnit) { - // Named atoms cannot be merged by content. - assert(atom.merge() != DefinedAtom::mergeByContent); - // Track named atoms that are not scoped to file (static). - return addByName(atom); - } - if (atom.merge() == DefinedAtom::mergeByContent) { - // Named atoms cannot be merged by content. - assert(atom.name().empty()); - // Currently only read-only constants can be merged. - if (atom.permissions() == DefinedAtom::permR__) - return addByContent(atom); - // TODO: support mergeByContent of data atoms by comparing content & fixups. - } - return false; -} - -enum NameCollisionResolution { - NCR_First, - NCR_Second, - NCR_DupDef, - NCR_DupUndef, - NCR_DupShLib, - NCR_Error -}; - -static NameCollisionResolution cases[4][4] = { - //regular absolute undef sharedLib - { - // first is regular - NCR_DupDef, NCR_Error, NCR_First, NCR_First - }, - { - // first is absolute - NCR_Error, NCR_Error, NCR_First, NCR_First - }, - { - // first is undef - NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second - }, - { - // first is sharedLib - NCR_Second, NCR_Second, NCR_First, NCR_DupShLib - } -}; - -static NameCollisionResolution collide(Atom::Definition first, - Atom::Definition second) { - return cases[first][second]; -} - -enum MergeResolution { - MCR_First, - MCR_Second, - MCR_Largest, - MCR_SameSize, - MCR_Error -}; - -static MergeResolution mergeCases[][6] = { - // no tentative weak weakAddress sameNameAndSize largest - {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no - {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative - {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak - {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress - {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize - {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest -}; - -static MergeResolution mergeSelect(DefinedAtom::Merge first, - DefinedAtom::Merge second) { - assert(first != DefinedAtom::mergeByContent); - assert(second != DefinedAtom::mergeByContent); - return mergeCases[first][second]; -} - -bool SymbolTable::addByName(const Atom &newAtom) { - StringRef name = newAtom.name(); - assert(!name.empty()); - const Atom *existing = findByName(name); - if (existing == nullptr) { - // Name is not in symbol table yet, add it associate with this atom. - _nameTable[name] = &newAtom; - return true; - } - - // Do nothing if the same object is added more than once. - if (existing == &newAtom) - return false; - - // Name is already in symbol table and associated with another atom. - bool useNew = true; - switch (collide(existing->definition(), newAtom.definition())) { - case NCR_First: - useNew = false; - break; - case NCR_Second: - useNew = true; - break; - case NCR_DupDef: { - const auto *existingDef = cast(existing); - const auto *newDef = cast(&newAtom); - switch (mergeSelect(existingDef->merge(), newDef->merge())) { - case MCR_First: - useNew = false; - break; - case MCR_Second: - useNew = true; - break; - case MCR_Largest: { - uint64_t existingSize = existingDef->sectionSize(); - uint64_t newSize = newDef->sectionSize(); - useNew = (newSize >= existingSize); - break; - } - case MCR_SameSize: { - uint64_t existingSize = existingDef->sectionSize(); - uint64_t newSize = newDef->sectionSize(); - if (existingSize == newSize) { - useNew = true; - break; - } - llvm::errs() << "Size mismatch: " << existing->name() << " (" - << existingSize << ") " << newAtom.name() << " (" << newSize - << ")\n"; - LLVM_FALLTHROUGH; - } - case MCR_Error: - llvm::errs() << "Duplicate symbols: " << existing->name() << ":" - << existing->file().path() << " and " << newAtom.name() - << ":" << newAtom.file().path() << "\n"; - llvm::report_fatal_error("duplicate symbol error"); - break; - } - break; - } - case NCR_DupUndef: { - const UndefinedAtom* existingUndef = cast(existing); - const UndefinedAtom* newUndef = cast(&newAtom); - - bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); - if (sameCanBeNull) - useNew = false; - else - useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); - break; - } - case NCR_DupShLib: { - useNew = false; - break; - } - case NCR_Error: - llvm::errs() << "SymbolTable: error while merging " << name << "\n"; - llvm::report_fatal_error("duplicate symbol error"); - break; - } - - if (useNew) { - // Update name table to use new atom. - _nameTable[name] = &newAtom; - // Add existing atom to replacement table. - _replacedAtoms[existing] = &newAtom; - } else { - // New atom is not being used. Add it to replacement table. - _replacedAtoms[&newAtom] = existing; - } - return false; -} - -unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) { - auto content = atom->rawContent(); - return llvm::hash_combine(atom->size(), - atom->contentType(), - llvm::hash_combine_range(content.begin(), - content.end())); -} - -bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l, - const DefinedAtom * const r) { - if (l == r) - return true; - if (l == getEmptyKey() || r == getEmptyKey()) - return false; - if (l == getTombstoneKey() || r == getTombstoneKey()) - return false; - if (l->contentType() != r->contentType()) - return false; - if (l->size() != r->size()) - return false; - if (l->sectionChoice() != r->sectionChoice()) - return false; - if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) { - if (!l->customSectionName().equals(r->customSectionName())) - return false; - } - ArrayRef lc = l->rawContent(); - ArrayRef rc = r->rawContent(); - return memcmp(lc.data(), rc.data(), lc.size()) == 0; -} - -bool SymbolTable::addByContent(const DefinedAtom &newAtom) { - AtomContentSet::iterator pos = _contentTable.find(&newAtom); - if (pos == _contentTable.end()) { - _contentTable.insert(&newAtom); - return true; - } - const Atom* existing = *pos; - // New atom is not being used. Add it to replacement table. - _replacedAtoms[&newAtom] = existing; - return false; -} - -const Atom *SymbolTable::findByName(StringRef sym) { - NameToAtom::iterator pos = _nameTable.find(sym); - if (pos == _nameTable.end()) - return nullptr; - return pos->second; -} - -const Atom *SymbolTable::replacement(const Atom *atom) { - // Find the replacement for a given atom. Atoms in _replacedAtoms - // may be chained, so find the last one. - for (;;) { - AtomToAtom::iterator pos = _replacedAtoms.find(atom); - if (pos == _replacedAtoms.end()) - return atom; - atom = pos->second; - } -} - -bool SymbolTable::isCoalescedAway(const Atom *atom) { - return _replacedAtoms.count(atom) > 0; -} - -std::vector SymbolTable::undefines() { - std::vector ret; - for (auto it : _nameTable) { - const Atom *atom = it.second; - assert(atom != nullptr); - if (const auto *undef = dyn_cast(atom)) - if (_replacedAtoms.count(undef) == 0) - ret.push_back(undef); - } - return ret; -} - -} // namespace lld diff --git a/lld/lib/Core/Writer.cpp b/lld/lib/Core/Writer.cpp deleted file mode 100644 --- a/lld/lib/Core/Writer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -//===- lib/Core/Writer.cpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Writer.h" - -namespace lld { - -Writer::Writer() = default; - -Writer::~Writer() = default; - -} // end namespace lld diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt deleted file mode 100644 --- a/lld/lib/Driver/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td) -tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs) -add_public_tablegen_target(DriverOptionsTableGen) - -add_lld_library(lldDriver - DarwinLdDriver.cpp - - ADDITIONAL_HEADER_DIRS - ${LLD_INCLUDE_DIR}/lld/Driver - - LINK_COMPONENTS - Option - Support - - LINK_LIBS - lldCommon - lldCore - lldMachOOld - lldReaderWriter - lldYAML - ) - -add_dependencies(lldDriver DriverOptionsTableGen) diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp deleted file mode 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ /dev/null @@ -1,1229 +0,0 @@ -//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Concrete instance of the Driver for darwin's ld. -/// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Args.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/LLVM.h" -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/Error.h" -#include "lld/Core/File.h" -#include "lld/Core/Instrumentation.h" -#include "lld/Core/LinkingContext.h" -#include "lld/Core/Node.h" -#include "lld/Core/PassManager.h" -#include "lld/Core/Resolver.h" -#include "lld/Core/SharedLibraryFile.h" -#include "lld/Core/Simple.h" -#include "lld/ReaderWriter/MachOLinkingContext.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/OptTable.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace lld; - -namespace { - -// Create enum with OPT_xxx values for each option in DarwinLdOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META, VALUES) \ - OPT_##ID, -#include "DarwinLdOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in DarwinLdOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "DarwinLdOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in DarwinLdOptions.td -static const llvm::opt::OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES) \ - {PREFIX, NAME, HELPTEXT, \ - METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, \ - OPT_##ALIAS, ALIASARGS, VALUES}, -#include "DarwinLdOptions.inc" -#undef OPTION -}; - -// Create OptTable class for parsing actual command line arguments -class DarwinLdOptTable : public llvm::opt::OptTable { -public: - DarwinLdOptTable() : OptTable(InfoTable) {} -}; - -static std::vector> -makeErrorFile(StringRef path, std::error_code ec) { - std::vector> result; - result.push_back(std::make_unique(path, ec)); - return result; -} - -static std::vector> -parseMemberFiles(std::unique_ptr file) { - std::vector> members; - if (auto *archive = dyn_cast(file.get())) { - if (std::error_code ec = archive->parseAllMembers(members)) - return makeErrorFile(file->path(), ec); - } else { - members.push_back(std::move(file)); - } - return members; -} - -std::vector> loadFile(MachOLinkingContext &ctx, - StringRef path, bool wholeArchive, - bool upwardDylib) { - if (ctx.logInputFiles()) - message(path); - - ErrorOr> mbOrErr = ctx.getMemoryBuffer(path); - if (std::error_code ec = mbOrErr.getError()) - return makeErrorFile(path, ec); - ErrorOr> fileOrErr = - ctx.registry().loadFile(std::move(mbOrErr.get())); - if (std::error_code ec = fileOrErr.getError()) - return makeErrorFile(path, ec); - std::unique_ptr &file = fileOrErr.get(); - - // If file is a dylib, inform LinkingContext about it. - if (SharedLibraryFile *shl = dyn_cast(file.get())) { - if (std::error_code ec = shl->parse()) - return makeErrorFile(path, ec); - ctx.registerDylib(reinterpret_cast(shl), - upwardDylib); - } - if (wholeArchive) - return parseMemberFiles(std::move(file)); - std::vector> files; - files.push_back(std::move(file)); - return files; -} - -} // end anonymous namespace - -// Test may be running on Windows. Canonicalize the path -// separator to '/' to get consistent outputs for tests. -static std::string canonicalizePath(StringRef path) { - char sep = llvm::sys::path::get_separator().front(); - if (sep != '/') { - std::string fixedPath = std::string(path); - std::replace(fixedPath.begin(), fixedPath.end(), sep, '/'); - return fixedPath; - } else { - return std::string(path); - } -} - -static void addFile(StringRef path, MachOLinkingContext &ctx, - bool loadWholeArchive, bool upwardDylib) { - std::vector> files = - loadFile(ctx, path, loadWholeArchive, upwardDylib); - for (std::unique_ptr &file : files) - ctx.getNodes().push_back(std::make_unique(std::move(file))); -} - -// Export lists are one symbol per line. Blank lines are ignored. -// Trailing comments start with #. -static std::error_code parseExportsList(StringRef exportFilePath, - MachOLinkingContext &ctx) { - // Map in export list file. - ErrorOr> mb = - MemoryBuffer::getFileOrSTDIN(exportFilePath); - if (std::error_code ec = mb.getError()) - return ec; - ctx.addInputFileDependency(exportFilePath); - StringRef buffer = mb->get()->getBuffer(); - while (!buffer.empty()) { - // Split off each line in the file. - std::pair lineAndRest = buffer.split('\n'); - StringRef line = lineAndRest.first; - // Ignore trailing # comments. - std::pair symAndComment = line.split('#'); - StringRef sym = symAndComment.first.trim(); - if (!sym.empty()) - ctx.addExportSymbol(sym); - buffer = lineAndRest.second; - } - return std::error_code(); -} - -/// Order files are one symbol per line. Blank lines are ignored. -/// Trailing comments start with #. Symbol names can be prefixed with an -/// architecture name and/or .o leaf name. Examples: -/// _foo -/// bar.o:_bar -/// libfrob.a(bar.o):_bar -/// x86_64:_foo64 -static std::error_code parseOrderFile(StringRef orderFilePath, - MachOLinkingContext &ctx) { - // Map in order file. - ErrorOr> mb = - MemoryBuffer::getFileOrSTDIN(orderFilePath); - if (std::error_code ec = mb.getError()) - return ec; - ctx.addInputFileDependency(orderFilePath); - StringRef buffer = mb->get()->getBuffer(); - while (!buffer.empty()) { - // Split off each line in the file. - std::pair lineAndRest = buffer.split('\n'); - StringRef line = lineAndRest.first; - buffer = lineAndRest.second; - // Ignore trailing # comments. - std::pair symAndComment = line.split('#'); - if (symAndComment.first.empty()) - continue; - StringRef sym = symAndComment.first.trim(); - if (sym.empty()) - continue; - // Check for prefix. - StringRef prefix; - std::pair prefixAndSym = sym.split(':'); - if (!prefixAndSym.second.empty()) { - sym = prefixAndSym.second; - prefix = prefixAndSym.first; - if (!prefix.endswith(".o") && !prefix.endswith(".o)")) { - // If arch name prefix does not match arch being linked, ignore symbol. - if (!ctx.archName().equals(prefix)) - continue; - prefix = ""; - } - } else - sym = prefixAndSym.first; - if (!sym.empty()) { - ctx.appendOrderedSymbol(sym, prefix); - // llvm::errs() << sym << ", prefix=" << prefix << "\n"; - } - } - return std::error_code(); -} - -// -// There are two variants of the -filelist option: -// -// -filelist -// In this variant, the path is to a text file which contains one file path -// per line. There are no comments or trimming of whitespace. -// -// -fileList , -// In this variant, the path is to a text file which contains a partial path -// per line. The prefix is prepended to each partial path. -// -static llvm::Error loadFileList(StringRef fileListPath, - MachOLinkingContext &ctx, bool forceLoad) { - // If there is a comma, split off . - std::pair opt = fileListPath.split(','); - StringRef filePath = opt.first; - StringRef dirName = opt.second; - ctx.addInputFileDependency(filePath); - // Map in file list file. - ErrorOr> mb = - MemoryBuffer::getFileOrSTDIN(filePath); - if (std::error_code ec = mb.getError()) - return llvm::errorCodeToError(ec); - StringRef buffer = mb->get()->getBuffer(); - while (!buffer.empty()) { - // Split off each line in the file. - std::pair lineAndRest = buffer.split('\n'); - StringRef line = lineAndRest.first; - StringRef path; - if (!dirName.empty()) { - // If there is a then prepend dir to each line. - SmallString<256> fullPath; - fullPath.assign(dirName); - llvm::sys::path::append(fullPath, Twine(line)); - path = ctx.copy(fullPath.str()); - } else { - // No use whole line as input file path. - path = ctx.copy(line); - } - if (!ctx.pathExists(path)) { - return llvm::make_error(Twine("File not found '") - + path - + "'"); - } - if (ctx.testingFileUsage()) { - message("Found filelist entry " + canonicalizePath(path)); - } - addFile(path, ctx, forceLoad, false); - buffer = lineAndRest.second; - } - return llvm::Error::success(); -} - -/// Parse number assuming it is base 16, but allow 0x prefix. -static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { - if (numStr.startswith_insensitive("0x")) - numStr = numStr.drop_front(2); - return numStr.getAsInteger(16, baseAddress); -} - -static void parseLLVMOptions(const LinkingContext &ctx) { - // Honor -mllvm - if (!ctx.llvmOptions().empty()) { - unsigned numArgs = ctx.llvmOptions().size(); - auto **args = new const char *[numArgs + 2]; - args[0] = "lld (LLVM option parsing)"; - for (unsigned i = 0; i != numArgs; ++i) - args[i + 1] = ctx.llvmOptions()[i]; - args[numArgs + 1] = nullptr; - llvm::cl::ResetAllOptionOccurrences(); - llvm::cl::ParseCommandLineOptions(numArgs + 1, args); - } -} - -namespace lld { -namespace mach_o { - -bool parse(llvm::ArrayRef args, MachOLinkingContext &ctx) { - // Parse command line options using DarwinLdOptions.td - DarwinLdOptTable table; - unsigned missingIndex; - unsigned missingCount; - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - if (missingCount) { - error("missing arg value for '" + - Twine(parsedArgs.getArgString(missingIndex)) + "' expected " + - Twine(missingCount) + " argument(s)."); - return false; - } - - for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) { - warn("ignoring unknown argument: " + - Twine(unknownArg->getAsString(parsedArgs))); - } - - errorHandler().verbose = parsedArgs.hasArg(OPT_v); - errorHandler().errorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20); - - // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) - llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; - bool isStaticExecutable = false; - if (llvm::opt::Arg *kind = parsedArgs.getLastArg( - OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { - switch (kind->getOption().getID()) { - case OPT_dylib: - fileType = llvm::MachO::MH_DYLIB; - break; - case OPT_relocatable: - fileType = llvm::MachO::MH_OBJECT; - break; - case OPT_bundle: - fileType = llvm::MachO::MH_BUNDLE; - break; - case OPT_static: - fileType = llvm::MachO::MH_EXECUTE; - isStaticExecutable = true; - break; - case OPT_preload: - fileType = llvm::MachO::MH_PRELOAD; - break; - } - } - - // Handle -arch xxx - MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown; - if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) { - arch = MachOLinkingContext::archFromName(archStr->getValue()); - if (arch == MachOLinkingContext::arch_unknown) { - error("unknown arch named '" + Twine(archStr->getValue()) + "'"); - return false; - } - } - // If no -arch specified, scan input files to find first non-fat .o file. - if (arch == MachOLinkingContext::arch_unknown) { - for (auto &inFile : parsedArgs.filtered(OPT_INPUT)) { - // This is expensive because it opens and maps the file. But that is - // ok because no -arch is rare. - if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch)) - break; - } - if (arch == MachOLinkingContext::arch_unknown && - !parsedArgs.getLastArg(OPT_test_file_usage)) { - // If no -arch and no options at all, print usage message. - if (parsedArgs.size() == 0) { - table.printHelp(llvm::outs(), - (std::string(args[0]) + " [options] file...").c_str(), - "LLVM Linker", false); - } else { - error("-arch not specified and could not be inferred"); - } - return false; - } - } - - // Handle -macosx_version_min or -ios_version_min - MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown; - uint32_t minOSVersion = 0; - if (llvm::opt::Arg *minOS = - parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min, - OPT_ios_simulator_version_min)) { - switch (minOS->getOption().getID()) { - case OPT_macosx_version_min: - os = MachOLinkingContext::OS::macOSX; - if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), - minOSVersion)) { - error("malformed macosx_version_min value"); - return false; - } - break; - case OPT_ios_version_min: - os = MachOLinkingContext::OS::iOS; - if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), - minOSVersion)) { - error("malformed ios_version_min value"); - return false; - } - break; - case OPT_ios_simulator_version_min: - os = MachOLinkingContext::OS::iOS_simulator; - if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), - minOSVersion)) { - error("malformed ios_simulator_version_min value"); - return false; - } - break; - } - } else { - // No min-os version on command line, check environment variables - } - - // Handle export_dynamic - // FIXME: Should we warn when this applies to something other than a static - // executable or dylib? Those are the only cases where this has an effect. - // Note, this has to come before ctx.configure() so that we get the correct - // value for _globalsAreDeadStripRoots. - bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic); - - // Now that there's enough information parsed in, let the linking context - // set up default values. - ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols); - - // Handle -e xxx - if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry)) - ctx.setEntrySymbolName(entry->getValue()); - - // Handle -o xxx - if (llvm::opt::Arg *outpath = parsedArgs.getLastArg(OPT_output)) - ctx.setOutputPath(outpath->getValue()); - else - ctx.setOutputPath("a.out"); - - // Handle -image_base XXX and -seg1addr XXXX - if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) { - uint64_t baseAddress; - if (parseNumberBase16(imageBase->getValue(), baseAddress)) { - error("image_base expects a hex number"); - return false; - } else if (baseAddress < ctx.pageZeroSize()) { - error("image_base overlaps with __PAGEZERO"); - return false; - } else if (baseAddress % ctx.pageSize()) { - error("image_base must be a multiple of page size (0x" + - llvm::utohexstr(ctx.pageSize()) + ")"); - return false; - } - - ctx.setBaseAddress(baseAddress); - } - - // Handle -dead_strip - if (parsedArgs.getLastArg(OPT_dead_strip)) - ctx.setDeadStripping(true); - - bool globalWholeArchive = false; - // Handle -all_load - if (parsedArgs.getLastArg(OPT_all_load)) - globalWholeArchive = true; - - // Handle -install_name - if (llvm::opt::Arg *installName = parsedArgs.getLastArg(OPT_install_name)) - ctx.setInstallName(installName->getValue()); - else - ctx.setInstallName(ctx.outputPath()); - - // Handle -mark_dead_strippable_dylib - if (parsedArgs.getLastArg(OPT_mark_dead_strippable_dylib)) - ctx.setDeadStrippableDylib(true); - - // Handle -compatibility_version and -current_version - if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) { - if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { - error("-compatibility_version can only be used with -dylib"); - return false; - } - uint32_t parsedVers; - if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { - error("-compatibility_version value is malformed"); - return false; - } - ctx.setCompatibilityVersion(parsedVers); - } - - if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) { - if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { - error("-current_version can only be used with -dylib"); - return false; - } - uint32_t parsedVers; - if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { - error("-current_version value is malformed"); - return false; - } - ctx.setCurrentVersion(parsedVers); - } - - // Handle -bundle_loader - if (llvm::opt::Arg *loader = parsedArgs.getLastArg(OPT_bundle_loader)) - ctx.setBundleLoader(loader->getValue()); - - // Handle -sectalign segname sectname align - for (auto &alignArg : parsedArgs.filtered(OPT_sectalign)) { - const char* segName = alignArg->getValue(0); - const char* sectName = alignArg->getValue(1); - const char* alignStr = alignArg->getValue(2); - if ((alignStr[0] == '0') && (alignStr[1] == 'x')) - alignStr += 2; - unsigned long long alignValue; - if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) { - error("-sectalign alignment value '" + Twine(alignStr) + - "' not a valid number"); - return false; - } - uint16_t align = 1 << llvm::countTrailingZeros(alignValue); - if (!llvm::isPowerOf2_64(alignValue)) { - std::string Msg; - llvm::raw_string_ostream OS(Msg); - OS << "alignment for '-sectalign " << segName << " " << sectName - << llvm::format(" 0x%llX", alignValue) - << "' is not a power of two, using " << llvm::format("0x%08X", align); - OS.flush(); - warn(Msg); - } - ctx.addSectionAlignment(segName, sectName, align); - } - - // Handle -mllvm - for (auto &llvmArg : parsedArgs.filtered(OPT_mllvm)) { - ctx.appendLLVMOption(llvmArg->getValue()); - } - - // Handle -print_atoms - if (parsedArgs.getLastArg(OPT_print_atoms)) - ctx.setPrintAtoms(); - - // Handle -t (trace) option. - if (parsedArgs.getLastArg(OPT_t)) - ctx.setLogInputFiles(true); - - // Handle -demangle option. - if (parsedArgs.getLastArg(OPT_demangle)) - ctx.setDemangleSymbols(true); - - // Handle -keep_private_externs - if (parsedArgs.getLastArg(OPT_keep_private_externs)) { - ctx.setKeepPrivateExterns(true); - if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT) - warn("-keep_private_externs only used in -r mode"); - } - - // Handle -dependency_info used by Xcode. - if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) - if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) - warn(ec.message() + ", processing '-dependency_info " + - depInfo->getValue()); - - // In -test_file_usage mode, we'll be given an explicit list of paths that - // exist. We'll also be expected to print out information about how we located - // libraries and so on that the user specified, but not to actually do any - // linking. - if (parsedArgs.getLastArg(OPT_test_file_usage)) { - ctx.setTestingFileUsage(); - - // With paths existing by fiat, linking is not going to end well. - ctx.setDoNothing(true); - - // Only bother looking for an existence override if we're going to use it. - for (auto existingPath : parsedArgs.filtered(OPT_path_exists)) { - ctx.addExistingPathForDebug(existingPath->getValue()); - } - } - - // Register possible input file parsers. - if (!ctx.doNothing()) { - ctx.registry().addSupportMachOObjects(ctx); - ctx.registry().addSupportArchives(ctx.logInputFiles()); - ctx.registry().addSupportYamlFiles(); - } - - // Now construct the set of library search directories, following ld64's - // baroque set of accumulated hacks. Mostly, the algorithm constructs - // { syslibroots } x { libpaths } - // - // Unfortunately, there are numerous exceptions: - // 1. Only absolute paths get modified by syslibroot options. - // 2. If there is just 1 -syslibroot, system paths not found in it are - // skipped. - // 3. If the last -syslibroot is "/", all of them are ignored entirely. - // 4. If { syslibroots } x path == {}, the original path is kept. - std::vector sysLibRoots; - for (auto syslibRoot : parsedArgs.filtered(OPT_syslibroot)) { - sysLibRoots.push_back(syslibRoot->getValue()); - } - if (!sysLibRoots.empty()) { - // Ignore all if last -syslibroot is "/". - if (sysLibRoots.back() != "/") - ctx.setSysLibRoots(sysLibRoots); - } - - // Paths specified with -L come first, and are not considered system paths for - // the case where there is precisely 1 -syslibroot. - for (auto libPath : parsedArgs.filtered(OPT_L)) { - ctx.addModifiedSearchDir(libPath->getValue()); - } - - // Process -F directories (where to look for frameworks). - for (auto fwPath : parsedArgs.filtered(OPT_F)) { - ctx.addFrameworkSearchDir(fwPath->getValue()); - } - - // -Z suppresses the standard search paths. - if (!parsedArgs.hasArg(OPT_Z)) { - ctx.addModifiedSearchDir("/usr/lib", true); - ctx.addModifiedSearchDir("/usr/local/lib", true); - ctx.addFrameworkSearchDir("/Library/Frameworks", true); - ctx.addFrameworkSearchDir("/System/Library/Frameworks", true); - } - - // Now that we've constructed the final set of search paths, print out those - // search paths in verbose mode. - if (errorHandler().verbose) { - message("Library search paths:"); - for (auto path : ctx.searchDirs()) { - message(" " + path); - } - message("Framework search paths:"); - for (auto path : ctx.frameworkDirs()) { - message(" " + path); - } - } - - // Handle -exported_symbols_list - for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) { - if (ctx.exportMode() == MachOLinkingContext::ExportMode::unexported) { - error("-exported_symbols_list cannot be combined with " - "-unexported_symbol[s_list]"); - return false; - } - ctx.setExportMode(MachOLinkingContext::ExportMode::exported); - if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) { - error(ec.message() + ", processing '-exported_symbols_list " + - expFile->getValue()); - return false; - } - } - - // Handle -exported_symbol - for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) { - if (ctx.exportMode() == MachOLinkingContext::ExportMode::unexported) { - error("-exported_symbol cannot be combined with " - "-unexported_symbol[s_list]"); - return false; - } - ctx.setExportMode(MachOLinkingContext::ExportMode::exported); - ctx.addExportSymbol(symbol->getValue()); - } - - // Handle -unexported_symbols_list - for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) { - if (ctx.exportMode() == MachOLinkingContext::ExportMode::exported) { - error("-unexported_symbols_list cannot be combined with " - "-exported_symbol[s_list]"); - return false; - } - ctx.setExportMode(MachOLinkingContext::ExportMode::unexported); - if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) { - error(ec.message() + ", processing '-unexported_symbols_list " + - expFile->getValue()); - return false; - } - } - - // Handle -unexported_symbol - for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) { - if (ctx.exportMode() == MachOLinkingContext::ExportMode::exported) { - error("-unexported_symbol cannot be combined with " - "-exported_symbol[s_list]"); - return false; - } - ctx.setExportMode(MachOLinkingContext::ExportMode::unexported); - ctx.addExportSymbol(symbol->getValue()); - } - - // Handle obosolete -multi_module and -single_module - if (llvm::opt::Arg *mod = - parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) { - if (mod->getOption().getID() == OPT_multi_module) - warn("-multi_module is obsolete and being ignored"); - else if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) - warn("-single_module being ignored. It is only for use when producing a " - "dylib"); - } - - // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only - if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { - error("-objc_gc_compaction is not supported"); - return false; - } - - if (parsedArgs.getLastArg(OPT_objc_gc)) { - error("-objc_gc is not supported"); - return false; - } - - if (parsedArgs.getLastArg(OPT_objc_gc_only)) { - error("-objc_gc_only is not supported"); - return false; - } - - // Handle -pie or -no_pie - if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) { - switch (ctx.outputMachOType()) { - case llvm::MachO::MH_EXECUTE: - switch (ctx.os()) { - case MachOLinkingContext::OS::macOSX: - if ((minOSVersion < 0x000A0500) && - (pie->getOption().getID() == OPT_pie)) { - error("-pie can only be used when targeting Mac OS X 10.5 or later"); - return false; - } - break; - case MachOLinkingContext::OS::iOS: - if ((minOSVersion < 0x00040200) && - (pie->getOption().getID() == OPT_pie)) { - error("-pie can only be used when targeting iOS 4.2 or later"); - return false; - } - break; - case MachOLinkingContext::OS::iOS_simulator: - if (pie->getOption().getID() == OPT_no_pie) { - error("iOS simulator programs must be built PIE"); - return false; - } - break; - case MachOLinkingContext::OS::unknown: - break; - } - ctx.setPIE(pie->getOption().getID() == OPT_pie); - break; - case llvm::MachO::MH_PRELOAD: - break; - case llvm::MachO::MH_DYLIB: - case llvm::MachO::MH_BUNDLE: - warn(pie->getSpelling() + - " being ignored. It is only used when linking main executables"); - break; - default: - error(pie->getSpelling() + - " can only used when linking main executables"); - return false; - } - } - - // Handle -version_load_command or -no_version_load_command - { - bool flagOn = false; - bool flagOff = false; - if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command, - OPT_no_version_load_command)) { - flagOn = arg->getOption().getID() == OPT_version_load_command; - flagOff = arg->getOption().getID() == OPT_no_version_load_command; - } - - // default to adding version load command for dynamic code, - // static code must opt-in - switch (ctx.outputMachOType()) { - case llvm::MachO::MH_OBJECT: - ctx.setGenerateVersionLoadCommand(false); - break; - case llvm::MachO::MH_EXECUTE: - // dynamic executables default to generating a version load command, - // while static executables only generate it if required. - if (isStaticExecutable) { - if (flagOn) - ctx.setGenerateVersionLoadCommand(true); - } else { - if (!flagOff) - ctx.setGenerateVersionLoadCommand(true); - } - break; - case llvm::MachO::MH_PRELOAD: - case llvm::MachO::MH_KEXT_BUNDLE: - if (flagOn) - ctx.setGenerateVersionLoadCommand(true); - break; - case llvm::MachO::MH_DYLINKER: - case llvm::MachO::MH_DYLIB: - case llvm::MachO::MH_BUNDLE: - if (!flagOff) - ctx.setGenerateVersionLoadCommand(true); - break; - case llvm::MachO::MH_FVMLIB: - case llvm::MachO::MH_DYLDLINK: - case llvm::MachO::MH_DYLIB_STUB: - case llvm::MachO::MH_DSYM: - // We don't generate load commands for these file types, even if - // forced on. - break; - } - } - - // Handle -function_starts or -no_function_starts - { - bool flagOn = false; - bool flagOff = false; - if (auto *arg = parsedArgs.getLastArg(OPT_function_starts, - OPT_no_function_starts)) { - flagOn = arg->getOption().getID() == OPT_function_starts; - flagOff = arg->getOption().getID() == OPT_no_function_starts; - } - - // default to adding functions start for dynamic code, static code must - // opt-in - switch (ctx.outputMachOType()) { - case llvm::MachO::MH_OBJECT: - ctx.setGenerateFunctionStartsLoadCommand(false); - break; - case llvm::MachO::MH_EXECUTE: - // dynamic executables default to generating a version load command, - // while static executables only generate it if required. - if (isStaticExecutable) { - if (flagOn) - ctx.setGenerateFunctionStartsLoadCommand(true); - } else { - if (!flagOff) - ctx.setGenerateFunctionStartsLoadCommand(true); - } - break; - case llvm::MachO::MH_PRELOAD: - case llvm::MachO::MH_KEXT_BUNDLE: - if (flagOn) - ctx.setGenerateFunctionStartsLoadCommand(true); - break; - case llvm::MachO::MH_DYLINKER: - case llvm::MachO::MH_DYLIB: - case llvm::MachO::MH_BUNDLE: - if (!flagOff) - ctx.setGenerateFunctionStartsLoadCommand(true); - break; - case llvm::MachO::MH_FVMLIB: - case llvm::MachO::MH_DYLDLINK: - case llvm::MachO::MH_DYLIB_STUB: - case llvm::MachO::MH_DSYM: - // We don't generate load commands for these file types, even if - // forced on. - break; - } - } - - // Handle -data_in_code_info or -no_data_in_code_info - { - bool flagOn = false; - bool flagOff = false; - if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info, - OPT_no_data_in_code_info)) { - flagOn = arg->getOption().getID() == OPT_data_in_code_info; - flagOff = arg->getOption().getID() == OPT_no_data_in_code_info; - } - - // default to adding data in code for dynamic code, static code must - // opt-in - switch (ctx.outputMachOType()) { - case llvm::MachO::MH_OBJECT: - if (!flagOff) - ctx.setGenerateDataInCodeLoadCommand(true); - break; - case llvm::MachO::MH_EXECUTE: - // dynamic executables default to generating a version load command, - // while static executables only generate it if required. - if (isStaticExecutable) { - if (flagOn) - ctx.setGenerateDataInCodeLoadCommand(true); - } else { - if (!flagOff) - ctx.setGenerateDataInCodeLoadCommand(true); - } - break; - case llvm::MachO::MH_PRELOAD: - case llvm::MachO::MH_KEXT_BUNDLE: - if (flagOn) - ctx.setGenerateDataInCodeLoadCommand(true); - break; - case llvm::MachO::MH_DYLINKER: - case llvm::MachO::MH_DYLIB: - case llvm::MachO::MH_BUNDLE: - if (!flagOff) - ctx.setGenerateDataInCodeLoadCommand(true); - break; - case llvm::MachO::MH_FVMLIB: - case llvm::MachO::MH_DYLDLINK: - case llvm::MachO::MH_DYLIB_STUB: - case llvm::MachO::MH_DSYM: - // We don't generate load commands for these file types, even if - // forced on. - break; - } - } - - // Handle sdk_version - if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) { - uint32_t sdkVersion = 0; - if (MachOLinkingContext::parsePackedVersion(arg->getValue(), - sdkVersion)) { - error("malformed sdkVersion value"); - return false; - } - ctx.setSdkVersion(sdkVersion); - } else if (ctx.generateVersionLoadCommand()) { - // If we don't have an sdk version, but were going to emit a load command - // with min_version, then we need to give a warning as we have no sdk - // version to put in that command. - // FIXME: We need to decide whether to make this an error. - warn("-sdk_version is required when emitting min version load command. " - "Setting sdk version to match provided min version"); - ctx.setSdkVersion(ctx.osMinVersion()); - } - - // Handle source_version - if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) { - uint64_t version = 0; - if (MachOLinkingContext::parsePackedVersion(arg->getValue(), - version)) { - error("malformed source_version value"); - return false; - } - ctx.setSourceVersion(version); - } - - // Handle stack_size - if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { - uint64_t stackSizeVal; - if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) { - error("stack_size expects a hex number"); - return false; - } - if ((stackSizeVal % ctx.pageSize()) != 0) { - error("stack_size must be a multiple of page size (0x" + - llvm::utohexstr(ctx.pageSize()) + ")"); - return false; - } - - ctx.setStackSize(stackSizeVal); - } - - // Handle debug info handling options: -S - if (parsedArgs.hasArg(OPT_S)) - ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap); - - // Handle -order_file - for (auto orderFile : parsedArgs.filtered(OPT_order_file)) { - if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx)) { - error(ec.message() + ", processing '-order_file " + orderFile->getValue() - + "'"); - return false; - } - } - - // Handle -flat_namespace. - if (llvm::opt::Arg *ns = - parsedArgs.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) { - if (ns->getOption().getID() == OPT_flat_namespace) - ctx.setUseFlatNamespace(true); - } - - // Handle -undefined - if (llvm::opt::Arg *undef = parsedArgs.getLastArg(OPT_undefined)) { - MachOLinkingContext::UndefinedMode UndefMode; - if (StringRef(undef->getValue()).equals("error")) - UndefMode = MachOLinkingContext::UndefinedMode::error; - else if (StringRef(undef->getValue()).equals("warning")) - UndefMode = MachOLinkingContext::UndefinedMode::warning; - else if (StringRef(undef->getValue()).equals("suppress")) - UndefMode = MachOLinkingContext::UndefinedMode::suppress; - else if (StringRef(undef->getValue()).equals("dynamic_lookup")) - UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup; - else { - error("invalid option to -undefined [ warning | error | suppress | " - "dynamic_lookup ]"); - return false; - } - - if (ctx.useFlatNamespace()) { - // If we're using -flat_namespace then 'warning', 'suppress' and - // 'dynamic_lookup' are all equivalent, so map them to 'suppress'. - if (UndefMode != MachOLinkingContext::UndefinedMode::error) - UndefMode = MachOLinkingContext::UndefinedMode::suppress; - } else { - // If we're using -twolevel_namespace then 'warning' and 'suppress' are - // illegal. Emit a diagnostic if they've been (mis)used. - if (UndefMode == MachOLinkingContext::UndefinedMode::warning || - UndefMode == MachOLinkingContext::UndefinedMode::suppress) { - error("can't use -undefined warning or suppress with " - "-twolevel_namespace"); - return false; - } - } - - ctx.setUndefinedMode(UndefMode); - } - - // Handle -no_objc_category_merging. - if (parsedArgs.getLastArg(OPT_no_objc_category_merging)) - ctx.setMergeObjCCategories(false); - - // Handle -rpath - if (parsedArgs.hasArg(OPT_rpath)) { - switch (ctx.outputMachOType()) { - case llvm::MachO::MH_EXECUTE: - case llvm::MachO::MH_DYLIB: - case llvm::MachO::MH_BUNDLE: - if (!ctx.minOS("10.5", "2.0")) { - if (ctx.os() == MachOLinkingContext::OS::macOSX) - error("-rpath can only be used when targeting OS X 10.5 or later"); - else - error("-rpath can only be used when targeting iOS 2.0 or later"); - return false; - } - break; - default: - error("-rpath can only be used when creating a dynamic final linked " - "image"); - return false; - } - - for (auto rPath : parsedArgs.filtered(OPT_rpath)) { - ctx.addRpath(rPath->getValue()); - } - } - - // Parse the LLVM options before we process files in case the file handling - // makes use of things like LLVM_DEBUG(). - parseLLVMOptions(ctx); - - // Handle input files and sectcreate. - for (auto &arg : parsedArgs) { - bool upward; - llvm::Optional resolvedPath; - switch (arg->getOption().getID()) { - default: - continue; - case OPT_INPUT: - addFile(arg->getValue(), ctx, globalWholeArchive, false); - break; - case OPT_upward_library: - addFile(arg->getValue(), ctx, false, true); - break; - case OPT_force_load: - addFile(arg->getValue(), ctx, true, false); - break; - case OPT_l: - case OPT_upward_l: - upward = (arg->getOption().getID() == OPT_upward_l); - resolvedPath = ctx.searchLibrary(arg->getValue()); - if (!resolvedPath) { - error("Unable to find library for " + arg->getSpelling() + - arg->getValue()); - return false; - } else if (ctx.testingFileUsage()) { - message(Twine("Found ") + (upward ? "upward " : " ") + "library " + - canonicalizePath(resolvedPath.getValue())); - } - addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward); - break; - case OPT_framework: - case OPT_upward_framework: - upward = (arg->getOption().getID() == OPT_upward_framework); - resolvedPath = ctx.findPathForFramework(arg->getValue()); - if (!resolvedPath) { - error("Unable to find framework for " + arg->getSpelling() + " " + - arg->getValue()); - return false; - } else if (ctx.testingFileUsage()) { - message(Twine("Found ") + (upward ? "upward " : " ") + "framework " + - canonicalizePath(resolvedPath.getValue())); - } - addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward); - break; - case OPT_filelist: - if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive)) { - handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { - error(EI.message() + ", processing '-filelist " + arg->getValue()); - }); - return false; - } - break; - case OPT_sectcreate: { - const char* seg = arg->getValue(0); - const char* sect = arg->getValue(1); - const char* fileName = arg->getValue(2); - - ErrorOr> contentOrErr = - MemoryBuffer::getFile(fileName); - - if (!contentOrErr) { - error("can't open -sectcreate file " + Twine(fileName)); - return false; - } - - ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr)); - } - break; - } - } - - if (ctx.getNodes().empty()) { - error("No input files"); - return false; - } - - // Validate the combination of options used. - return ctx.validate(); -} - -static void createFiles(MachOLinkingContext &ctx, bool Implicit) { - std::vector> Files; - if (Implicit) - ctx.createImplicitFiles(Files); - else - ctx.createInternalFiles(Files); - for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), std::make_unique(std::move(*i))); - } -} - -/// This is where the link is actually performed. -bool link(llvm::ArrayRef args, bool CanExitEarly, - raw_ostream &StdoutOS, raw_ostream &StderrOS) { - lld::stdoutOS = &StdoutOS; - lld::stderrOS = &StderrOS; - - errorHandler().logName = args::getFilenameWithoutExe(args[0]); - errorHandler().errorLimitExceededMsg = - "too many errors emitted, stopping now (use " - "'-error-limit 0' to see all errors)"; - errorHandler().exitEarly = CanExitEarly; - StderrOS.enable_colors(StderrOS.has_colors()); - - MachOLinkingContext ctx; - if (!parse(args, ctx)) - return false; - if (ctx.doNothing()) - return true; - if (ctx.getNodes().empty()) - return false; - - for (std::unique_ptr &ie : ctx.getNodes()) - if (FileNode *node = dyn_cast(ie.get())) - node->getFile()->parse(); - - createFiles(ctx, false /* Implicit */); - - // Give target a chance to add files - createFiles(ctx, true /* Implicit */); - - // Give target a chance to postprocess input files. - // Mach-O uses this chance to move all object files before library files. - ctx.finalizeInputFiles(); - - // Do core linking. - ScopedTask resolveTask(getDefaultDomain(), "Resolve"); - Resolver resolver(ctx); - if (!resolver.resolve()) - return false; - SimpleFile *merged = nullptr; - { - std::unique_ptr mergedFile = resolver.resultFile(); - merged = mergedFile.get(); - auto &members = ctx.getNodes(); - members.insert(members.begin(), - std::make_unique(std::move(mergedFile))); - } - resolveTask.end(); - - // Run passes on linked atoms. - ScopedTask passTask(getDefaultDomain(), "Passes"); - PassManager pm; - ctx.addPasses(pm); - if (auto ec = pm.runOnFile(*merged)) { - // FIXME: This should be passed to logAllUnhandledErrors but it needs - // to be passed a Twine instead of a string. - lld::errs() << "Failed to run passes on file '" << ctx.outputPath() - << "': "; - logAllUnhandledErrors(std::move(ec), lld::errs(), std::string()); - return false; - } - - passTask.end(); - - // Give linked atoms to Writer to generate output file. - ScopedTask writeTask(getDefaultDomain(), "Write"); - if (auto ec = ctx.writeFile(*merged)) { - // FIXME: This should be passed to logAllUnhandledErrors but it needs - // to be passed a Twine instead of a string. - lld::errs() << "Failed to write file '" << ctx.outputPath() << "': "; - logAllUnhandledErrors(std::move(ec), lld::errs(), std::string()); - return false; - } - - // Call exit() if we can to avoid calling destructors. - if (CanExitEarly) - exitLld(errorCount() ? 1 : 0); - - - return true; -} - -} // end namespace mach_o -} // end namespace lld diff --git a/lld/lib/Driver/DarwinLdOptions.td b/lld/lib/Driver/DarwinLdOptions.td deleted file mode 100644 --- a/lld/lib/Driver/DarwinLdOptions.td +++ /dev/null @@ -1,250 +0,0 @@ -include "llvm/Option/OptParser.td" - - -// output kinds -def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">; -def relocatable : Flag<["-"], "r">, - HelpText<"Create relocatable object file">, Group; -def static : Flag<["-"], "static">, - HelpText<"Create static executable">, Group; -def dynamic : Flag<["-"], "dynamic">, - HelpText<"Create dynamic executable (default)">,Group; -def dylib : Flag<["-"], "dylib">, - HelpText<"Create dynamic library">, Group; -def bundle : Flag<["-"], "bundle">, - HelpText<"Create dynamic bundle">, Group; -def execute : Flag<["-"], "execute">, - HelpText<"Create main executable (default)">, Group; -def preload : Flag<["-"], "preload">, - HelpText<"Create binary for use with embedded systems">, Group; - -// optimizations -def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">; -def dead_strip : Flag<["-"], "dead_strip">, - HelpText<"Remove unreference code and data">, Group; -def macosx_version_min : Separate<["-"], "macosx_version_min">, - MetaVarName<"">, - HelpText<"Minimum Mac OS X version">, Group; -def ios_version_min : Separate<["-"], "ios_version_min">, - MetaVarName<"">, - HelpText<"Minimum iOS version">, Group; -def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">, - Alias; -def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">, - MetaVarName<"">, - HelpText<"Minimum iOS simulator version">, Group; -def sdk_version : Separate<["-"], "sdk_version">, - MetaVarName<"">, - HelpText<"SDK version">, Group; -def source_version : Separate<["-"], "source_version">, - MetaVarName<"">, - HelpText<"Source version">, Group; -def version_load_command : Flag<["-"], "version_load_command">, - HelpText<"Force generation of a version load command">, Group; -def no_version_load_command : Flag<["-"], "no_version_load_command">, - HelpText<"Disable generation of a version load command">, Group; -def function_starts : Flag<["-"], "function_starts">, - HelpText<"Force generation of a function starts load command">, - Group; -def no_function_starts : Flag<["-"], "no_function_starts">, - HelpText<"Disable generation of a function starts load command">, - Group; -def data_in_code_info : Flag<["-"], "data_in_code_info">, - HelpText<"Force generation of a data in code load command">, - Group; -def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">, - HelpText<"Disable generation of a data in code load command">, - Group; -def mllvm : Separate<["-"], "mllvm">, - MetaVarName<"