blob: 531f41c2949639fe717eddb5e9985bb3129e5ceb [file] [log] [blame]
//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#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/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
#include <set>
using llvm::MachO::HeaderFileType;
namespace lld {
namespace mach_o {
class ArchHandler;
class MachODylibFile;
class MachOFile;
}
class MachOLinkingContext : public LinkingContext {
public:
MachOLinkingContext();
~MachOLinkingContext();
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.
whiteList, // -exported_symbol[s_list], only listed symbols exported.
blackList // -unexported_symbol[s_list], no listed symbol exported.
};
enum class DebugInfoMode {
addDebugMap, // Default
noDebugMap // -S option
};
/// 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);
void addPasses(PassManager &pm) override;
bool validateImpl(raw_ostream &diagnostics) override;
std::string demangle(StringRef symbolName) const override;
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
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; }
/// 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; }
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; }
/// \brief 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;
/// \brief 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);
/// \brief 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).
ErrorOr<StringRef> searchDirForLibrary(StringRef path,
StringRef libName) const;
/// \brief Iterates through all search path entries looking for libName (as
/// specified by -lFoo).
ErrorOr<StringRef> 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);
/// \brief Iterates through all framework directories looking for
/// Foo.framework/Foo (when fwName = "Foo").
ErrorOr<StringRef> findPathForFramework(StringRef fwName) const;
/// \brief 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; }
/// \brief The dylib's current version, in the 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; }
/// \brief 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; }
/// \brief 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; }
/// \brief 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 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);
/// 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;
/// 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<std::unique_ptr<MemoryBuffer>> 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;
/// 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);
void finalizeInputFiles() override;
bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
bool &leftBeforeRight) const;
private:
Writer &writer() const override;
mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
void checkExportWhiteList(const DefinedAtom *atom) const;
void checkExportBlackList(const DefinedAtom *atom) const;
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<OrderFileNode> &nodes,
const DefinedAtom *atom, unsigned &ordinal);
static ArchInfo _s_archInfos[];
std::set<StringRef> _existingPaths; // For testing only.
StringRefVector _searchDirs;
StringRefVector _syslibRoots;
StringRefVector _frameworkDirs;
HeaderFileType _outputMachOType; // e.g MH_EXECUTE
bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
bool _doNothing; // for -help and -v which just print info
bool _pie;
Arch _arch;
OS _os;
uint32_t _osMinVersion;
uint64_t _pageZeroSize;
uint64_t _pageSize;
uint64_t _baseAddress;
uint64_t _stackSize;
uint32_t _compatibilityVersion;
uint32_t _currentVersion;
StringRef _installName;
StringRefVector _rpaths;
bool _deadStrippableDylib;
bool _printAtoms;
bool _testingFileUsage;
bool _keepPrivateExterns;
bool _demangle;
StringRef _bundleLoader;
mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
mutable std::unique_ptr<Writer> _writer;
std::vector<SectionAlign> _sectAligns;
mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
mutable std::set<mach_o::MachODylibFile*> _allDylibs;
mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
mutable std::mutex _dylibsMutex;
ExportMode _exportMode;
llvm::StringSet<> _exportedSymbols;
DebugInfoMode _debugInfoMode;
std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
unsigned _orderFileEntries;
};
} // end namespace lld
#endif