summaryrefslogtreecommitdiffstats
path: root/lld/lib/Driver
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/Driver')
-rw-r--r--lld/lib/Driver/CMakeLists.txt1
-rw-r--r--lld/lib/Driver/CoreDriver.cpp145
-rw-r--r--lld/lib/Driver/DarwinLdDriver.cpp108
-rw-r--r--lld/lib/Driver/Driver.cpp22
-rw-r--r--lld/lib/Driver/GnuLdDriver.cpp279
-rw-r--r--lld/lib/Driver/InputGraph.cpp56
-rw-r--r--lld/lib/Driver/LDOptions.td14
-rw-r--r--lld/lib/Driver/WinLinkDriver.cpp463
8 files changed, 581 insertions, 507 deletions
diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt
index 11d288809a1..bea845bf764 100644
--- a/lld/lib/Driver/CMakeLists.txt
+++ b/lld/lib/Driver/CMakeLists.txt
@@ -9,6 +9,7 @@ tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs)
add_public_tablegen_target(DriverOptionsTableGen)
add_lld_library(lldDriver
+ InputGraph.cpp
CoreDriver.cpp
DarwinLdDriver.cpp
Driver.cpp
diff --git a/lld/lib/Driver/CoreDriver.cpp b/lld/lib/Driver/CoreDriver.cpp
index c0869b790f6..9e4ca1228e0 100644
--- a/lld/lib/Driver/CoreDriver.cpp
+++ b/lld/lib/Driver/CoreDriver.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
+#include "lld/Driver/CoreInputGraph.h"
#include "lld/ReaderWriter/CoreLinkingContext.h"
#include "lld/ReaderWriter/Reader.h"
@@ -61,103 +62,105 @@ public:
CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};
-
-
} // namespace anonymous
namespace lld {
+std::unique_ptr<lld::LinkerInput>
+COREFileNode::createLinkerInput(const LinkingContext &info) {
+ return std::unique_ptr<LinkerInput>(new LinkerInput(path(info)));
+}
+
bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) {
CoreLinkingContext info;
if (parse(argc, argv, info))
return true;
-
+
return Driver::link(info);
}
-bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &info,
+bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
raw_ostream &diagnostics) {
// Parse command line options using CoreOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
CoreOptTable table;
unsigned missingIndex;
unsigned missingCount;
- parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
- missingIndex, missingCount));
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
- diagnostics << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex)
- << "' expected " << missingCount << " argument(s).\n";
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
return true;
}
- for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
- ie = parsedArgs->filtered_end(); it != ie; ++it) {
- diagnostics << "warning: ignoring unknown argument: "
- << (*it)->getAsString(*parsedArgs) << "\n";
- }
-
- // Copy mllvm
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- info.appendLLVMOption((*it)->getValue());
- }
-
- // Handle -e xxx
- if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
- info.setEntrySymbolName(entry->getValue());
-
- // Handle -o xxx
- if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
- info.setOutputPath(outpath->getValue());
- else
- info.setOutputPath("-");
-
- // Handle --dead_strip
- if (parsedArgs->getLastArg(OPT_dead_strip))
- info.setDeadStripping(true);
- else
- info.setDeadStripping(false);
-
- // Handle --keep-globals
- if (parsedArgs->getLastArg(OPT_keep_globals))
- info.setGlobalsAreDeadStripRoots(true);
- else
- info.setGlobalsAreDeadStripRoots(false);
-
- // Handle --undefines-are-errors
- if (parsedArgs->getLastArg(OPT_undefines_are_errors)) {
- info.setPrintRemainingUndefines(true);
- info.setAllowRemainingUndefines(false);
- }
- else {
- info.setPrintRemainingUndefines(false);
- info.setAllowRemainingUndefines(true);
+ std::unique_ptr<InputGraph> inputGraph(new InputGraph());
+
+ // 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 Elements
+ 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: {
+ inputGraph->addInputElement(std::unique_ptr<InputElement>(
+ new COREFileNode(ctx, inputArg->getValue())));
+ } break;
+
+ default:
+ break;
+ }
}
- // Handle --commons-search-archives
- if (parsedArgs->getLastArg(OPT_commons_search_archives))
- info.setSearchArchivesToOverrideTentativeDefinitions(true);
- else
- info.setSearchArchivesToOverrideTentativeDefinitions(false);
-
- // Handle --add-pass xxx option
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_add_pass),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- info.addPassNamed((*it)->getValue());
+ if (!inputGraph->numFiles()) {
+ diagnostics << "No input files\n";
+ return true;
}
- // Handle input files
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- info.appendInputFile((*it)->getValue());
- }
-
- return false;
+ ctx.setInputGraph(std::move(inputGraph));
+
+ // Validate the combination of options used.
+ return ctx.validate(diagnostics);
}
} // namespace lld
diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp
index 2e3d695d12f..90469d89731 100644
--- a/lld/lib/Driver/DarwinLdDriver.cpp
+++ b/lld/lib/Driver/DarwinLdDriver.cpp
@@ -14,9 +14,9 @@
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
+#include "lld/Driver/DarwinInputGraph.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
-#include "../ReaderWriter/MachO/MachOFormat.hpp"
-
+#include "lld/ReaderWriter/MachOFormat.hpp"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
@@ -71,31 +71,35 @@ public:
namespace lld {
-bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
- raw_ostream &diagnostics) {
- MachOLinkingContext info;
- if (parse(argc, argv, info, diagnostics))
+std::unique_ptr<lld::LinkerInput>
+MachOFileNode::createLinkerInput(const LinkingContext &ctx) {
+ return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx)));
+}
+
+bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ MachOLinkingContext ctx;
+ if (parse(argc, argv, ctx, diagnostics))
return true;
- if ( info.doNothing() )
+ if (ctx.doNothing())
return false;
-
- return link(info, diagnostics);
+
+ return link(ctx, diagnostics);
}
bool DarwinLdDriver::parse(int argc, const char *argv[],
- MachOLinkingContext &info,
- raw_ostream &diagnostics) {
+ MachOLinkingContext &ctx, raw_ostream &diagnostics) {
// Parse command line options using DarwinOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
DarwinLdOptTable table;
unsigned missingIndex;
unsigned missingCount;
- parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
- missingIndex, missingCount));
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
- diagnostics << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex)
- << "' expected " << missingCount << " argument(s).\n";
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
return true;
}
@@ -104,52 +108,52 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
diagnostics << "warning: ignoring unknown argument: "
<< (*it)->getAsString(*parsedArgs) << "\n";
}
-
+
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable,
OPT_bundle, OPT_static, OPT_preload)) {
switch (kind->getOption().getID()) {
case OPT_dylib:
- info.setOutputFileType(mach_o::MH_DYLIB);
- info.setGlobalsAreDeadStripRoots(true);
+ ctx.setOutputFileType(mach_o::MH_DYLIB);
+ ctx.setGlobalsAreDeadStripRoots(true);
break;
case OPT_relocatable:
- info.setPrintRemainingUndefines(false);
- info.setAllowRemainingUndefines(true);
- info.setOutputFileType(mach_o::MH_OBJECT);
+ ctx.setPrintRemainingUndefines(false);
+ ctx.setAllowRemainingUndefines(true);
+ ctx.setOutputFileType(mach_o::MH_OBJECT);
break;
case OPT_bundle:
- info.setOutputFileType(mach_o::MH_BUNDLE);
+ ctx.setOutputFileType(mach_o::MH_BUNDLE);
break;
case OPT_static:
- info.setOutputFileType(mach_o::MH_EXECUTE);
+ ctx.setOutputFileType(mach_o::MH_EXECUTE);
break;
case OPT_preload:
- info.setOutputFileType(mach_o::MH_PRELOAD);
+ ctx.setOutputFileType(mach_o::MH_PRELOAD);
break;
}
}
-
+
// Handle -e xxx
if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
- info.setEntrySymbolName(entry->getValue());
+ ctx.setEntrySymbolName(entry->getValue());
// Handle -o xxx
if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
- info.setOutputPath(outpath->getValue());
-
+ ctx.setOutputPath(outpath->getValue());
+
// Handle -dead_strip
if (parsedArgs->getLastArg(OPT_dead_strip))
- info.setDeadStripping(true);
-
+ ctx.setDeadStripping(true);
+
// Handle -all_load
if (parsedArgs->getLastArg(OPT_all_load))
- info.setForceLoadAllArchives(true);
-
+ ctx.setForceLoadAllArchives(true);
+
// Handle -arch xxx
if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) {
- info.setArch(MachOLinkingContext::archFromName(archStr->getValue()));
- if (info.arch() == MachOLinkingContext::arch_unknown) {
+ ctx.setArch(MachOLinkingContext::archFromName(archStr->getValue()));
+ if (ctx.arch() == MachOLinkingContext::arch_unknown) {
diagnostics << "error: unknown arch named '" << archStr->getValue()
<< "'\n";
return true;
@@ -163,20 +167,20 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
OPT_ios_simulator_version_min)) {
switch (minOS->getOption().getID()) {
case OPT_macosx_version_min:
- if (info.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) {
+ if (ctx.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) {
diagnostics << "error: malformed macosx_version_min value\n";
return true;
}
break;
case OPT_ios_version_min:
- if (info.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) {
+ if (ctx.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) {
diagnostics << "error: malformed ios_version_min value\n";
return true;
}
break;
case OPT_ios_simulator_version_min:
- if (info.setOS(MachOLinkingContext::OS::iOS_simulator,
- minOS->getValue())) {
+ if (ctx.setOS(MachOLinkingContext::OS::iOS_simulator,
+ minOS->getValue())) {
diagnostics << "error: malformed ios_simulator_version_min value\n";
return true;
}
@@ -185,34 +189,32 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
else {
// No min-os version on command line, check environment variables
-
}
-
+
+ std::unique_ptr<InputGraph> inputGraph(new InputGraph());
+
// Handle input files
for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
ie = parsedArgs->filtered_end();
it != ie; ++it) {
- info.appendInputFile((*it)->getValue());
+ inputGraph->addInputElement(std::unique_ptr<InputElement>(
+ new MachOFileNode(ctx, (*it)->getValue())));
}
-
- // Handle -help
- if (parsedArgs->getLastArg(OPT_help)) {
- table.PrintHelp(llvm::outs(), argv[0], "LLVM Darwin Linker", false);
- // If only -help on command line, don't try to do any linking
- if ( argc == 2 ) {
- info.setDoNothing(true);
- return false;
- }
+
+ if (!inputGraph->numFiles()) {
+ diagnostics << "No input files\n";
+ return true;
}
+ ctx.setInputGraph(std::move(inputGraph));
+
// Validate the combination of options used.
- if (info.validate(diagnostics))
+ if (ctx.validate(diagnostics))
return true;
return false;
}
-
} // namespace lld
diff --git a/lld/lib/Driver/Driver.cpp b/lld/lib/Driver/Driver.cpp
index d76bbdd31d4..ae20f84c973 100644
--- a/lld/lib/Driver/Driver.cpp
+++ b/lld/lib/Driver/Driver.cpp
@@ -40,21 +40,31 @@ bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) {
args[numArgs + 1] = 0;
llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
}
+ InputGraph &inputGraph = context.inputGraph();
+ if (!inputGraph.numFiles())
+ return true;
// Read inputs
ScopedTask readTask(getDefaultDomain(), "Read Args");
- std::vector<std::vector<std::unique_ptr<File>> > files(
- context.inputFiles().size());
+ std::vector<std::vector<std::unique_ptr<File> > > files(
+ inputGraph.numFiles());
size_t index = 0;
std::atomic<bool> fail(false);
TaskGroup tg;
- for (const auto &input : context.inputFiles()) {
+ std::vector<std::unique_ptr<LinkerInput> > linkerInputs;
+ for (auto &ie : inputGraph) {
+ if (ie->kind() == InputElement::Kind::File) {
+ FileNode *fileNode = (llvm::dyn_cast<FileNode>)(ie.get());
+ linkerInputs.push_back(std::move(fileNode->createLinkerInput(context)));
+ }
+ }
+ for (const auto &input : linkerInputs) {
if (context.logInputFiles())
- llvm::outs() << input.getPath() << "\n";
+ llvm::outs() << input->getPath() << "\n";
tg.spawn([ &, index]{
- if (error_code ec = context.readFile(input.getPath(), files[index])) {
- diagnostics << "Failed to read file: " << input.getPath() << ": "
+ if (error_code ec = context.readFile(input->getPath(), files[index])) {
+ diagnostics << "Failed to read file: " << input->getPath() << ": "
<< ec.message() << "\n";
fail = true;
return;
diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp
index 01c7c489b1a..96fa31905fc 100644
--- a/lld/lib/Driver/GnuLdDriver.cpp
+++ b/lld/lib/Driver/GnuLdDriver.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "lld/Driver/GnuLDInputGraph.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
@@ -71,10 +71,20 @@ public:
} // namespace
+std::unique_ptr<lld::LinkerInput>
+ELFFileNode::createLinkerInput(const LinkingContext &ctx) {
+ std::unique_ptr<LinkerInput> inputFile(new LinkerInput(path(ctx)));
+ inputFile->setAsNeeded(_asNeeded);
+ inputFile->setForceLoad(_isWholeArchive);
+ return std::move(inputFile);
+}
+StringRef ELFFileNode::path(const LinkingContext &) const {
+ return _elfLinkingContext.searchLibrary(_path, _libraryPaths);
+}
bool GnuLdDriver::linkELF(int argc, const char *argv[],
- raw_ostream &diagnostics) {
+ raw_ostream &diagnostics) {
std::unique_ptr<ELFLinkingContext> options;
bool error = parse(argc, argv, options, diagnostics);
if (error)
@@ -93,6 +103,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
GnuLdOptTable table;
unsigned missingIndex;
unsigned missingCount;
+
parsedArgs.reset(
table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
@@ -102,13 +113,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
return true;
}
- for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
- ie = parsedArgs->filtered_end(); it != ie; ++it) {
- diagnostics << "warning: ignoring unknown argument: " << (*it)->getAsString(
- *parsedArgs)
- << "\n";
- }
-
// Handle --help
if (parsedArgs->getLastArg(OPT_help)) {
table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
@@ -121,154 +125,181 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
triple = llvm::Triple(trip->getValue());
else
triple = getDefaultTarget(argv[0]);
- std::unique_ptr<ELFLinkingContext> options(ELFLinkingContext::create(triple));
+ std::unique_ptr<ELFLinkingContext> ctx(ELFLinkingContext::create(triple));
- if (!options) {
+ if (!ctx) {
diagnostics << "unknown target triple\n";
return true;
}
- // Handle -e xxx
- if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
- options->setEntrySymbolName(entry->getValue());
-
- // Handle -emit-yaml
- if (parsedArgs->getLastArg(OPT_emit_yaml))
- options->setOutputYAML(true);
-
- // Handle -o xxx
- if (llvm::opt::Arg *output = parsedArgs->getLastArg(OPT_output))
- options->setOutputPath(output->getValue());
- else if (options->outputYAML())
- options->setOutputPath("-"); // yaml writes to stdout by default
- else
- options->setOutputPath("a.out");
-
- // Handle -r, -shared, or -static
- if (llvm::opt::Arg *kind =
- parsedArgs->getLastArg(OPT_relocatable, OPT_shared, OPT_static)) {
- switch (kind->getOption().getID()) {
+ std::unique_ptr<InputGraph> inputGraph(new InputGraph());
+ std::stack<InputElement *> controlNodeStack;
+
+ // Positional options for an Input File
+ std::vector<StringRef> searchPath;
+ bool isWholeArchive = false;
+ bool asNeeded = false;
+ bool _outputOptionSet = false;
+
+ // Create a dynamic executable by default
+ ctx->setOutputFileType(llvm::ELF::ET_EXEC);
+ ctx->setIsStaticExecutable(false);
+ ctx->setAllowShlibUndefines(false);
+ ctx->setUseShlibUndefines(true);
+
+ // Set the output file to be a.out
+ ctx->setOutputPath("a.out");
+
+ // Process all the arguments and create Input Elements
+ for (auto inputArg : *parsedArgs) {
+ switch (inputArg->getOption().getID()) {
+ case OPT_mllvm:
+ ctx->appendLLVMOption(inputArg->getValue());
+ break;
case OPT_relocatable:
- options->setOutputFileType(llvm::ELF::ET_REL);
- options->setPrintRemainingUndefines(false);
- options->setAllowRemainingUndefines(true);
+ ctx->setOutputFileType(llvm::ELF::ET_REL);
+ ctx->setPrintRemainingUndefines(false);
+ ctx->setAllowRemainingUndefines(true);
+ break;
+ case OPT_static:
+ ctx->setOutputFileType(llvm::ELF::ET_EXEC);
+ ctx->setIsStaticExecutable(true);
break;
case OPT_shared:
- options->setOutputFileType(llvm::ELF::ET_DYN);
- options->setAllowShlibUndefines(true);
- options->setUseShlibUndefines(false);
+ ctx->setOutputFileType(llvm::ELF::ET_DYN);
+ ctx->setAllowShlibUndefines(true);
+ ctx->setUseShlibUndefines(false);
break;
- case OPT_static:
- options->setOutputFileType(llvm::ELF::ET_EXEC);
- options->setIsStaticExecutable(true);
+ case OPT_entry:
+ ctx->setEntrySymbolName(inputArg->getValue());
break;
- }
- } else {
- options->setOutputFileType(llvm::ELF::ET_EXEC);
- options->setIsStaticExecutable(false);
- options->setAllowShlibUndefines(false);
- options->setUseShlibUndefines(true);
- }
-
- // Handle --noinhibit-exec
- if (parsedArgs->getLastArg(OPT_noinhibit_exec))
- options->setAllowRemainingUndefines(true);
- // Handle --force-load
- if (parsedArgs->getLastArg(OPT_force_load))
- options->setForceLoadAllArchives(true);
+ case OPT_output:
+ _outputOptionSet = true;
+ ctx->setOutputPath(inputArg->getValue());
+ break;
- // Handle --merge-strings
- if (parsedArgs->getLastArg(OPT_merge_strings))
- options->setMergeCommonStrings(true);
+ case OPT_noinhibit_exec:
+ ctx->setAllowRemainingUndefines(true);
+ break;
- // Handle -t
- if (parsedArgs->getLastArg(OPT_t))
- options->setLogInputFiles(true);
+ case OPT_merge_strings:
+ ctx->setMergeCommonStrings(true);
+ break;
- // Handle --no-allow-shlib-undefined
- if (parsedArgs->getLastArg(OPT_no_allow_shlib_undefs))
- options->setAllowShlibUndefines(false);
+ case OPT_all_load:
+ ctx->setForceLoadAllArchives(true);
+ break;
- // Handle --allow-shlib-undefined
- if (parsedArgs->getLastArg(OPT_allow_shlib_undefs))
- options->setAllowShlibUndefines(true);
+ case OPT_t:
+ ctx->setLogInputFiles(true);
+ break;
- // Handle --use-shlib-undefs
- if (parsedArgs->getLastArg(OPT_use_shlib_undefs))
- options->setUseShlibUndefines(true);
+ case OPT_no_allow_shlib_undefs:
+ ctx->setAllowShlibUndefines(false);
+ break;
- // Handle --dynamic-linker
- if (llvm::opt::Arg *dynamicLinker =
- parsedArgs->getLastArg(OPT_dynamic_linker))
- options->setInterpreter(dynamicLinker->getValue());
+ case OPT_allow_shlib_undefs:
+ ctx->setAllowShlibUndefines(true);
+ break;
- // Handle NMAGIC
- if (parsedArgs->getLastArg(OPT_nmagic))
- options->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
+ case OPT_use_shlib_undefs:
+ ctx->setUseShlibUndefines(true);
+ break;
- // Handle OMAGIC
- if (parsedArgs->getLastArg(OPT_omagic))
- options->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
+ case OPT_dynamic_linker:
+ ctx->setInterpreter(inputArg->getValue());
+ break;
- // Handle --no-omagic
- if (parsedArgs->getLastArg(OPT_no_omagic)) {
- options->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
- options->setNoAllowDynamicLibraries();
- }
+ case OPT_nmagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
+ ctx->setIsStaticExecutable(true);
+ break;
- // If either of the options NMAGIC/OMAGIC have been set, make the executable
- // static
- if (!options->allowLinkWithDynamicLibraries())
- options->setIsStaticExecutable(true);
+ case OPT_omagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
+ ctx->setIsStaticExecutable(true);
+ break;
- // Handle -u, --undefined option
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_u),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- options->addInitialUndefinedSymbol((*it)->getValue());
- }
+ case OPT_no_omagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
+ ctx->setNoAllowDynamicLibraries();
+ break;
- // Handle -Lxxx
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- options->appendSearchPath((*it)->getValue());
- }
+ case OPT_u:
+ ctx->addInitialUndefinedSymbol(inputArg->getValue());
+ break;
- // Copy mllvm
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- options->appendLLVMOption((*it)->getValue());
- }
+ case OPT_emit_yaml:
+ if (!_outputOptionSet)
+ ctx->setOutputPath("-");
+ ctx->setOutputYAML(true);
+ break;
- // Handle input files (full paths and -lxxx)
- for (llvm::opt::arg_iterator
- it = parsedArgs->filtered_begin(OPT_INPUT, OPT_l),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- switch ((*it)->getOption().getID()) {
- case OPT_INPUT:
- options->appendInputFile((*it)->getValue());
+ case OPT_no_whole_archive:
+ isWholeArchive = false;
+ break;
+ case OPT_whole_archive:
+ isWholeArchive = true;
+ break;
+ case OPT_as_needed:
+ asNeeded = true;
break;
- case OPT_l:
- if (options->appendLibrary((*it)->getValue())) {
- diagnostics << "Failed to find library for " << (*it)->getValue()
- << "\n";
- return true;
- }
+ case OPT_no_as_needed:
+ asNeeded = false;
break;
+ case OPT_L:
+ searchPath.push_back(inputArg->getValue());
+ break;
+
+ case OPT_start_group: {
+ std::unique_ptr<InputElement> controlStart(new ELFGroup(*ctx));
+ controlNodeStack.push(controlStart.get());
+ (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
+ ->processControlEnter();
+ inputGraph->addInputElement(std::move(controlStart));
+ } break;
+
+ case OPT_end_group:
+ (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
+ ->processControlExit();
+ controlNodeStack.pop();
+ return false;
+
+ case OPT_INPUT:
+ case OPT_l: {
+ std::unique_ptr<InputElement> inputFile =
+ std::move(std::unique_ptr<InputElement>(
+ new ELFFileNode(*ctx, inputArg->getValue(), isWholeArchive,
+ asNeeded, searchPath)));
+ if (controlNodeStack.empty())
+ inputGraph->addInputElement(std::move(inputFile));
+ else
+ (llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
+ ->processInputElement(std::move(inputFile));
+ } break;
+
default:
- llvm_unreachable("input option type not handled");
- }
+ break;
+ } // end switch on option ID
+ } // end for
+
+ if (!inputGraph->numFiles()) {
+ diagnostics << "No input files\n";
+ return true;
}
+ if (ctx->outputYAML())
+ inputGraph->dump(diagnostics);
+
// Validate the combination of options used.
- if (options->validate(diagnostics))
+ if (ctx->validate(diagnostics))
return true;
- context.swap(options);
+ ctx->setInputGraph(std::move(inputGraph));
+
+ context.swap(ctx);
+
return false;
}
diff --git a/lld/lib/Driver/InputGraph.cpp b/lld/lib/Driver/InputGraph.cpp
new file mode 100644
index 00000000000..001cfed4e27
--- /dev/null
+++ b/lld/lib/Driver/InputGraph.cpp
@@ -0,0 +1,56 @@
+//===- lib/Driver/InputGraph.cpp ------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "lld/Driver/InputGraph.h"
+
+using namespace lld;
+
+namespace {
+bool sortInputElements(const std::unique_ptr<InputElement> &a,
+ const std::unique_ptr<InputElement> &b) {
+ return a->getOrdinal() < b->getOrdinal();
+}
+}
+
+bool InputGraph::addInputElement(std::unique_ptr<InputElement> ie) {
+ switch (ie->kind()) {
+ case InputElement::Kind::Control:
+ ++_numElements;
+ break;
+ case InputElement::Kind::File:
+ ++_numElements;
+ ++_numFiles;
+ break;
+ }
+ _inputArgs.push_back(std::move(ie));
+ return true;
+}
+
+bool InputGraph::assignOrdinals() {
+ for (auto &ie : _inputArgs)
+ ie->setOrdinal(++_ordinal);
+ return true;
+}
+
+void InputGraph::doPostProcess() {
+ std::stable_sort(_inputArgs.begin(), _inputArgs.end(), sortInputElements);
+}
+
+bool InputGraph::validate() {
+ for (auto &ie : _inputArgs)
+ if (!ie->validate())
+ return false;
+ return true;
+}
+
+bool InputGraph::dump(raw_ostream &diagnostics) {
+ for (auto &ie : _inputArgs)
+ if (!ie->dump(diagnostics))
+ return false;
+ return true;
+}
diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td
index e941d547c9b..8f5a87996df 100644
--- a/lld/lib/Driver/LDOptions.td
+++ b/lld/lib/Driver/LDOptions.td
@@ -80,8 +80,18 @@ def undefined : Separate<["--"], "undefined">, Alias<u>;
def u_equal : Joined<["-"], "u=">, Alias<u>;
def undefined_equal : Joined<["--"], "undefined=">, Alias<u>;
+def as_needed : Flag<["--"], "as-needed">,
+ HelpText<"This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line">;
+def no_as_needed : Flag<["--"], "no-as-needed">,
+ HelpText<"This option restores the default behavior of adding DT_NEEDED entries">;
+
// extensions
def emit_yaml : Flag<["-"], "emit-yaml">,
HelpText<"Write YAML instead of ELF">;
-def force_load : Flag<["--"], "force-load">,
- HelpText<"Force load of all members in all static libraries">;
+def whole_archive: Flag<["--"], "whole-archive">,
+ HelpText<"Force load of all members in a static library">;
+def no_whole_archive: Flag<["--"], "no-whole-archive">,
+ HelpText<"Restores the default behavior of loading archive members">;
+
+def all_load : Flag<["-"], "all_load">,
+ HelpText<"Forces all members of all static libraries to be loaded">;
diff --git a/lld/lib/Driver/WinLinkDriver.cpp b/lld/lib/Driver/WinLinkDriver.cpp
index 54dbe843292..d863aa73362 100644
--- a/lld/lib/Driver/WinLinkDriver.cpp
+++ b/lld/lib/Driver/WinLinkDriver.cpp
@@ -17,15 +17,16 @@
#include <sstream>
#include <map>
+#include "lld/Driver/Driver.h"
+#include "lld/Driver/WinLinkInputGraph.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"
-#include "lld/Driver/Driver.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-
namespace lld {
namespace {
@@ -62,135 +63,6 @@ public:
WinLinkOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};
-// Displays error message if the given version does not match with
-// /^\d+$/.
-bool checkNumber(StringRef version, const char *errorMessage,
- raw_ostream &diagnostics) {
- if (version.str().find_first_not_of("0123456789") != std::string::npos
- || version.empty()) {
- diagnostics << "error: " << errorMessage << version << "\n";
- return false;
- }
- return true;
-}
-
-// Parse an argument for /base, /stack or /heap. The expected string
-// is "<integer>[,<integer>]".
-bool parseMemoryOption(const StringRef &arg, raw_ostream &diagnostics,
- uint64_t &reserve, uint64_t &commit) {
- StringRef reserveStr, commitStr;
- llvm::tie(reserveStr, commitStr) = arg.split(',');
- if (!checkNumber(reserveStr, "invalid size: ", diagnostics))
- return false;
- reserve = atoi(reserveStr.str().c_str());
- if (!commitStr.empty()) {
- if (!checkNumber(commitStr, "invalid size: ", diagnostics))
- return false;
- commit = atoi(commitStr.str().c_str());
- }
- return true;
-}
-
-// Parse /base command line option. The argument for the parameter is in the
-// form of "<address>[:<size>]".
-bool parseBaseOption(PECOFFLinkingContext &context, const StringRef &arg,
- raw_ostream &diagnostics) {
- // Size should be set to SizeOfImage field in the COFF header, and if it's
- // smaller than the actual size, the linker should warn about that. Currently
- // we just ignore the value of size parameter.
- uint64_t addr, size;
- if (!parseMemoryOption(arg, diagnostics, addr, size))
- return false;
- // It's an error if the base address is not multiple of 64K.
- if (addr & 0xffff) {
- diagnostics << "Base address have to be multiple of 64K, but got "
- << addr << "\n";
- return false;
- }
- context.setBaseAddress(addr);
- return true;
-}
-
-// Parse /stack command line option
-bool parseStackOption(PECOFFLinkingContext &context, const StringRef &arg,
- raw_ostream &diagnostics) {
- uint64_t reserve;
- uint64_t commit = context.getStackCommit();
- if (!parseMemoryOption(arg, diagnostics, reserve, commit))
- return false;
- context.setStackReserve(reserve);
- context.setStackCommit(commit);
- return true;
-}
-
-// Parse /heap command line option.
-bool parseHeapOption(PECOFFLinkingContext &context, const StringRef &arg,
- raw_ostream &diagnostics) {
- uint64_t reserve;
- uint64_t commit = context.getHeapCommit();
- if (!parseMemoryOption(arg, diagnostics, reserve, commit))
- return false;
- context.setHeapReserve(reserve);
- context.setHeapCommit(commit);
- return true;
-}
-
-// Returns subsystem type for the given string.
-llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
- std::string arg(str.lower());
- return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(arg)
- .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
- .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
- .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
-}
-
-bool parseMinOSVersion(PECOFFLinkingContext &context,
- const StringRef &osVersion, raw_ostream &diagnostics) {
- StringRef majorVersion, minorVersion;
- llvm::tie(majorVersion, minorVersion) = osVersion.split('.');
- if (minorVersion.empty())
- minorVersion = "0";
- if (!checkNumber(majorVersion, "invalid OS major version: ", diagnostics))
- return false;
- if (!checkNumber(minorVersion, "invalid OS minor version: ", diagnostics))
- return false;
- PECOFFLinkingContext::OSVersion minOSVersion(
- atoi(majorVersion.str().c_str()), atoi(minorVersion.str().c_str()));
- context.setMinOSVersion(minOSVersion);
- return true;
-}
-
-// Parse /subsystem command line option. The form of /subsystem is
-// "subsystem_name[,majorOSVersion[.minorOSVersion]]".
-bool parseSubsystemOption(PECOFFLinkingContext &context, std::string arg,
- raw_ostream &diagnostics) {
- StringRef subsystemStr, osVersionStr;
- llvm::tie(subsystemStr, osVersionStr) = StringRef(arg).split(',');
-
- // Parse optional OS version if exists.
- if (!osVersionStr.empty())
- if (!parseMinOSVersion(context, osVersionStr, diagnostics))
- return false;
-
- // Parse subsystem name.
- llvm::COFF::WindowsSubsystem subsystem = stringToWinSubsystem(subsystemStr);
- if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
- diagnostics << "error: unknown subsystem name: " << subsystemStr << "\n";
- return false;
- }
- context.setSubsystem(subsystem);
- return true;
-}
-
-// Replace a file extension with ".exe". If the given file has no
-// extension, just add ".exe".
-StringRef getDefaultOutputFileName(PECOFFLinkingContext &context,
- StringRef path) {
- SmallString<128> smallStr = path;
- llvm::sys::path::replace_extension(smallStr, ".exe");
- return context.allocateString(smallStr.str());
-}
-
// Split the given string with spaces.
std::vector<std::string> splitArgList(std::string str) {
std::stringstream stream(str);
@@ -210,6 +82,26 @@ std::vector<StringRef> splitPathList(StringRef str) {
return std::move(ret);
}
+// Parse an argument for /base, /stack or /heap. The expected string
+// is "<integer>[,<integer>]".
+bool parseMemoryOption(StringRef arg, uint64_t &reserve, uint64_t &commit) {
+ StringRef reserveStr, commitStr;
+ llvm::tie(reserveStr, commitStr) = arg.split(',');
+ if (reserveStr.getAsInteger(0, reserve))
+ return true;
+ if (!commitStr.empty() && (commitStr.getAsInteger(0, commit)))
+ return true;
+ return false;
+}
+
+// Returns subsystem type for the given string.
+llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
+ return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(str.lower())
+ .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
+}
+
// Handle /failifmatch option.
bool handleFailIfMismatchOption(StringRef option,
std::map<StringRef, StringRef> &mustMatch,
@@ -218,26 +110,16 @@ bool handleFailIfMismatchOption(StringRef option,
llvm::tie(key, value) = option.split('=');
if (key.empty() || value.empty()) {
diagnostics << "error: malformed /failifmatch option: " << option << "\n";
- return false;
+ return true;
}
auto it = mustMatch.find(key);
if (it != mustMatch.end() && it->second != value) {
diagnostics << "error: mismatch detected: '" << it->second << "' and '"
<< value << "' for key '" << key << "'\n";
- return false;
+ return true;
}
mustMatch[key] = value;
- return true;
-}
-
-// Add ".lib" extension if the path does not already have the extension to mimic
-// link.exe behavior.
-StringRef canonicalizeImportLibraryPath(PECOFFLinkingContext &context,
- StringRef path) {
- std::string s(path.lower());
- if (StringRef(s).endswith(".lib"))
- return path;
- return context.allocateString(std::string(path).append(".lib"));
+ return false;
}
// Process "LINK" environment variable. If defined, the value of the variable
@@ -299,6 +181,29 @@ std::unique_ptr<llvm::opt::InputArgList> parseArgs(int argc, const char *argv[],
} // namespace
+std::unique_ptr<lld::LinkerInput>
+PECOFFFileNode::createLinkerInput(const LinkingContext &ctx) {
+ return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx)));
+}
+
+std::unique_ptr<lld::LinkerInput>
+PECOFFLibraryNode::createLinkerInput(const LinkingContext &ctx) {
+ return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx)));
+}
+
+StringRef PECOFFFileNode::path(const LinkingContext &) const {
+ if (_path.endswith(".lib"))
+ return _ctx.searchLibraryFile(_path);
+ if (llvm::sys::path::extension(_path).empty())
+ return (_path.str() + ".obj");
+ return _path;
+}
+
+StringRef PECOFFLibraryNode::path(const LinkingContext &) const {
+ if (!_path.endswith(".lib"))
+ return _ctx.searchLibraryFile(_path.str() + ".lib");
+ return _ctx.searchLibraryFile(_path);
+}
bool WinLinkDriver::linkPECOFF(int argc, const char *argv[],
raw_ostream &diagnostics) {
@@ -311,14 +216,19 @@ bool WinLinkDriver::linkPECOFF(int argc, const char *argv[],
}
bool WinLinkDriver::parse(int argc, const char *argv[],
- PECOFFLinkingContext &context,
- raw_ostream &diagnostics) {
+ PECOFFLinkingContext &ctx, raw_ostream &diagnostics) {
+ std::map<StringRef, StringRef> failIfMismatchMap;
// Parse the options.
std::unique_ptr<llvm::opt::InputArgList> parsedArgs = parseArgs(
argc, argv, diagnostics);
if (!parsedArgs)
return true;
+ if (!ctx.hasInputGraph())
+ ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph()));
+
+ InputGraph &inputGraph = ctx.inputGraph();
+
// handle /help
if (parsedArgs->getLastArg(OPT_help)) {
WinLinkOptTable table;
@@ -326,75 +236,6 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
return true;
}
- // Copy -mllvm
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- context.appendLLVMOption((*it)->getValue());
- }
-
- // handle /base
- if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_base))
- if (!parseBaseOption(context, arg->getValue(), diagnostics))
- return true;
-
- // handle /stack
- if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_stack))
- if (!parseStackOption(context, arg->getValue(), diagnostics))
- return true;
-
- // handle /heap
- if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_heap))
- if (!parseHeapOption(context, arg->getValue(), diagnostics))
- return true;
-
- // handle /subsystem
- if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_subsystem))
- if (!parseSubsystemOption(context, arg->getValue(), diagnostics))
- return true;
-
- // handle /entry
- if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_entry))
- context.setEntrySymbolName(arg->getValue());
-
- // handle /libpath
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_libpath),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- context.appendInputSearchPath((*it)->getValue());
- }
-
- // handle /force
- if (parsedArgs->getLastArg(OPT_force))
- context.setAllowRemainingUndefines(true);
-
- // handle /nxcompat:no
- if (parsedArgs->getLastArg(OPT_no_nxcompat))
- context.setNxCompat(false);
-
- // handle /largeaddressaware
- if (parsedArgs->getLastArg(OPT_largeaddressaware))
- context.setLargeAddressAware(true);
-
- // handle /fixed
- if (parsedArgs->getLastArg(OPT_fixed))
- context.setBaseRelocationEnabled(false);
-
- // handle /tsaware:no
- if (parsedArgs->getLastArg(OPT_no_tsaware))
- context.setTerminalServerAware(false);
-
- // handle /include
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_incl),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- context.addInitialUndefinedSymbol((*it)->getValue());
- }
-
- // handle /out
- if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out))
- context.setOutputPath(outpath->getValue());
-
// handle /defaultlib
std::vector<StringRef> defaultLibs;
for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_defaultlib),
@@ -403,29 +244,143 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
defaultLibs.push_back((*it)->getValue());
}
- // Handle /failifmismatch. /failifmismatch is the hidden linker option behind
- // the scenes of "detect_mismatch" pragma. If the compiler finds "#pragma
- // detect_mismatch(name, value)", it outputs "/failifmismatch:name=value" to
- // the .drectve section of the resultant object file. The linker raises an
- // error if conflicting /failmismatch options are given. Conflicting options
- // are the options with the same key but with different values.
- //
- // This feature is used to prevent inconsistent object files from linking.
- std::map<StringRef, StringRef> mustMatch;
- for (llvm::opt::arg_iterator
- it = parsedArgs->filtered_begin(OPT_failifmismatch),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- if (!handleFailIfMismatchOption((*it)->getValue(), mustMatch, diagnostics))
- return true;
- }
-
- // Add input files
- std::vector<StringRef> inputPaths;
- for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
- ie = parsedArgs->filtered_end();
- it != ie; ++it) {
- inputPaths.push_back((*it)->getValue());
+ // Process all the arguments and create Input Elements
+ for (auto inputArg : *parsedArgs) {
+ switch (inputArg->getOption().getID()) {
+ case OPT_mllvm:
+ ctx.appendLLVMOption(inputArg->getValue());
+ break;
+
+ case OPT_base:
+ // Parse /base command line option. The argument for the parameter is in
+ // the
+ // form of "<address>[:<size>]".
+ uint64_t addr, size;
+ // Size should be set to SizeOfImage field in the COFF header, and if
+ // it's smaller than the actual size, the linker should warn about that.
+ // Currently we just ignore the value of size parameter.
+ if (parseMemoryOption(inputArg->getValue(), addr, size))
+ return true;
+ // It's an error if the base address is not multiple of 64K.
+ // TODO: move this to validation of LinkingContext
+ if (addr & 0xffff) {
+ diagnostics << "Base address have to be multiple of 64K, but got "
+ << addr << "\n";
+ return true;
+ }
+ ctx.setBaseAddress(addr);
+ break;
+ case OPT_stack: {
+ // Parse /stack command line option
+ uint64_t reserve;
+ uint64_t commit = ctx.getStackCommit();
+ if (parseMemoryOption(inputArg->getValue(), reserve, commit))
+ return true;
+ ctx.setStackReserve(reserve);
+ ctx.setStackCommit(commit);
+ } break;
+ case OPT_heap: {
+ // Parse /heap command line option
+ uint64_t reserve;
+ uint64_t commit = ctx.getHeapCommit();
+ if (parseMemoryOption(inputArg->getValue(), reserve, commit))
+ return true;
+ ctx.setHeapReserve(reserve);
+ ctx.setHeapCommit(commit);
+ } break;
+ case OPT_subsystem: {
+ // Parse /subsystem command line option. The form of /subsystem is
+ // "subsystem_name[,majorOSVersion[.minorOSVersion]]".
+ StringRef subsystemStr, osVersion;
+ llvm::tie(subsystemStr, osVersion) =
+ StringRef(inputArg->getValue()).split(',');
+ if (!osVersion.empty()) {
+ StringRef majorVersion, minorVersion;
+ llvm::tie(majorVersion, minorVersion) = osVersion.split('.');
+ if (minorVersion.empty())
+ minorVersion = "0";
+ int32_t major, minor;
+ if (majorVersion.getAsInteger(0, major))
+ return true;
+ if (minorVersion.getAsInteger(0, minor))
+ return true;
+ ctx.setMinOSVersion(PECOFFLinkingContext::OSVersion(major, minor));
+ }
+ // Parse subsystem name.
+ llvm::COFF::WindowsSubsystem subsystem =
+ stringToWinSubsystem(subsystemStr);
+ if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
+ diagnostics << "error: unknown subsystem name: " << subsystemStr
+ << "\n";
+ return true;
+ }
+ ctx.setSubsystem(subsystem);
+ } break;
+
+ case OPT_failifmismatch:
+ if (handleFailIfMismatchOption(inputArg->getValue(), failIfMismatchMap,
+ diagnostics))
+ return true;
+ break;
+
+ case OPT_entry:
+ // handle /entry
+ ctx.setEntrySymbolName(inputArg->getValue());
+ break;
+
+ case OPT_libpath:
+ // handle /libpath
+ ctx.appendInputSearchPath(inputArg->getValue());
+ break;
+
+ case OPT_force:
+ // handle /force
+ ctx.setAllowRemainingUndefines(true);
+ break;
+
+ case OPT_no_nxcompat:
+ // handle /nxcompat:no
+ ctx.setNxCompat(false);
+ break;
+
+ case OPT_largeaddressaware:
+ // handle /largeaddressaware
+ ctx.setLargeAddressAware(true);
+ break;
+
+ case OPT_fixed:
+ // handle /fixed
+ ctx.setBaseRelocationEnabled(false);
+ break;
+
+ case OPT_tsaware:
+ // handle /tsaware
+ ctx.setTerminalServerAware(true);
+ break;
+
+ case OPT_no_tsaware:
+ // handle /tsaware:no
+ ctx.setTerminalServerAware(false);
+ break;
+
+ case OPT_incl:
+ // handle /incl
+ ctx.addInitialUndefinedSymbol(inputArg->getValue());
+ break;
+
+ case OPT_out:
+ // handle /out
+ ctx.setOutputPath(inputArg->getValue());
+ break;
+
+ case OPT_INPUT: {
+ inputGraph.addInputElement(std::unique_ptr<InputElement>(
+ new PECOFFFileNode(ctx, inputArg->getValue())));
+ } break;
+
+ default:
+ break;
+ }
}
// Arguments after "--" are interpreted as filenames even if they
@@ -433,27 +388,33 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
// but useful for us to test lld on Unix.
if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH)) {
for (const StringRef value : dashdash->getValues())
- inputPaths.push_back(value);
+ inputGraph.addInputElement(
+ std::unique_ptr<InputElement>(new PECOFFFileNode(ctx, value)));
}
- // Add input files specified via the command line.
- for (const StringRef path : inputPaths)
- context.appendInputFileOrLibrary(path);
+ // Add ".lib" extension if the path does not already have the extension to
+ // mimic link.exe behavior.
+ for (auto defaultLibPath : defaultLibs)
+ inputGraph.addInputElement(std::unique_ptr<InputElement>(
+ new PECOFFLibraryNode(ctx, defaultLibPath)));
- // Add the library files specified by /defaultlib option. The files
- // specified by the option should have lower precedence than the other files
- // added above, which is important for link.exe compatibility.
- for (const StringRef path : defaultLibs)
- context.appendLibraryFile(canonicalizeImportLibraryPath(context, path));
+ if (!inputGraph.numFiles()) {
+ diagnostics << "No input files\n";
+ return true;
+ }
// If /out option was not specified, the default output file name is
// constructed by replacing an extension of the first input file
// with ".exe".
- if (context.outputPath().empty() && !inputPaths.empty())
- context.setOutputPath(getDefaultOutputFileName(context, inputPaths[0]));
+ if (ctx.outputPath().empty()) {
+ SmallString<128> firstInputFilePath =
+ (llvm::dyn_cast<FileNode>(&((inputGraph)[0])))->path(ctx);
+ (llvm::sys::path::replace_extension(firstInputFilePath, ".exe"));
+ ctx.setOutputPath(firstInputFilePath.str());
+ }
// Validate the combination of options used.
- return context.validate(diagnostics);
+ return ctx.validate(diagnostics);
}
} // namespace lld
OpenPOWER on IntegriCloud