aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lld/COFF/DriverUtils.cpp')
-rw-r--r--contrib/llvm/tools/lld/COFF/DriverUtils.cpp115
1 files changed, 90 insertions, 25 deletions
diff --git a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
index 4b3b6d5e09d6..c12e791f9507 100644
--- a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
+++ b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
@@ -61,12 +61,7 @@ public:
StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
- std::vector<const char *> Vec;
- for (StringRef S : Args)
- Vec.push_back(S.data());
- Vec.push_back(nullptr);
-
- if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
+ if (sys::ExecuteAndWait(Args[0], Args) != 0)
fatal("ExecuteAndWait failed: " +
llvm::join(Args.begin(), Args.end(), " "));
}
@@ -128,6 +123,21 @@ void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
fatal("invalid number: " + S2);
}
+void parseGuard(StringRef FullArg) {
+ SmallVector<StringRef, 1> SplitArgs;
+ FullArg.split(SplitArgs, ",");
+ for (StringRef Arg : SplitArgs) {
+ if (Arg.equals_lower("no"))
+ Config->GuardCF = GuardCFLevel::Off;
+ else if (Arg.equals_lower("nolongjmp"))
+ Config->GuardCF = GuardCFLevel::NoLongJmp;
+ else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp"))
+ Config->GuardCF = GuardCFLevel::Full;
+ else
+ fatal("invalid argument to /guard: " + Arg);
+ }
+}
+
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
uint32_t *Minor) {
@@ -170,6 +180,10 @@ void parseMerge(StringRef S) {
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
fatal("/merge: invalid argument: " + S);
+ if (From == ".rsrc" || To == ".rsrc")
+ fatal("/merge: cannot merge '.rsrc' with any section");
+ if (From == ".reloc" || To == ".reloc")
+ fatal("/merge: cannot merge '.reloc' with any section");
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
@@ -418,15 +432,15 @@ static std::string createManifestXml() {
return createManifestXmlWithExternalMt(DefaultXml);
}
-static std::unique_ptr<MemoryBuffer>
+static std::unique_ptr<WritableMemoryBuffer>
createMemoryBufferForManifestRes(size_t ManifestSize) {
size_t ResSize = alignTo(
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
sizeof(object::WinResHeaderSuffix) + ManifestSize,
object::WIN_RES_DATA_ALIGNMENT);
- return MemoryBuffer::getNewMemBuffer(ResSize,
- Config->OutputFile + ".manifest.res");
+ return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile +
+ ".manifest.res");
}
static void writeResFileHeader(char *&Buf) {
@@ -465,16 +479,16 @@ static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
std::unique_ptr<MemoryBuffer> createManifestRes() {
std::string Manifest = createManifestXml();
- std::unique_ptr<MemoryBuffer> Res =
+ std::unique_ptr<WritableMemoryBuffer> Res =
createMemoryBufferForManifestRes(Manifest.size());
- char *Buf = const_cast<char *>(Res->getBufferStart());
+ char *Buf = Res->getBufferStart();
writeResFileHeader(Buf);
writeResEntryHeader(Buf, Manifest.size());
// Copy the manifest data into the .res file.
std::copy(Manifest.begin(), Manifest.end(), Buf);
- return Res;
+ return std::move(Res);
}
void createSideBySideManifest() {
@@ -558,6 +572,12 @@ err:
static StringRef undecorate(StringRef Sym) {
if (Config->Machine != I386)
return Sym;
+ // In MSVC mode, a fully decorated stdcall function is exported
+ // as-is with the leading underscore (with type IMPORT_NAME).
+ // In MinGW mode, a decorated stdcall function gets the underscore
+ // removed, just like normal cdecl functions.
+ if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW)
+ return Sym;
return Sym.startswith("_") ? Sym.substr(1) : Sym;
}
@@ -731,6 +751,28 @@ static const llvm::opt::OptTable::Info InfoTable[] = {
COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
+// Set color diagnostics according to --color-diagnostics={auto,always,never}
+// or --no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return;
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().ColorDiagnostics = true;
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().ColorDiagnostics = false;
+ } else {
+ StringRef S = Arg->getValue();
+ if (S == "always")
+ errorHandler().ColorDiagnostics = true;
+ else if (S == "never")
+ errorHandler().ColorDiagnostics = false;
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
+ }
+}
+
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
StringRef S = Arg->getValue();
@@ -749,50 +791,73 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
unsigned MissingIndex;
unsigned MissingCount;
- SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
// We need to get the quoting style for response files before parsing all
// options so we parse here before and ignore all the options but
// --rsp-quoting.
- opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
- Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size());
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv);
+ Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex,
+ MissingCount);
// Print the real command line if response files are expanded.
- if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) {
+ if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) {
std::string Msg = "Command line:";
- for (const char *S : Vec)
+ for (const char *S : ExpandedArgv)
Msg += " " + std::string(S);
message(Msg);
}
+ // Save the command line after response file expansion so we can write it to
+ // the PDB if necessary.
+ Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()};
+
// Handle /WX early since it converts missing argument warnings to errors.
errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false);
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+ handleColorDiagnostics(Args);
+
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
+
+ if (Args.hasArg(OPT_lib))
+ warn("ignoring /lib since it's not the first argument");
+
return Args;
}
// Tokenizes and parses a given string as command line in .drective section.
-opt::InputArgList ArgParser::parseDirectives(StringRef S) {
- // Make InputArgList from string vectors.
+// /EXPORT options are processed in fastpath.
+std::pair<opt::InputArgList, std::vector<StringRef>>
+ArgParser::parseDirectives(StringRef S) {
+ std::vector<StringRef> Exports;
+ SmallVector<const char *, 16> Rest;
+
+ for (StringRef Tok : tokenize(S)) {
+ if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:"))
+ Exports.push_back(Tok.substr(strlen("/export:")));
+ else
+ Rest.push_back(Tok.data());
+ }
+
+ // Make InputArgList from unparsed string vectors.
unsigned MissingIndex;
unsigned MissingCount;
- opt::InputArgList Args =
- Table.ParseArgs(tokenize(S), MissingIndex, MissingCount);
+ opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount);
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
warn("ignoring unknown argument: " + Arg->getSpelling());
- return Args;
+ return {std::move(Args), std::move(Exports)};
}
// link.exe has an interesting feature. If LINK or _LINK_ environment
@@ -802,11 +867,11 @@ opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) {
// Concatenate LINK env and command line arguments, and then parse them.
if (Optional<std::string> S = Process::GetEnv("LINK")) {
std::vector<const char *> V = tokenize(*S);
- Argv.insert(Argv.begin(), V.begin(), V.end());
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
}
if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
std::vector<const char *> V = tokenize(*S);
- Argv.insert(Argv.begin(), V.begin(), V.end());
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
}
return parse(Argv);
}