diff options
Diffstat (limited to 'lib/Driver')
| -rw-r--r-- | lib/Driver/CMakeLists.txt | 21 | ||||
| -rw-r--r-- | lib/Driver/CoreDriver.cpp | 173 | ||||
| -rw-r--r-- | lib/Driver/CoreOptions.td | 15 | ||||
| -rw-r--r-- | lib/Driver/DarwinLdDriver.cpp | 387 | ||||
| -rw-r--r-- | lib/Driver/DarwinLdOptions.td | 35 | ||||
| -rw-r--r-- | lib/Driver/Driver.cpp | 142 | ||||
| -rw-r--r-- | lib/Driver/GnuLdDriver.cpp | 782 | ||||
| -rw-r--r-- | lib/Driver/GnuLdOptions.td | 378 | ||||
| -rw-r--r-- | lib/Driver/TODO.rst | 99 | ||||
| -rw-r--r-- | lib/Driver/UniversalDriver.cpp | 225 | ||||
| -rw-r--r-- | lib/Driver/UniversalDriverOptions.td | 19 |
11 files changed, 380 insertions, 1896 deletions
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 840ccce50ab3..1bd1f2125816 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -1,19 +1,9 @@ -set(LLVM_TARGET_DEFINITIONS UniversalDriverOptions.td) -tablegen(LLVM UniversalDriverOptions.inc -gen-opt-parser-defs) -set(LLVM_TARGET_DEFINITIONS GnuLdOptions.td) -tablegen(LLVM GnuLdOptions.inc -gen-opt-parser-defs) -set(LLVM_TARGET_DEFINITIONS CoreOptions.td) -tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs) set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td) tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs) add_public_tablegen_target(DriverOptionsTableGen) add_lld_library(lldDriver - CoreDriver.cpp DarwinLdDriver.cpp - Driver.cpp - GnuLdDriver.cpp - UniversalDriver.cpp ADDITIONAL_HEADER_DIRS ${LLD_INCLUDE_DIR}/lld/Driver @@ -21,16 +11,6 @@ add_lld_library(lldDriver LINK_LIBS lldConfig lldMachO - lldCOFF - lldELF - lldELF2 - lldAArch64ELFTarget - lldARMELFTarget - lldHexagonELFTarget - lldMipsELFTarget - lldX86ELFTarget - lldExampleSubTarget - lldX86_64ELFTarget lldCore lldReaderWriter lldYAML @@ -40,4 +20,3 @@ add_lld_library(lldDriver ) add_dependencies(lldDriver DriverOptionsTableGen) - diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp deleted file mode 100644 index ce8648595109..000000000000 --- a/lib/Driver/CoreDriver.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//===- lib/Driver/CoreDriver.cpp ------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/Reader.h" -#include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/CoreLinkingContext.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; - -namespace { - -// Create enum with OPT_xxx values for each option in CoreOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, -#include "CoreOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in CoreOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "CoreOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in CoreOptions.td -static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, -#include "CoreOptions.inc" -#undef OPTION -}; - -// Create OptTable class for parsing actual command line arguments -class CoreOptTable : public llvm::opt::OptTable { -public: - CoreOptTable() : OptTable(infoTable) {} -}; - -} // namespace anonymous - - -namespace lld { - -static const Registry::KindStrings coreKindStrings[] = { - { CoreLinkingContext::TEST_RELOC_CALL32, "call32" }, - { CoreLinkingContext::TEST_RELOC_PCREL32, "pcrel32" }, - { CoreLinkingContext::TEST_RELOC_GOT_LOAD32, "gotLoad32" }, - { CoreLinkingContext::TEST_RELOC_GOT_USE32, "gotUse32" }, - { CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT, "lea32wasGot" }, - LLD_KIND_STRING_END -}; - -bool CoreDriver::link(llvm::ArrayRef<const char *> args, - raw_ostream &diagnostics) { - CoreLinkingContext ctx; - - // Register possible input file parsers. - ctx.registry().addSupportYamlFiles(); - ctx.registry().addKindTable(Reference::KindNamespace::testing, - Reference::KindArch::all, coreKindStrings); - - if (!parse(args, ctx)) - return false; - return Driver::link(ctx); -} - -bool CoreDriver::parse(llvm::ArrayRef<const char *> args, - CoreLinkingContext &ctx, raw_ostream &diagnostics) { - // Parse command line options using CoreOptions.td - CoreOptTable table; - unsigned missingIndex; - unsigned missingCount; - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; - return false; - } - - // Set default options - ctx.setOutputPath("-"); - ctx.setDeadStripping(false); - ctx.setGlobalsAreDeadStripRoots(false); - ctx.setPrintRemainingUndefines(false); - ctx.setAllowRemainingUndefines(true); - ctx.setSearchArchivesToOverrideTentativeDefinitions(false); - - // Process all the arguments and create input files. - for (auto inputArg : parsedArgs) { - switch (inputArg->getOption().getID()) { - case OPT_mllvm: - ctx.appendLLVMOption(inputArg->getValue()); - break; - - case OPT_entry: - ctx.setEntrySymbolName(inputArg->getValue()); - break; - - case OPT_output: - ctx.setOutputPath(inputArg->getValue()); - break; - - case OPT_dead_strip: - ctx.setDeadStripping(true); - break; - - case OPT_keep_globals: - ctx.setGlobalsAreDeadStripRoots(true); - break; - - case OPT_undefines_are_errors: - ctx.setPrintRemainingUndefines(true); - ctx.setAllowRemainingUndefines(false); - break; - - case OPT_commons_search_archives: - ctx.setSearchArchivesToOverrideTentativeDefinitions(true); - break; - - case OPT_add_pass: - ctx.addPassNamed(inputArg->getValue()); - break; - - case OPT_INPUT: { - std::vector<std::unique_ptr<File>> files - = loadFile(ctx, inputArg->getValue(), false); - for (std::unique_ptr<File> &file : files) - ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); - break; - } - - default: - break; - } - } - - parseLLVMOptions(ctx); - - if (ctx.getNodes().empty()) { - diagnostics << "No input files\n"; - return false; - } - - // Validate the combination of options used. - return ctx.validate(diagnostics); -} - -} // namespace lld diff --git a/lib/Driver/CoreOptions.td b/lib/Driver/CoreOptions.td deleted file mode 100644 index df7cb41737d2..000000000000 --- a/lib/Driver/CoreOptions.td +++ /dev/null @@ -1,15 +0,0 @@ -include "llvm/Option/OptParser.td" - -def output : Separate<["-"], "o">; -def entry : Separate<["-"], "e">; - -def dead_strip : Flag<["--"], "dead-strip">; -def undefines_are_errors : Flag<["--"], "undefines-are-errors">; -def keep_globals : Flag<["--"], "keep-globals">; -def commons_search_archives : Flag<["--"], "commons-search-archives">; - -def add_pass : Separate<["--"], "add-pass">; - -def target : Separate<["-"], "target">, HelpText<"Target triple to link for">; -def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; - diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp index 40fad74c9529..496b651bab4f 100644 --- a/lib/Driver/DarwinLdDriver.cpp +++ b/lib/Driver/DarwinLdDriver.cpp @@ -13,8 +13,11 @@ /// //===----------------------------------------------------------------------===// -#include "lld/Core/File.h" #include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" +#include "lld/Core/PassManager.h" +#include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Driver/Driver.h" #include "lld/ReaderWriter/MachOLinkingContext.h" @@ -25,17 +28,10 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> using namespace lld; @@ -72,6 +68,25 @@ 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, raw_ostream &diag, bool wholeArchive, bool upwardDylib) { @@ -215,9 +230,9 @@ static std::error_code parseOrderFile(StringRef orderFilePath, // 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 std::error_code loadFileList(StringRef fileListPath, - MachOLinkingContext &ctx, bool forceLoad, - raw_ostream &diagnostics) { +static llvm::Error loadFileList(StringRef fileListPath, + MachOLinkingContext &ctx, bool forceLoad, + raw_ostream &diagnostics) { // If there is a comma, split off <dir>. std::pair<StringRef, StringRef> opt = fileListPath.split(','); StringRef filePath = opt.first; @@ -227,7 +242,7 @@ static std::error_code loadFileList(StringRef fileListPath, ErrorOr<std::unique_ptr<MemoryBuffer>> mb = MemoryBuffer::getFileOrSTDIN(filePath); if (std::error_code ec = mb.getError()) - return ec; + return llvm::errorCodeToError(ec); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. @@ -245,9 +260,9 @@ static std::error_code loadFileList(StringRef fileListPath, path = ctx.copy(line); } if (!ctx.pathExists(path)) { - return make_dynamic_error_code(Twine("File not found '") - + path - + "'"); + return llvm::make_error<GenericError>(Twine("File not found '") + + path + + "'"); } if (ctx.testingFileUsage()) { diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; @@ -255,7 +270,7 @@ static std::error_code loadFileList(StringRef fileListPath, addFile(path, ctx, forceLoad, false, diagnostics); buffer = lineAndRest.second; } - return std::error_code(); + return llvm::Error(); } /// Parse number assuming it is base 16, but allow 0x prefix. @@ -265,20 +280,24 @@ static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { return numStr.getAsInteger(16, baseAddress); } -namespace lld { - -bool DarwinLdDriver::linkMachO(llvm::ArrayRef<const char *> args, - raw_ostream &diagnostics) { - MachOLinkingContext ctx; - if (!parse(args, ctx, diagnostics)) - return false; - if (ctx.doNothing()) - return true; - return link(ctx, diagnostics); +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); + } } -bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, - MachOLinkingContext &ctx, raw_ostream &diagnostics) { +namespace lld { +namespace mach_o { + +bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, + raw_ostream &diagnostics) { // Parse command line options using DarwinLdOptions.td DarwinLdOptTable table; unsigned missingIndex; @@ -299,6 +318,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // 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()) { @@ -313,6 +333,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, break; case OPT_static: fileType = llvm::MachO::MH_EXECUTE; + isStaticExecutable = true; break; case OPT_preload: fileType = llvm::MachO::MH_PRELOAD; @@ -350,7 +371,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } // Handle -macosx_version_min or -ios_version_min - MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX; + 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, @@ -385,9 +406,16 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // 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); + ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols); // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry)) @@ -673,6 +701,22 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } } + // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only + if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { + diagnostics << "error: -objc_gc_compaction is not supported\n"; + return false; + } + + if (parsedArgs.getLastArg(OPT_objc_gc)) { + diagnostics << "error: -objc_gc is not supported\n"; + return false; + } + + if (parsedArgs.getLastArg(OPT_objc_gc_only)) { + diagnostics << "error: -objc_gc_only is not supported\n"; + return false; + } + // Handle -pie or -no_pie if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) { switch (ctx.outputMachOType()) { @@ -719,6 +763,182 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, } } + // 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)) { + diagnostics << "error: malformed sdkVersion value\n"; + 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. + diagnostics << "warning: -sdk_version is required when emitting " + "min version load command. " + "Setting sdk version to match provided min version\n"; + 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)) { + diagnostics << "error: malformed source_version value\n"; + return false; + } + ctx.setSourceVersion(version); + } + // Handle stack_size if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { uint64_t stackSizeVal; @@ -794,6 +1014,10 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, 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()) { @@ -829,7 +1053,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, // Handle input files and sectcreate. for (auto &arg : parsedArgs) { bool upward; - ErrorOr<StringRef> resolvedPath = StringRef(); + llvm::Optional<StringRef> resolvedPath; switch (arg->getOption().getID()) { default: continue; @@ -852,9 +1076,10 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "library " - << canonicalizePath(resolvedPath.get()) << '\n'; + << canonicalizePath(resolvedPath.getValue()) << '\n'; } - addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, + upward, diagnostics); break; case OPT_framework: case OPT_upward_framework: @@ -866,17 +1091,20 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "framework " - << canonicalizePath(resolvedPath.get()) << '\n'; + << canonicalizePath(resolvedPath.getValue()) << '\n'; } - addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics); + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, + upward, diagnostics); break; case OPT_filelist: - if (std::error_code ec = loadFileList(arg->getValue(), - ctx, globalWholeArchive, - diagnostics)) { - diagnostics << "error: " << ec.message() - << ", processing '-filelist " << arg->getValue() - << "'\n"; + if (auto ec = loadFileList(arg->getValue(), + ctx, globalWholeArchive, + diagnostics)) { + handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { + diagnostics << "error: "; + EI.log(diagnostics); + diagnostics << ", processing '-filelist " << arg->getValue() << "'\n"; + }); return false; } break; @@ -908,5 +1136,80 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args, return ctx.validate(diagnostics); } +/// This is where the link is actually performed. +bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (!parse(args, ctx, diagnostics)) + 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(); + + std::vector<std::unique_ptr<File>> internalFiles; + ctx.createInternalFiles(internalFiles); + for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); + } + + // Give target a chance to add files. + std::vector<std::unique_ptr<File>> implicitFiles; + ctx.createImplicitFiles(implicitFiles); + for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); + } + + // 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. + diagnostics << "Failed to run passes on file '" << ctx.outputPath() + << "': "; + logAllUnhandledErrors(std::move(ec), diagnostics, 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. + diagnostics << "Failed to write file '" << ctx.outputPath() << "': "; + logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + return false; + } + + return true; +} +} // namespace mach_o } // namespace lld diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td index cbf6ac1d4a4b..fa07f33646e7 100644 --- a/lib/Driver/DarwinLdOptions.td +++ b/lib/Driver/DarwinLdOptions.td @@ -33,6 +33,28 @@ def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">, def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">, MetaVarName<"<version>">, HelpText<"Minimum iOS simulator version">, Group<grp_opts>; +def sdk_version : Separate<["-"], "sdk_version">, + MetaVarName<"<version>">, + HelpText<"SDK version">, Group<grp_opts>; +def source_version : Separate<["-"], "source_version">, + MetaVarName<"<version>">, + HelpText<"Source version">, Group<grp_opts>; +def version_load_command : Flag<["-"], "version_load_command">, + HelpText<"Force generation of a version load command">, Group<grp_opts>; +def no_version_load_command : Flag<["-"], "no_version_load_command">, + HelpText<"Disable generation of a version load command">, Group<grp_opts>; +def function_starts : Flag<["-"], "function_starts">, + HelpText<"Force generation of a function starts load command">, + Group<grp_opts>; +def no_function_starts : Flag<["-"], "no_function_starts">, + HelpText<"Disable generation of a function starts load command">, + Group<grp_opts>; +def data_in_code_info : Flag<["-"], "data_in_code_info">, + HelpText<"Force generation of a data in code load command">, + Group<grp_opts>; +def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">, + HelpText<"Disable generation of a data in code load command">, + Group<grp_opts>; def mllvm : Separate<["-"], "mllvm">, MetaVarName<"<option>">, HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>; @@ -68,6 +90,10 @@ def undefined : Separate<["-"], "undefined">, MetaVarName<"<undefined>">, HelpText<"Determines how undefined symbols are handled.">, Group<grp_opts>; +def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">, + HelpText<"Disables the optimisation which merges Objective-C categories " + "on a class in to the class itself.">, + Group<grp_opts>; // main executable options def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">; @@ -84,6 +110,9 @@ def stack_size : Separate<["-"], "stack_size">, HelpText<"Specifies the maximum stack size for the main thread in a program. " "Must be a page-size multiple. (default=8Mb)">, Group<grp_main>; +def export_dynamic : Flag<["-"], "export_dynamic">, + HelpText<"Preserves all global symbols in main executables during LTO">, + Group<grp_main>; // dylib executable options def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">; @@ -205,3 +234,9 @@ def single_module : Flag<["-"], "single_module">, HelpText<"Default for dylibs">, Group<grp_obsolete>; def multi_module : Flag<["-"], "multi_module">, HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>; +def objc_gc_compaction : Flag<["-"], "objc_gc_compaction">, + HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>; +def objc_gc : Flag<["-"], "objc_gc">, + HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>; +def objc_gc_only : Flag<["-"], "objc_gc_only">, + HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp deleted file mode 100644 index 6a7a26b3b0f6..000000000000 --- a/lib/Driver/Driver.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//===- lib/Driver/Driver.cpp - Linker Driver Emulator -----------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/File.h" -#include "lld/Core/Instrumentation.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/Parallel.h" -#include "lld/Core/PassManager.h" -#include "lld/Core/Reader.h" -#include "lld/Core/Resolver.h" -#include "lld/Core/Writer.h" -#include "lld/Driver/Driver.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Option/Arg.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" -#include <mutex> - -namespace lld { - -FileVector 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; -} - -FileVector 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; -} - -FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) { - ErrorOr<std::unique_ptr<MemoryBuffer>> mb - = MemoryBuffer::getFileOrSTDIN(path); - if (std::error_code ec = mb.getError()) - return makeErrorFile(path, ec); - ErrorOr<std::unique_ptr<File>> fileOrErr = - ctx.registry().loadFile(std::move(mb.get())); - if (std::error_code ec = fileOrErr.getError()) - return makeErrorFile(path, ec); - std::unique_ptr<File> &file = fileOrErr.get(); - if (wholeArchive) - return parseMemberFiles(std::move(file)); - std::vector<std::unique_ptr<File>> files; - files.push_back(std::move(file)); - return files; -} - -void Driver::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); - } -} - -/// This is where the link is actually performed. -bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) { - if (ctx.getNodes().empty()) - return false; - - for (std::unique_ptr<Node> &ie : ctx.getNodes()) - if (FileNode *node = dyn_cast<FileNode>(ie.get())) - ctx.getTaskGroup().spawn([node] { node->getFile()->parse(); }); - - std::vector<std::unique_ptr<File>> internalFiles; - ctx.createInternalFiles(internalFiles); - for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); - } - - // Give target a chance to add files. - std::vector<std::unique_ptr<File>> implicitFiles; - ctx.createImplicitFiles(implicitFiles); - for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i))); - } - - // Give target a chance to postprocess input files. - // Mach-O uses this chance to move all object files before library files. - // ELF adds specific undefined symbols resolver. - ctx.finalizeInputFiles(); - - // Do core linking. - ScopedTask resolveTask(getDefaultDomain(), "Resolve"); - Resolver resolver(ctx); - if (!resolver.resolve()) { - ctx.getTaskGroup().sync(); - return false; - } - std::unique_ptr<SimpleFile> merged = resolver.resultFile(); - resolveTask.end(); - - // Run passes on linked atoms. - ScopedTask passTask(getDefaultDomain(), "Passes"); - PassManager pm; - ctx.addPasses(pm); - if (std::error_code ec = pm.runOnFile(*merged)) { - diagnostics << "Failed to write file '" << ctx.outputPath() - << "': " << ec.message() << "\n"; - return false; - } - - passTask.end(); - - // Give linked atoms to Writer to generate output file. - ScopedTask writeTask(getDefaultDomain(), "Write"); - if (std::error_code ec = ctx.writeFile(*merged)) { - diagnostics << "Failed to write file '" << ctx.outputPath() - << "': " << ec.message() << "\n"; - return false; - } - - return true; -} - -} // namespace lld diff --git a/lib/Driver/GnuLdDriver.cpp b/lib/Driver/GnuLdDriver.cpp deleted file mode 100644 index 1cff481dd8d7..000000000000 --- a/lib/Driver/GnuLdDriver.cpp +++ /dev/null @@ -1,782 +0,0 @@ -//===- lib/Driver/GnuLdDriver.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 GNU's ld. -/// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "lld/ReaderWriter/LinkerScript.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" -#include <cstring> -#include <tuple> - -using namespace lld; - -using llvm::BumpPtrAllocator; - -namespace { - -// Create enum with OPT_xxx values for each option in GnuLdOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, -#include "GnuLdOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in GnuLdOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "GnuLdOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in GnuLdOptions.td -static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, -#include "GnuLdOptions.inc" -#undef OPTION -}; - - -// Create OptTable class for parsing actual command line arguments -class GnuLdOptTable : public llvm::opt::OptTable { -public: - GnuLdOptTable() : OptTable(infoTable){} -}; - -} // anonymous namespace - -// If a command line option starts with "@", the driver reads its suffix as a -// file, parse its contents as a list of command line options, and insert them -// at the original @file position. If file cannot be read, @file is not expanded -// and left unmodified. @file can appear in a response file, so it's a recursive -// process. -static llvm::ArrayRef<const char *> -maybeExpandResponseFiles(llvm::ArrayRef<const char *> args, - BumpPtrAllocator &alloc) { - // Expand response files. - SmallVector<const char *, 256> smallvec; - for (const char *arg : args) - smallvec.push_back(arg); - llvm::StringSaver saver(alloc); - llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec); - - // Pack the results to a C-array and return it. - const char **copy = alloc.Allocate<const char *>(smallvec.size() + 1); - std::copy(smallvec.begin(), smallvec.end(), copy); - copy[smallvec.size()] = nullptr; - return llvm::makeArrayRef(copy, smallvec.size() + 1); -} - -// Parses an argument of --defsym=<sym>=<number> -static bool parseDefsymAsAbsolute(StringRef opt, StringRef &sym, - uint64_t &addr) { - size_t equalPos = opt.find('='); - if (equalPos == 0 || equalPos == StringRef::npos) - return false; - sym = opt.substr(0, equalPos); - if (opt.substr(equalPos + 1).getAsInteger(0, addr)) - return false; - return true; -} - -// Parses an argument of --defsym=<sym>=<sym> -static bool parseDefsymAsAlias(StringRef opt, StringRef &sym, - StringRef &target) { - size_t equalPos = opt.find('='); - if (equalPos == 0 || equalPos == StringRef::npos) - return false; - sym = opt.substr(0, equalPos); - target = opt.substr(equalPos + 1); - return !target.empty(); -} - -// Parses -z max-page-size=<value> -static bool parseMaxPageSize(StringRef opt, uint64_t &val) { - size_t equalPos = opt.find('='); - if (equalPos == 0 || equalPos == StringRef::npos) - return false; - StringRef value = opt.substr(equalPos + 1); - val = 0; - if (value.getAsInteger(0, val) || !val) - return false; - return true; -} - -bool GnuLdDriver::linkELF(llvm::ArrayRef<const char *> args, - raw_ostream &diag) { - BumpPtrAllocator alloc; - args = maybeExpandResponseFiles(args, alloc); - std::unique_ptr<ELFLinkingContext> options; - if (!parse(args, options, diag)) - return false; - if (!options) - return true; - bool linked = link(*options, diag); - - // Handle --stats. - if (options->collectStats()) { - llvm::TimeRecord t = llvm::TimeRecord::getCurrentTime(true); - diag << "total time in link " << t.getProcessTime() << "\n"; - diag << "data size " << t.getMemUsed() << "\n"; - } - return linked; -} - -static llvm::Optional<llvm::Triple::ArchType> -getArchType(const llvm::Triple &triple, StringRef value) { - switch (triple.getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (value == "elf_i386") - return llvm::Triple::x86; - if (value == "elf_x86_64") - return llvm::Triple::x86_64; - return llvm::None; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - return llvm::StringSwitch<llvm::Optional<llvm::Triple::ArchType>>(value) - .Cases("elf32btsmip", "elf32btsmipn32", llvm::Triple::mips) - .Cases("elf32ltsmip", "elf32ltsmipn32", llvm::Triple::mipsel) - .Case("elf64btsmip", llvm::Triple::mips64) - .Case("elf64ltsmip", llvm::Triple::mips64el) - .Default(llvm::None); - case llvm::Triple::aarch64: - if (value == "aarch64linux") - return llvm::Triple::aarch64; - return llvm::None; - case llvm::Triple::arm: - if (value == "armelf_linux_eabi") - return llvm::Triple::arm; - return llvm::None; - default: - return llvm::None; - } -} - -static bool isLinkerScript(StringRef path, raw_ostream &diag) { - llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown; - if (std::error_code ec = llvm::sys::fs::identify_magic(path, magic)) { - diag << "unknown input file format: " << path << ": " - << ec.message() << "\n"; - return false; - } - return magic == llvm::sys::fs::file_magic::unknown; -} - -static ErrorOr<StringRef> -findFile(ELFLinkingContext &ctx, StringRef path, bool dashL) { - // If the path was referred to by using a -l argument, let's search - // for the file in the search path. - if (dashL) { - ErrorOr<StringRef> pathOrErr = ctx.searchLibrary(path); - if (std::error_code ec = pathOrErr.getError()) - return make_dynamic_error_code( - Twine("Unable to find library -l") + path + ": " + ec.message()); - path = pathOrErr.get(); - } - if (!llvm::sys::fs::exists(path)) - return make_dynamic_error_code( - Twine("lld: cannot find file ") + path); - return path; -} - -static bool isPathUnderSysroot(StringRef sysroot, StringRef path) { - if (sysroot.empty()) - return false; - while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path)) - path = llvm::sys::path::parent_path(path); - return !path.empty(); -} - -static std::error_code -addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath, - const std::vector<script::Path> &inputPaths, - raw_ostream &diag) { - bool sysroot = (!ctx.getSysroot().empty() - && isPathUnderSysroot(ctx.getSysroot(), scriptPath)); - for (const script::Path &path : inputPaths) { - ErrorOr<StringRef> pathOrErr = path._isDashlPrefix - ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot); - if (std::error_code ec = pathOrErr.getError()) { - auto file = llvm::make_unique<ErrorFile>(path._path, ec); - ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); - continue; - } - - std::vector<std::unique_ptr<File>> files - = loadFile(ctx, pathOrErr.get(), false); - for (std::unique_ptr<File> &file : files) { - if (ctx.logInputFiles()) - diag << file->path() << "\n"; - ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); - } - } - return std::error_code(); -} - -std::error_code GnuLdDriver::evalLinkerScript(ELFLinkingContext &ctx, - std::unique_ptr<MemoryBuffer> mb, - raw_ostream &diag, - bool nostdlib) { - // Read the script file from disk and parse. - StringRef path = mb->getBufferIdentifier(); - auto parser = llvm::make_unique<script::Parser>(std::move(mb)); - if (std::error_code ec = parser->parse()) - return ec; - script::LinkerScript *script = parser->get(); - if (!script) - return LinkerScriptReaderError::parse_error; - // Evaluate script commands. - // Currently we only recognize this subset of linker script commands. - for (const script::Command *c : script->_commands) { - if (auto *input = dyn_cast<script::Input>(c)) - if (std::error_code ec = addFilesFromLinkerScript( - ctx, path, input->getPaths(), diag)) - return ec; - if (auto *group = dyn_cast<script::Group>(c)) { - int origSize = ctx.getNodes().size(); - if (std::error_code ec = addFilesFromLinkerScript( - ctx, path, group->getPaths(), diag)) - return ec; - size_t groupSize = ctx.getNodes().size() - origSize; - ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(groupSize)); - } - if (auto *searchDir = dyn_cast<script::SearchDir>(c)) - if (!nostdlib) - ctx.addSearchPath(searchDir->getSearchPath()); - if (auto *entry = dyn_cast<script::Entry>(c)) - ctx.setEntrySymbolName(entry->getEntryName()); - if (auto *output = dyn_cast<script::Output>(c)) - ctx.setOutputPath(output->getOutputFileName()); - if (auto *externs = dyn_cast<script::Extern>(c)) { - for (auto symbol : *externs) { - ctx.addInitialUndefinedSymbol(symbol); - } - } - } - // Transfer ownership of the script to the linking context - ctx.linkerScriptSema().addLinkerScript(std::move(parser)); - return std::error_code(); -} - -bool GnuLdDriver::applyEmulation(llvm::Triple &triple, - llvm::opt::InputArgList &args, - raw_ostream &diag) { - llvm::opt::Arg *arg = args.getLastArg(OPT_m); - if (!arg) - return true; - llvm::Optional<llvm::Triple::ArchType> arch = - getArchType(triple, arg->getValue()); - if (!arch) { - diag << "error: unsupported emulation '" << arg->getValue() << "'.\n"; - return false; - } - triple.setArch(*arch); - return true; -} - -void GnuLdDriver::addPlatformSearchDirs(ELFLinkingContext &ctx, - llvm::Triple &triple, - llvm::Triple &baseTriple) { - if (triple.getOS() == llvm::Triple::NetBSD && - triple.getArch() == llvm::Triple::x86 && - baseTriple.getArch() == llvm::Triple::x86_64) { - ctx.addSearchPath("=/usr/lib/i386"); - return; - } - ctx.addSearchPath("=/usr/lib"); -} - -std::unique_ptr<ELFLinkingContext> -GnuLdDriver::createELFLinkingContext(llvm::Triple triple) { - std::unique_ptr<ELFLinkingContext> p; - if ((p = elf::createAArch64LinkingContext(triple))) return p; - if ((p = elf::createARMLinkingContext(triple))) return p; - if ((p = elf::createExampleLinkingContext(triple))) return p; - if ((p = elf::createHexagonLinkingContext(triple))) return p; - if ((p = elf::createMipsLinkingContext(triple))) return p; - if ((p = elf::createX86LinkingContext(triple))) return p; - if ((p = elf::createX86_64LinkingContext(triple))) return p; - return nullptr; -} - -static llvm::Optional<bool> -getBool(const llvm::opt::InputArgList &parsedArgs, - unsigned yesFlag, unsigned noFlag) { - if (auto *arg = parsedArgs.getLastArg(yesFlag, noFlag)) - return arg->getOption().getID() == yesFlag; - return llvm::None; -} - -bool GnuLdDriver::parse(llvm::ArrayRef<const char *> args, - std::unique_ptr<ELFLinkingContext> &context, - raw_ostream &diag) { - // Parse command line options using GnuLdOptions.td - GnuLdOptTable table; - unsigned missingIndex; - unsigned missingCount; - - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - if (missingCount) { - diag << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; - return false; - } - - // Handle --help - if (parsedArgs.hasArg(OPT_help)) { - table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false); - return true; - } - - // Use -target or use default target triple to instantiate LinkingContext - llvm::Triple baseTriple; - if (auto *arg = parsedArgs.getLastArg(OPT_target)) { - baseTriple = llvm::Triple(arg->getValue()); - } else { - baseTriple = getDefaultTarget(args[0]); - } - llvm::Triple triple(baseTriple); - - if (!applyEmulation(triple, parsedArgs, diag)) - return false; - - std::unique_ptr<ELFLinkingContext> ctx(createELFLinkingContext(triple)); - - if (!ctx) { - diag << "unknown target triple\n"; - return false; - } - - // Copy mllvm - for (auto *arg : parsedArgs.filtered(OPT_mllvm)) - ctx->appendLLVMOption(arg->getValue()); - - // Ignore unknown arguments. - for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) - diag << "warning: ignoring unknown argument: " - << unknownArg->getValue() << "\n"; - - // Set sys root path. - if (auto *arg = parsedArgs.getLastArg(OPT_sysroot)) - ctx->setSysroot(arg->getValue()); - - // Handle --demangle option(For compatibility) - if (parsedArgs.hasArg(OPT_demangle)) - ctx->setDemangleSymbols(true); - - // Handle --no-demangle option. - if (parsedArgs.hasArg(OPT_no_demangle)) - ctx->setDemangleSymbols(false); - - // Figure out output kind (-r, -static, -shared) - if (parsedArgs.hasArg(OPT_relocatable)) { - ctx->setOutputELFType(llvm::ELF::ET_REL); - ctx->setPrintRemainingUndefines(false); - ctx->setAllowRemainingUndefines(true); - } - - if (parsedArgs.hasArg(OPT_static)) { - ctx->setOutputELFType(llvm::ELF::ET_EXEC); - ctx->setIsStaticExecutable(true); - } - - if (parsedArgs.hasArg(OPT_shared)) { - ctx->setOutputELFType(llvm::ELF::ET_DYN); - ctx->setAllowShlibUndefines(true); - ctx->setUseShlibUndefines(false); - ctx->setPrintRemainingUndefines(false); - ctx->setAllowRemainingUndefines(true); - } - - // Handle --stats. - if (parsedArgs.hasArg(OPT_stats)) { - ctx->setCollectStats(true); - } - - // Figure out if the output type is nmagic/omagic - if (auto *arg = - parsedArgs.getLastArg(OPT_nmagic, OPT_omagic, OPT_no_omagic)) { - switch (arg->getOption().getID()) { - case OPT_nmagic: - ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC); - ctx->setIsStaticExecutable(true); - break; - case OPT_omagic: - ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC); - ctx->setIsStaticExecutable(true); - break; - case OPT_no_omagic: - ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT); - ctx->setNoAllowDynamicLibraries(); - break; - } - } - - if (parsedArgs.hasArg(OPT_discard_loc)) - ctx->setDiscardLocals(true); - - if (parsedArgs.hasArg(OPT_discard_temp_loc)) - ctx->setDiscardTempLocals(true); - - if (parsedArgs.hasArg(OPT_strip_all)) - ctx->setStripSymbols(true); - - if (auto *arg = parsedArgs.getLastArg(OPT_soname)) - ctx->setSharedObjectName(arg->getValue()); - - if (parsedArgs.hasArg(OPT_rosegment)) - ctx->setCreateSeparateROSegment(); - - if (parsedArgs.hasArg(OPT_no_align_segments)) - ctx->setAlignSegments(false); - - if (auto *arg = parsedArgs.getLastArg(OPT_image_base)) { - uint64_t baseAddress = 0; - StringRef inputValue = arg->getValue(); - if (inputValue.getAsInteger(0, baseAddress) || !baseAddress) { - diag << "invalid value for image base " << inputValue << "\n"; - return false; - } - ctx->setBaseAddress(baseAddress); - } - - if (parsedArgs.hasArg(OPT_merge_strings)) - ctx->setMergeCommonStrings(true); - - if (parsedArgs.hasArg(OPT_t)) - ctx->setLogInputFiles(true); - - if (parsedArgs.hasArg(OPT_use_shlib_undefs)) - ctx->setUseShlibUndefines(true); - - if (auto val = getBool(parsedArgs, OPT_allow_shlib_undefs, - OPT_no_allow_shlib_undefs)) - ctx->setAllowShlibUndefines(*val); - - if (auto *arg = parsedArgs.getLastArg(OPT_e)) - ctx->setEntrySymbolName(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_output)) - ctx->setOutputPath(arg->getValue()); - - if (parsedArgs.hasArg(OPT_noinhibit_exec)) - ctx->setAllowRemainingUndefines(true); - - if (auto val = getBool(parsedArgs, OPT_export_dynamic, OPT_no_export_dynamic)) - ctx->setExportDynamic(*val); - - if (parsedArgs.hasArg(OPT_allow_multiple_definition)) - ctx->setAllowDuplicates(true); - - if (auto *arg = parsedArgs.getLastArg(OPT_dynamic_linker)) - ctx->setInterpreter(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_init)) - ctx->setInitFunction(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_fini)) - ctx->setFiniFunction(arg->getValue()); - - if (auto *arg = parsedArgs.getLastArg(OPT_output_filetype)) - ctx->setOutputFileType(arg->getValue()); - - // Process ELF/ARM specific options - bool hasArmTarget1Rel = parsedArgs.hasArg(OPT_target1_rel); - bool hasArmTarget1Abs = parsedArgs.hasArg(OPT_target1_abs); - if (triple.getArch() == llvm::Triple::arm) { - if (hasArmTarget1Rel && hasArmTarget1Abs) { - diag << "error: options --target1-rel and --target1-abs" - " can't be used together.\n"; - return false; - } else if (hasArmTarget1Rel || hasArmTarget1Abs) { - ctx->setArmTarget1Rel(hasArmTarget1Rel && !hasArmTarget1Abs); - } - } else { - for (const auto *arg : parsedArgs.filtered(OPT_grp_arm_targetopts)) { - diag << "warning: ignoring unsupported ARM/ELF specific argument: " - << arg->getSpelling() << "\n"; - } - } - - // Process MIPS specific options. - if (triple.getArch() == llvm::Triple::mips || - triple.getArch() == llvm::Triple::mipsel || - triple.getArch() == llvm::Triple::mips64 || - triple.getArch() == llvm::Triple::mips64el) { - ctx->setMipsPcRelEhRel(parsedArgs.hasArg(OPT_pcrel_eh_reloc)); - auto *hashArg = parsedArgs.getLastArg(OPT_hash_style); - if (hashArg && hashArg->getValue() != StringRef("sysv")) { - diag << "error: .gnu.hash is incompatible with the MIPS ABI\n"; - return false; - } - } - else { - for (const auto *arg : parsedArgs.filtered(OPT_grp_mips_targetopts)) { - diag << "warning: ignoring unsupported MIPS specific argument: " - << arg->getSpelling() << "\n"; - } - } - - for (auto *arg : parsedArgs.filtered(OPT_L)) - ctx->addSearchPath(arg->getValue()); - - // Add the default search directory specific to the target. - if (!parsedArgs.hasArg(OPT_nostdlib)) - addPlatformSearchDirs(*ctx, triple, baseTriple); - - for (auto *arg : parsedArgs.filtered(OPT_u)) - ctx->addInitialUndefinedSymbol(arg->getValue()); - - for (auto *arg : parsedArgs.filtered(OPT_defsym)) { - StringRef sym, target; - uint64_t addr; - if (parseDefsymAsAbsolute(arg->getValue(), sym, addr)) { - ctx->addInitialAbsoluteSymbol(sym, addr); - } else if (parseDefsymAsAlias(arg->getValue(), sym, target)) { - ctx->addAlias(sym, target); - } else { - diag << "invalid --defsym: " << arg->getValue() << "\n"; - return false; - } - } - - for (auto *arg : parsedArgs.filtered(OPT_z)) { - StringRef opt = arg->getValue(); - if (opt == "muldefs") - ctx->setAllowDuplicates(true); - else if (opt == "now") - ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_NOW); - else if (opt == "origin") - ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN); - else if (opt.startswith("max-page-size")) { - // Parse -z max-page-size option. - // The default page size is considered the minimum page size the user - // can set, check the user input if its atleast the minimum page size - // and does not exceed the maximum page size allowed for the target. - uint64_t maxPageSize = 0; - - // Error if the page size user set is less than the maximum page size - // and greather than the default page size and the user page size is a - // modulo of the default page size. - if ((!parseMaxPageSize(opt, maxPageSize)) || - (maxPageSize < ctx->getPageSize()) || - (maxPageSize % ctx->getPageSize())) { - diag << "invalid option: " << opt << "\n"; - return false; - } - ctx->setMaxPageSize(maxPageSize); - } else { - diag << "warning: ignoring unknown argument for -z: " << opt << "\n"; - } - } - - for (auto *arg : parsedArgs.filtered(OPT_rpath)) { - SmallVector<StringRef, 2> rpaths; - StringRef(arg->getValue()).split(rpaths, ":"); - for (auto path : rpaths) - ctx->addRpath(path); - } - - for (auto *arg : parsedArgs.filtered(OPT_rpath_link)) { - SmallVector<StringRef, 2> rpaths; - StringRef(arg->getValue()).split(rpaths, ":"); - for (auto path : rpaths) - ctx->addRpathLink(path); - } - - // Enable new dynamic tags. - if (parsedArgs.hasArg(OPT_enable_newdtags)) - ctx->setEnableNewDtags(true); - - // Support --wrap option. - for (auto *arg : parsedArgs.filtered(OPT_wrap)) - ctx->addWrapForSymbol(arg->getValue()); - - // Register possible input file parsers. - ctx->registry().addSupportELFObjects(*ctx); - ctx->registry().addSupportArchives(ctx->logInputFiles()); - ctx->registry().addSupportYamlFiles(); - if (ctx->allowLinkWithDynamicLibraries()) - ctx->registry().addSupportELFDynamicSharedObjects(*ctx); - - // Parse the LLVM options before we process files in case the file handling - // makes use of things like DEBUG(). - parseLLVMOptions(*ctx); - - std::stack<int> groupStack; - int numfiles = 0; - bool asNeeded = false; - bool wholeArchive = false; - - // Process files - for (auto arg : parsedArgs) { - switch (arg->getOption().getID()) { - case OPT_no_whole_archive: - wholeArchive = false; - break; - - case OPT_whole_archive: - wholeArchive = true; - break; - - case OPT_as_needed: - asNeeded = true; - break; - - case OPT_no_as_needed: - asNeeded = false; - break; - - case OPT_start_group: - groupStack.push(numfiles); - break; - - case OPT_end_group: { - if (groupStack.empty()) { - diag << "stray --end-group\n"; - return false; - } - int startGroupPos = groupStack.top(); - ctx->getNodes().push_back( - llvm::make_unique<GroupEnd>(numfiles - startGroupPos)); - groupStack.pop(); - break; - } - - case OPT_INPUT: - case OPT_l: - case OPT_T: { - bool dashL = (arg->getOption().getID() == OPT_l); - StringRef path = arg->getValue(); - - ErrorOr<StringRef> pathOrErr = findFile(*ctx, path, dashL); - if (std::error_code ec = pathOrErr.getError()) { - auto file = llvm::make_unique<ErrorFile>(path, ec); - auto node = llvm::make_unique<FileNode>(std::move(file)); - node->setAsNeeded(asNeeded); - ctx->getNodes().push_back(std::move(node)); - break; - } - StringRef realpath = pathOrErr.get(); - - bool isScript = - (!path.endswith(".objtxt") && isLinkerScript(realpath, diag)); - if (isScript) { - if (ctx->logInputFiles()) - diag << path << "\n"; - ErrorOr<std::unique_ptr<MemoryBuffer>> mb = - MemoryBuffer::getFileOrSTDIN(realpath); - if (std::error_code ec = mb.getError()) { - diag << "Cannot open " << path << ": " << ec.message() << "\n"; - return false; - } - bool nostdlib = parsedArgs.hasArg(OPT_nostdlib); - std::error_code ec = - evalLinkerScript(*ctx, std::move(mb.get()), diag, nostdlib); - if (ec) { - diag << path << ": Error parsing linker script: " - << ec.message() << "\n"; - return false; - } - break; - } - std::vector<std::unique_ptr<File>> files - = loadFile(*ctx, realpath, wholeArchive); - for (std::unique_ptr<File> &file : files) { - if (ctx->logInputFiles()) - diag << file->path() << "\n"; - auto node = llvm::make_unique<FileNode>(std::move(file)); - node->setAsNeeded(asNeeded); - ctx->getNodes().push_back(std::move(node)); - } - numfiles += files.size(); - break; - } - } - } - - if (ctx->getNodes().empty()) { - diag << "No input files\n"; - return false; - } - - // Set default output file name if the output file was not specified. - if (ctx->outputPath().empty()) { - switch (ctx->outputFileType()) { - case LinkingContext::OutputFileType::YAML: - ctx->setOutputPath("-"); - break; - default: - ctx->setOutputPath("a.out"); - break; - } - } - - // Validate the combination of options used. - if (!ctx->validate(diag)) - return false; - - // Perform linker script semantic actions - if (auto ec = ctx->linkerScriptSema().perform()) { - diag << "Error in the linker script's semantics: " << ec.message() << "\n"; - return false; - } - - context.swap(ctx); - return true; -} - -/// Get the default target triple based on either the program name -/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for. -llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) { - SmallVector<StringRef, 4> components; - llvm::SplitString(llvm::sys::path::stem(progName), components, "-"); - // If has enough parts to be start with a triple. - if (components.size() >= 4) { - llvm::Triple triple(components[0], components[1], components[2], - components[3]); - // If first component looks like an arch. - if (triple.getArch() != llvm::Triple::UnknownArch) - return triple; - } - - // Fallback to use whatever default triple llvm was configured for. - return llvm::Triple(llvm::sys::getDefaultTargetTriple()); -} diff --git a/lib/Driver/GnuLdOptions.td b/lib/Driver/GnuLdOptions.td deleted file mode 100644 index 7d850d4d002e..000000000000 --- a/lib/Driver/GnuLdOptions.td +++ /dev/null @@ -1,378 +0,0 @@ -include "llvm/Option/OptParser.td" - -//===----------------------------------------------------------------------===// -/// Utility Functions -//===----------------------------------------------------------------------===// -// Single and multiple dash options combined -multiclass smDash<string opt1, string opt2, string help> { - // Option - def "" : Separate<["-"], opt1>, HelpText<help>; - def opt1_eq : Joined<["-"], opt1#"=">, - Alias<!cast<Option>(opt1)>; - // Compatibility aliases - def opt2_dashdash : Separate<["--"], opt2>, - Alias<!cast<Option>(opt1)>; - def opt2_dashdash_eq : Joined<["--"], opt2#"=">, - Alias<!cast<Option>(opt1)>; -} - -// Support -<option>,-<option>= -multiclass dashEq<string opt1, string opt2, string help> { - // Option - def "" : Separate<["-"], opt1>, HelpText<help>; - // Compatibility aliases - def opt2_eq : Joined<["-"], opt2#"=">, - Alias<!cast<Option>(opt1)>; -} - -// Support --<option>,--<option>= -multiclass mDashEq<string opt1, string help> { - // Option - def "" : Separate<["--"], opt1>, HelpText<help>; - // Compatibility aliases - def opt2_eq : Joined<["--"], opt1#"=">, - Alias<!cast<Option>(opt1)>; -} - -//===----------------------------------------------------------------------===// -/// LLVM and Target options -//===----------------------------------------------------------------------===// -def grp_llvmtarget : OptionGroup<"opts">, - HelpText<"LLVM and Target Options">; -def mllvm : Separate<["-"], "mllvm">, - HelpText<"Options to pass to LLVM">, Group<grp_llvmtarget>; -def target : Separate<["-"], "target">, MetaVarName<"<triple>">, - HelpText<"Target triple to link for">, - Group<grp_llvmtarget>; - -//===----------------------------------------------------------------------===// -/// Output Kinds -//===----------------------------------------------------------------------===// -def grp_kind : OptionGroup<"outs">, - HelpText<"OUTPUT KIND">; -def relocatable : Flag<["-"], "r">, - HelpText<"Create relocatable object file">, Group<grp_kind>; -def static : Flag<["-"], "static">, - HelpText<"Create static executable">, Group<grp_kind>; -def dynamic : Flag<["-"], "dynamic">, - HelpText<"Create dynamic executable (default)">,Group<grp_kind>; -def shared : Flag<["-"], "shared">, - HelpText<"Create dynamic library">, Group<grp_kind>; - -// output kinds - compatibility aliases -def Bstatic : Flag<["-"], "Bstatic">, Alias<static>; -def Bshareable : Flag<["-"], "Bshareable">, Alias<shared>; - -//===----------------------------------------------------------------------===// -/// General Options -//===----------------------------------------------------------------------===// -def grp_general : OptionGroup<"opts">, - HelpText<"GENERAL OPTIONS">; -def output : Separate<["-"], "o">, MetaVarName<"<path>">, - HelpText<"Path to file to write output">, - Group<grp_general>; -def m : JoinedOrSeparate<["-"], "m">, MetaVarName<"<emulation>">, - HelpText<"Select target emulation">, - Group<grp_general>; -def build_id : Flag<["--"], "build-id">, - HelpText<"Request creation of \".note.gnu.build-id\" ELF note section">, - Group<grp_general>; -def sysroot : Joined<["--"], "sysroot=">, - HelpText<"Set the system root">, - Group<grp_general>; - - -//===----------------------------------------------------------------------===// -/// Executable Options -//===----------------------------------------------------------------------===// -def grp_main : OptionGroup<"opts">, - HelpText<"EXECUTABLE OPTIONS">; -def L : Joined<["-"], "L">, MetaVarName<"<dir>">, - HelpText<"Directory to search for libraries">, - Group<grp_main>; -def l : Joined<["-"], "l">, MetaVarName<"<libName>">, - HelpText<"Root name of library to use">, - Group<grp_main>; -def noinhibit_exec : Flag<["--"], "noinhibit-exec">, - HelpText<"Retain the executable output file whenever" - " it is still usable">, - Group<grp_main>; -defm e : smDash<"e", "entry", - "Name of entry point symbol">, - Group<grp_main>; -defm init: dashEq<"init", "init", - "Specify an initializer function">, - Group<grp_main>; -defm fini: dashEq<"fini", "fini", - "Specify a finalizer function">, - Group<grp_main>; -def whole_archive: Flag<["--"], "whole-archive">, - HelpText<"Force load of all members in a static library">, - Group<grp_main>; -def no_whole_archive: Flag<["--"], "no-whole-archive">, - HelpText<"Restores the default behavior of loading archive members">, - Group<grp_main>; -def nostdlib : Flag<["-"], "nostdlib">, - HelpText<"Disable default search path for libraries">, - Group<grp_main>; -def image_base : Separate<["--"], "image-base">, - HelpText<"Set the base address">, - Group<grp_main>; - -//===----------------------------------------------------------------------===// -/// Static Executable Options -//===----------------------------------------------------------------------===// -def grp_staticexec : OptionGroup<"opts">, - HelpText<"STATIC EXECUTABLE OPTIONS">; -def nmagic : Flag<["--"], "nmagic">, - HelpText<"Turn off page alignment of sections," - " and disable linking against shared libraries">, - Group<grp_staticexec>; -def omagic : Flag<["--"], "omagic">, - HelpText<"Set the text and data sections to be readable and writable." - " Also, do not page-align the data segment, and" - " disable linking against shared libraries.">, - Group<grp_staticexec>; -def no_omagic : Flag<["--"], "no-omagic">, - HelpText<"This option negates most of the effects of the -N option." - "Disable linking with shared libraries">, - Group<grp_staticexec>; -// Compatible Aliases -def nmagic_alias : Flag<["-"], "n">, - Alias<nmagic>; -def omagic_alias : Flag<["-"], "N">, - Alias<omagic>; - -//===----------------------------------------------------------------------===// -/// Dynamic Library/Executable Options -//===----------------------------------------------------------------------===// -def grp_dynlibexec : OptionGroup<"opts">, - HelpText<"DYNAMIC LIBRARY/EXECUTABLE OPTIONS">; -def dynamic_linker : Joined<["--"], "dynamic-linker=">, - HelpText<"Set the path to the dynamic linker">, Group<grp_dynlibexec>; -// Executable options - compatibility aliases -def dynamic_linker_alias : Separate<["-", "--"], "dynamic-linker">, - Alias<dynamic_linker>; -defm rpath : dashEq<"rpath", "rpath", - "Add a directory to the runtime library search path">, - Group<grp_dynlibexec>; -def rpath_link : Separate<["-"], "rpath-link">, - HelpText<"Specifies the first set of directories to search">, - Group<grp_dynlibexec>; -def export_dynamic : Flag<["-", "--"], "export-dynamic">, - HelpText<"Add all symbols to the dynamic symbol table" - " when creating executables">, - Group<grp_main>; -def alias_export_dynamic: Flag<["-"], "E">, - Alias<export_dynamic>; -def no_export_dynamic : Flag<["--"], "no-export-dynamic">, - Group<grp_main>; - -//===----------------------------------------------------------------------===// -/// Dynamic Library Options -//===----------------------------------------------------------------------===// -def grp_dynlib : OptionGroup<"opts">, - HelpText<"DYNAMIC LIBRARY OPTIONS">; -def soname : Joined<["-", "--"], "soname=">, - HelpText<"Set the internal DT_SONAME field to the specified name">, - Group<grp_dynlib>; -def soname_separate : Separate<["-", "--"], "soname">, Alias<soname>; -def soname_h : Separate<["-"], "h">, Alias<soname>; - -//===----------------------------------------------------------------------===// -/// Resolver Options -//===----------------------------------------------------------------------===// -def grp_resolveropt : OptionGroup<"opts">, - HelpText<"SYMBOL RESOLUTION OPTIONS">; -defm u : smDash<"u", "undefined", - "Force symbol to be entered in the output file" - " as an undefined symbol">, - Group<grp_resolveropt>; -def start_group : Flag<["--"], "start-group">, - HelpText<"Start a group">, - Group<grp_resolveropt>; -def alias_start_group: Flag<["-"], "(">, - Alias<start_group>; -def end_group : Flag<["--"], "end-group">, - HelpText<"End a group">, - Group<grp_resolveropt>; -def alias_end_group: Flag<["-"], ")">, - Alias<end_group>; -def as_needed : Flag<["--"], "as-needed">, - HelpText<"This option affects ELF DT_NEEDED tags for " - "dynamic libraries mentioned on the command line">, - Group<grp_resolveropt>; -def no_as_needed : Flag<["--"], "no-as-needed">, - HelpText<"This option restores the default behavior" - " of adding DT_NEEDED entries">, - Group<grp_resolveropt>; -def no_allow_shlib_undefs : Flag<["--"], "no-allow-shlib-undefined">, - HelpText<"Do not allow undefined symbols from dynamic" - " library when creating executables">, - Group<grp_resolveropt>; -def allow_shlib_undefs : Flag<["-", "--"], "allow-shlib-undefined">, - HelpText<"Allow undefined symbols from dynamic" - " library when creating executables">, - Group<grp_resolveropt>; -def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">, - HelpText<"Resolve undefined symbols from dynamic libraries">, - Group<grp_resolveropt>; -def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">, - HelpText<"Allow multiple definitions">, - Group<grp_resolveropt>; -defm defsym : mDashEq<"defsym", - "Create a global symbol in the output file " - "containing the absolute address given by expression">, - MetaVarName<"symbol=<expression>">, - Group<grp_resolveropt>; - -//===----------------------------------------------------------------------===// -/// Custom Options -//===----------------------------------------------------------------------===// -def grp_customopts : OptionGroup<"opts">, - HelpText<"CUSTOM OPTIONS">; -def disable_newdtags: Flag<["--"], "disable-new-dtags">, - HelpText<"Disable new dynamic tags">, - Group<grp_customopts>; -def enable_newdtags: Flag<["--"], "enable-new-dtags">, - HelpText<"Enable new dynamic tags">, - Group<grp_customopts>; -def rosegment: Flag<["--"], "rosegment">, - HelpText<"Put read-only non-executable sections in their own segment">, - Group<grp_customopts>; -def z : Separate<["-"], "z">, - HelpText<"Linker Option extensions">, - Group<grp_customopts>; -def no_align_segments: Flag<["--"], "no-align-segments">, - HelpText<"Don't align ELF segments(virtualaddress/fileoffset) to page boundaries">, - Group<grp_customopts>; - -//===----------------------------------------------------------------------===// -/// Symbol options -//===----------------------------------------------------------------------===// -def grp_symbolopts : OptionGroup<"opts">, - HelpText<"SYMBOL OPTIONS">; -def demangle : Flag<["--"], "demangle">, - HelpText<"Demangle C++ symbols">, - Group<grp_symbolopts>; -def discard_loc : Flag<["--"], "discard-all">, - HelpText<"Discard all local symbols">, - Group<grp_symbolopts>; -def alias_discard_loc: Flag<["-"], "x">, - Alias<discard_loc>; -def discard_temp_loc : Flag<["--"], "discard-locals">, - HelpText<"Discard temporary local symbols">, - Group<grp_symbolopts>; -def alias_discard_temp_loc : Flag<["-"], "X">, - Alias<discard_temp_loc>; -def no_demangle : Flag<["--"], "no-demangle">, - HelpText<"Dont demangle C++ symbols">, - Group<grp_symbolopts>; -def strip_all : Flag<["--"], "strip-all">, - HelpText<"Omit all symbol informations from output">, - Group<grp_symbolopts>; -def alias_strip_all : Flag<["-"], "s">, - Alias<strip_all>; -defm wrap : smDash<"wrap", "wrap", - "Use a wrapper function for symbol. Any " - " undefined reference to symbol will be resolved to " - "\"__wrap_symbol\". Any undefined reference to \"__real_symbol\"" - " will be resolved to symbol.">, - MetaVarName<"<symbol>">, - Group<grp_symbolopts>; - -//===----------------------------------------------------------------------===// -/// Script Options -//===----------------------------------------------------------------------===// -def grp_scriptopts : OptionGroup<"opts">, - HelpText<"SCRIPT OPTIONS">; -defm T : smDash<"T", "script", - "Use the given linker script in place of the default script.">, - Group<grp_scriptopts>; - -//===----------------------------------------------------------------------===// -/// Optimization Options -//===----------------------------------------------------------------------===// -def grp_opts : OptionGroup<"opts">, - HelpText<"OPTIMIZATIONS">; -def hash_style : Joined <["--"], "hash-style=">, - HelpText<"Set the type of linker's hash table(s)">, - Group<grp_opts>; -def merge_strings : Flag<["--"], "merge-strings">, - HelpText<"Merge common strings across mergeable sections">, - Group<grp_opts>; -def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">, - HelpText<"Request creation of .eh_frame_hdr section and ELF " - " PT_GNU_EH_FRAME segment header">, - Group<grp_opts>; - -//===----------------------------------------------------------------------===// -/// Tracing Options -//===----------------------------------------------------------------------===// -def grp_tracingopts : OptionGroup<"opts">, - HelpText<"TRACING OPTIONS">; -def t : Flag<["-"], "t">, - HelpText<"Print the names of the input files as ld processes them">, - Group<grp_tracingopts>; -def stats : Flag<["--"], "stats">, - HelpText<"Print time and memory usage stats">, Group<grp_tracingopts>; - -//===----------------------------------------------------------------------===// -/// Extensions -//===----------------------------------------------------------------------===// -def grp_extns : OptionGroup<"opts">, - HelpText<"Extensions">; -def output_filetype: Separate<["--"], "output-filetype">, - HelpText<"Specify yaml to create an output in YAML format">, - Group<grp_extns>; -def alias_output_filetype: Joined<["--"], "output-filetype=">, - Alias<output_filetype>; - -//===----------------------------------------------------------------------===// -/// Target Specific Options -//===----------------------------------------------------------------------===// -def grp_targetopts : OptionGroup<"opts">, - HelpText<"ARCH SPECIFIC OPTIONS">; - -//===----------------------------------------------------------------------===// -/// ARM Target Specific Options -//===----------------------------------------------------------------------===// -def grp_arm_targetopts : OptionGroup<"ARM SPECIFIC OPTIONS">, - Group<grp_targetopts>; -def target1_rel : Flag<["--"], "target1-rel">, - Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">; -def target1_abs : Flag<["--"], "target1-abs">, - Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">; - -//===----------------------------------------------------------------------===// -/// MIPS Target Specific Options -//===----------------------------------------------------------------------===// -def grp_mips_targetopts : OptionGroup<"MIPS SPECIFIC OPTIONS">, - Group<grp_targetopts>; -def pcrel_eh_reloc : Flag<["-", "--"], "pcrel-eh-reloc">, - Group<grp_mips_targetopts>, - HelpText<"Interpret R_MIPS_EH as R_MIPS_PC32">; - -//===----------------------------------------------------------------------===// -/// Ignored options -//===----------------------------------------------------------------------===// -def grp_ignored: OptionGroup<"ignored">, - HelpText<"GNU Options ignored for Compatibility ">; -def dashg : Flag<["-"], "g">, - HelpText<"Ignored.">, - Group<grp_ignored>; -def Qy : Flag<["-"], "Qy">, - HelpText<"Ignored for SVR4 Compatibility">, - Group<grp_ignored>; -def qmagic : Flag<["-"], "qmagic">, - HelpText<"Ignored for Linux Compatibility">, - Group<grp_ignored>; -def G : Separate<["-"], "G">, - HelpText<"Ignored for MIPS GNU Linker Compatibility">, - Group<grp_ignored>; - -//===----------------------------------------------------------------------===// -/// Help -//===----------------------------------------------------------------------===// -def help : Flag<["--"], "help">, - HelpText<"Display this help message">; diff --git a/lib/Driver/TODO.rst b/lib/Driver/TODO.rst deleted file mode 100644 index 868eaf02290c..000000000000 --- a/lib/Driver/TODO.rst +++ /dev/null @@ -1,99 +0,0 @@ -GNU ld Driver -~~~~~~~~~~~~~ - -Missing Options -############### - -* --audit -* -A,--architecture -* -b,--format -* -d,-dc,-dp -* -P,--depaudit -* --exclude-libs -* --exclude-modules-for-implib -* -E,--export-dynamic,--no-export-dynamic -* -EB (We probably shouldn't support this) -* -EL (We probably shouldn't support this) -* -f,--auxiliary -* -F,--filter -* -G,--gpsize -* -h -* -i -* --library -* -M -* --print-map -* -output -* -O -* -q,--emit-relocs -* --force-dynamic -* --relocatable -* -R,--just-symbols -* -s,--strip-all -* -S,--strip-debug -* --trace -* -dT,--default-script -* -Ur -* --unique -* -v,--version,-V -* -y,--trace-symbol -* -z (keywords need to be implemented) -* --accept-unknown-input-arch,--no-accept-unknown-input-arch -* -Bdynamic,-dy,-call_shared -* -Bgroup -* -dn,-non_shared -* -Bsymbolic -* -Bsymbolic-functions -* --dynamic-list -* --dynamic-list-data -* --dynamic-list-cpp-new -* --dynamic-list-cpp-typeinfo -* --check-sections,--no-check-sections -* --copy-dt-needed-entries,--no-copy-dt-needed-entires -* --cref -* --no-define-common -* --defsym (only absolute value supported now) -* --demangle,--no-demangle -* -I -* --fatal-warnings,--no-fatal-warnings -* --force-exe-suffix -* --gc-sections,--no-gc-sections -* --print-gc-sections,--no-print-gc-sections -* --print-output-format -* --target-help -* -Map -* --no-keep-memory -* --no-undefined,-z defs -* --allow-shlib-undefined,--no-alow-shlib-undefined -* --no-undefined-version -* --default-symver -* --default-imported-symver -* --no-warn-mismatch -* --no-warn-search-mismatch -* --oformat -* -pie,--pic-executable -* --relax,--no-relax -* --retain-symbols-file -* --sort-common -* --sort-section={name,alignment} -* --split-by-file -* --split-by-reloc -* --stats -* --section-start -* -T{bss,data,text,{text,rodata,data}-segment} -* --unresolved-symbols -* -dll-verbose,--verbose -* --version-script -* --warn-common -* --warn-constructors -* --warn-multiple-gp -* --warn-once -* --warn-section-align -* --warn-shared-textrel -* --warn-alternate-em -* --warn-unresolved-symbols -* --error-unresolved-symbols -* --wrap -* --no-ld-generated-unwind-info -* --hash-size -* --reduce-memory-overheads -* --build-id diff --git a/lib/Driver/UniversalDriver.cpp b/lib/Driver/UniversalDriver.cpp deleted file mode 100644 index 3dea7ebfae89..000000000000 --- a/lib/Driver/UniversalDriver.cpp +++ /dev/null @@ -1,225 +0,0 @@ -//===- lib/Driver/UniversalDriver.cpp -------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Driver for "universal" lld tool which can mimic any linker command line -/// parsing once it figures out which command line flavor to use. -/// -//===----------------------------------------------------------------------===// - -#include "lld/Driver/Driver.h" -#include "lld/Config/Version.h" -#include "lld/Core/LLVM.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; - -namespace { - -// Create enum with OPT_xxx values for each option in GnuLdOptions.td -enum { - OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, -#include "UniversalDriverOptions.inc" -#undef OPTION -}; - -// Create prefix string literals used in GnuLdOptions.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "UniversalDriverOptions.inc" -#undef PREFIX - -// Create table mapping all options defined in GnuLdOptions.td -static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { \ - PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \ - } \ - , -#include "UniversalDriverOptions.inc" -#undef OPTION -}; - -// Create OptTable class for parsing actual command line arguments -class UniversalDriverOptTable : public llvm::opt::OptTable { -public: - UniversalDriverOptTable() - : OptTable(infoTable) {} -}; - -enum class Flavor { - invalid, - old_gnu_ld, // -flavor old-gnu - gnu_ld, // -flavor gnu - win_link, // -flavor link - darwin_ld, // -flavor darwin - core // -flavor core OR -core -}; - -struct ProgramNameParts { - StringRef _target; - StringRef _flavor; -}; - -} // anonymous namespace - -static Flavor strToFlavor(StringRef str) { - return llvm::StringSwitch<Flavor>(str) - .Case("old-gnu", Flavor::old_gnu_ld) - .Case("gnu", Flavor::gnu_ld) - .Case("ld.lld", Flavor::gnu_ld) - .Case("link", Flavor::win_link) - .Case("lld-link", Flavor::win_link) - .Case("darwin", Flavor::darwin_ld) - .Case("core", Flavor::core) - .Case("ld", Flavor::gnu_ld) - .Default(Flavor::invalid); -} - -static ProgramNameParts parseProgramName(StringRef programName) { - SmallVector<StringRef, 3> components; - llvm::SplitString(programName, components, "-"); - ProgramNameParts ret; - - using std::begin; - using std::end; - - // Erase any lld components. - components.erase(std::remove(components.begin(), components.end(), "lld"), - components.end()); - - // Find the flavor component. - auto flIter = std::find_if(components.begin(), components.end(), - [](StringRef str) -> bool { - return strToFlavor(str) != Flavor::invalid; - }); - - if (flIter != components.end()) { - ret._flavor = *flIter; - components.erase(flIter); - } - - // Any remaining component must be the target. - if (components.size() == 1) - ret._target = components[0]; - - return ret; -} - -// Removes the argument from argv along with its value, if exists, and updates -// argc. -static void removeArg(llvm::opt::Arg *arg, - llvm::MutableArrayRef<const char *> &args) { - unsigned int numToRemove = arg->getNumValues() + 1; - auto sub = args.slice(arg->getIndex() + 1); - std::rotate(sub.begin(), sub.begin() + numToRemove, sub.end()); - args = args.drop_back(numToRemove); -} - -static Flavor getFlavor(llvm::MutableArrayRef<const char *> &args, - const llvm::opt::InputArgList &parsedArgs) { - if (llvm::opt::Arg *argCore = parsedArgs.getLastArg(OPT_core)) { - removeArg(argCore, args); - return Flavor::core; - } - if (llvm::opt::Arg *argFlavor = parsedArgs.getLastArg(OPT_flavor)) { - removeArg(argFlavor, args); - return strToFlavor(argFlavor->getValue()); - } - -#if LLVM_ON_UNIX - if (llvm::sys::path::filename(args[0]).equals("ld")) { -#if __APPLE__ - // On a Darwin systems, if linker binary is named "ld", use Darwin driver. - return Flavor::darwin_ld; -#endif - // On a ELF based systems, if linker binary is named "ld", use gnu driver. - return Flavor::gnu_ld; - } -#endif - - StringRef name = llvm::sys::path::filename(args[0]); - if (name.endswith_lower(".exe")) - name = llvm::sys::path::stem(name); - return strToFlavor(parseProgramName(name)._flavor); -} - -namespace lld { - -bool UniversalDriver::link(llvm::MutableArrayRef<const char *> args, - raw_ostream &diagnostics) { - // Parse command line options using GnuLdOptions.td - UniversalDriverOptTable table; - unsigned missingIndex; - unsigned missingCount; - - // Program name - StringRef programName = llvm::sys::path::stem(args[0]); - - llvm::opt::InputArgList parsedArgs = - table.ParseArgs(args.slice(1), missingIndex, missingCount); - - if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; - return false; - } - - // Handle -help - if (parsedArgs.getLastArg(OPT_help)) { - table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false); - return true; - } - - // Handle -version - if (parsedArgs.getLastArg(OPT_version)) { - diagnostics << "LLVM Linker Version: " << getLLDVersion() - << getLLDRepositoryVersion() << "\n"; - return true; - } - - Flavor flavor = getFlavor(args, parsedArgs); - - // Switch to appropriate driver. - switch (flavor) { - case Flavor::old_gnu_ld: - return GnuLdDriver::linkELF(args, diagnostics); - case Flavor::gnu_ld: - elf2::link(args); - return true; - case Flavor::darwin_ld: - return DarwinLdDriver::linkMachO(args, diagnostics); - case Flavor::win_link: - coff::link(args); - return true; - case Flavor::core: - return CoreDriver::link(args, diagnostics); - case Flavor::invalid: - diagnostics << "Select the appropriate flavor\n"; - table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false); - return false; - } - llvm_unreachable("Unrecognised flavor"); -} - -} // end namespace lld diff --git a/lib/Driver/UniversalDriverOptions.td b/lib/Driver/UniversalDriverOptions.td deleted file mode 100644 index 14abc9ce9911..000000000000 --- a/lib/Driver/UniversalDriverOptions.td +++ /dev/null @@ -1,19 +0,0 @@ -include "llvm/Option/OptParser.td" - -// Select an optional flavor -def flavor: Separate<["-"], "flavor">, - HelpText<"Flavor for linking, options are gnu/darwin/link">; - -// Select the core flavor -def core : Flag<["-"], "core">, - HelpText<"CORE linking">; - -def target: Separate<["-"], "target">, - HelpText<"Select the target">; - -def version: Flag<["-"], "version">, - HelpText<"Display the version">; - -// Help message -def help : Flag<["-"], "help">, - HelpText<"Display this help message">; |
