summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
commitb64793999546ed8adebaeebd9d8345d18db8927d (patch)
tree4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
parentAdd support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff)
downloadwireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz
wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp')
-rw-r--r--gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp1230
1 files changed, 0 insertions, 1230 deletions
diff --git a/gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp b/gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
deleted file mode 100644
index bbac230df45..00000000000
--- a/gnu/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
+++ /dev/null
@@ -1,1230 +0,0 @@
-//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \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 <algorithm>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <system_error>
-#include <utility>
-#include <vector>
-
-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<std::unique_ptr<File>>
-makeErrorFile(StringRef path, std::error_code ec) {
- std::vector<std::unique_ptr<File>> result;
- result.push_back(llvm::make_unique<ErrorFile>(path, ec));
- return result;
-}
-
-static std::vector<std::unique_ptr<File>>
-parseMemberFiles(std::unique_ptr<File> file) {
- std::vector<std::unique_ptr<File>> members;
- if (auto *archive = dyn_cast<ArchiveLibraryFile>(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<std::unique_ptr<File>> loadFile(MachOLinkingContext &ctx,
- StringRef path, bool wholeArchive,
- bool upwardDylib) {
- if (ctx.logInputFiles())
- message(path);
-
- ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
- if (std::error_code ec = mbOrErr.getError())
- return makeErrorFile(path, ec);
- ErrorOr<std::unique_ptr<File>> fileOrErr =
- ctx.registry().loadFile(std::move(mbOrErr.get()));
- if (std::error_code ec = fileOrErr.getError())
- return makeErrorFile(path, ec);
- std::unique_ptr<File> &file = fileOrErr.get();
-
- // If file is a dylib, inform LinkingContext about it.
- if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(file.get())) {
- if (std::error_code ec = shl->parse())
- return makeErrorFile(path, ec);
- ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile *>(shl),
- upwardDylib);
- }
- if (wholeArchive)
- return parseMemberFiles(std::move(file));
- std::vector<std::unique_ptr<File>> 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 = path;
- std::replace(fixedPath.begin(), fixedPath.end(), sep, '/');
- return fixedPath;
- } else {
- return path;
- }
-}
-
-static void addFile(StringRef path, MachOLinkingContext &ctx,
- bool loadWholeArchive, bool upwardDylib) {
- std::vector<std::unique_ptr<File>> files =
- loadFile(ctx, path, loadWholeArchive, upwardDylib);
- for (std::unique_ptr<File> &file : files)
- ctx.getNodes().push_back(llvm::make_unique<FileNode>(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<std::unique_ptr<MemoryBuffer>> 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<StringRef, StringRef> lineAndRest = buffer.split('\n');
- StringRef line = lineAndRest.first;
- // Ignore trailing # comments.
- std::pair<StringRef, StringRef> 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<std::unique_ptr<MemoryBuffer>> 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<StringRef, StringRef> lineAndRest = buffer.split('\n');
- StringRef line = lineAndRest.first;
- buffer = lineAndRest.second;
- // Ignore trailing # comments.
- std::pair<StringRef, StringRef> symAndComment = line.split('#');
- if (symAndComment.first.empty())
- continue;
- StringRef sym = symAndComment.first.trim();
- if (sym.empty())
- continue;
- // Check for prefix.
- StringRef prefix;
- std::pair<StringRef, StringRef> 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 <path>
-// 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 <path>,<dir>
-// In this variant, the path is to a text file which contains a partial path
-// per line. The <dir> prefix is prepended to each partial path.
-//
-static llvm::Error loadFileList(StringRef fileListPath,
- MachOLinkingContext &ctx, bool forceLoad) {
- // If there is a comma, split off <dir>.
- std::pair<StringRef, StringRef> opt = fileListPath.split(',');
- StringRef filePath = opt.first;
- StringRef dirName = opt.second;
- ctx.addInputFileDependency(filePath);
- // Map in file list file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> 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<StringRef, StringRef> lineAndRest = buffer.split('\n');
- StringRef line = lineAndRest.first;
- StringRef path;
- if (!dirName.empty()) {
- // If there is a <dir> 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 <dir> use whole line as input file path.
- path = ctx.copy(line);
- }
- if (!ctx.pathExists(path)) {
- return llvm::make_error<GenericError>(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_lower("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::ParseCommandLineOptions(numArgs + 1, args);
- }
-}
-
-namespace lld {
-namespace mach_o {
-
-bool parse(llvm::ArrayRef<const char *> 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 <path> 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<StringRef> 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 <file>
- for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) {
- if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
- error("-exported_symbols_list cannot be combined with "
- "-unexported_symbol[s_list]");
- return false;
- }
- ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
- if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
- error(ec.message() + ", processing '-exported_symbols_list " +
- expFile->getValue());
- return false;
- }
- }
-
- // Handle -exported_symbol <symbol>
- for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) {
- if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
- error("-exported_symbol cannot be combined with "
- "-unexported_symbol[s_list]");
- return false;
- }
- ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
- ctx.addExportSymbol(symbol->getValue());
- }
-
- // Handle -unexported_symbols_list <file>
- for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) {
- if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
- error("-unexported_symbols_list cannot be combined with "
- "-exported_symbol[s_list]");
- return false;
- }
- ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
- if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
- error(ec.message() + ", processing '-unexported_symbols_list " +
- expFile->getValue());
- return false;
- }
- }
-
- // Handle -unexported_symbol <symbol>
- for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) {
- if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
- error("-unexported_symbol cannot be combined with "
- "-exported_symbol[s_list]");
- return false;
- }
- ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
- 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 exectuables 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 exectuables 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 exectuables 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 an 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 <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 <path>
- 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<StringRef> 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<std::unique_ptr<MemoryBuffer>> 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<std::unique_ptr<File>> 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(), llvm::make_unique<FileNode>(std::move(*i)));
- }
-}
-
-/// This is where the link is actually performed.
-bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
- raw_ostream &Error) {
- errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
- errorHandler().ErrorLimitExceededMsg =
- "too many errors emitted, stopping now (use "
- "'-error-limit 0' to see all errors)";
- errorHandler().ErrorOS = &Error;
- errorHandler().ExitEarly = CanExitEarly;
- errorHandler().ColorDiagnostics = Error.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<Node> &ie : ctx.getNodes())
- if (FileNode *node = dyn_cast<FileNode>(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<SimpleFile> mergedFile = resolver.resultFile();
- merged = mergedFile.get();
- auto &members = ctx.getNodes();
- members.insert(members.begin(),
- llvm::make_unique<FileNode>(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.
- *errorHandler().ErrorOS << "Failed to run passes on file '"
- << ctx.outputPath() << "': ";
- logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
- 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.
- *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath()
- << "': ";
- logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
- 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