From 45c4c54003641f2bb225eaf305c07906451d6096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Sun, 4 Oct 2020 01:29:45 +0300 Subject: [PATCH] [LLD] [COFF] Add a private option for setting the os version separately from subsystem version The MinGW driver has separate options for OS and subsystem version. Having this available in lld-link allows the MinGW driver to both match GNU ld better and simplifies the code for merging two (potentially mismatching) arguments into one. Differential Revision: https://reviews.llvm.org/D88802 --- lld/COFF/Config.h | 2 ++ lld/COFF/Driver.cpp | 25 +++++++++++++++++++++---- lld/COFF/Driver.h | 2 +- lld/COFF/DriverUtils.cpp | 4 +++- lld/COFF/Options.td | 6 ++++++ lld/COFF/Writer.cpp | 4 ++-- lld/test/COFF/subsystem.test | 18 ++++++++++++++++++ 7 files changed, 53 insertions(+), 8 deletions(-) diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 286b67b437a8..f0a26c19e955 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -223,6 +223,8 @@ struct Configuration { uint32_t minorImageVersion = 0; uint32_t majorOSVersion = 6; uint32_t minorOSVersion = 0; + uint32_t majorSubsystemVersion = 6; + uint32_t minorSubsystemVersion = 0; uint32_t timestamp = 0; uint32_t functionPadMin = 0; bool dynamicBase = true; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 56717de226c2..3560f1066f29 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -408,10 +408,17 @@ void LinkerDriver::parseDirectives(InputFile *file) { case OPT_section: parseSection(arg->getValue()); break; - case OPT_subsystem: + case OPT_subsystem: { + bool gotVersion = false; parseSubsystem(arg->getValue(), &config->subsystem, - &config->majorOSVersion, &config->minorOSVersion); + &config->majorSubsystemVersion, + &config->minorSubsystemVersion, &gotVersion); + if (gotVersion) { + config->majorOSVersion = config->majorSubsystemVersion; + config->minorOSVersion = config->minorSubsystemVersion; + } break; + } // Only add flags here that link.exe accepts in // `#pragma comment(linker, "/flag")`-generated sections. case OPT_editandcontinue: @@ -1459,8 +1466,18 @@ void LinkerDriver::link(ArrayRef argsArr) { // Handle /subsystem if (auto *arg = args.getLastArg(OPT_subsystem)) - parseSubsystem(arg->getValue(), &config->subsystem, &config->majorOSVersion, - &config->minorOSVersion); + parseSubsystem(arg->getValue(), &config->subsystem, + &config->majorSubsystemVersion, + &config->minorSubsystemVersion); + + // Handle /osversion + if (auto *arg = args.getLastArg(OPT_osversion)) { + parseVersion(arg->getValue(), &config->majorOSVersion, + &config->minorOSVersion); + } else { + config->majorOSVersion = config->majorSubsystemVersion; + config->minorOSVersion = config->minorSubsystemVersion; + } // Handle /timestamp if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) { diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 3fee9b1fe50e..5de05a1ef325 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -168,7 +168,7 @@ void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor); // Parses a string in the form of "[,[.]]". void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, - uint32_t *minor); + uint32_t *minor, bool *gotVersion = nullptr); void parseAlternateName(StringRef); void parseMerge(StringRef); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index d4449709e1b7..7de73f2cfe49 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -112,7 +112,7 @@ void parseGuard(StringRef fullArg) { // Parses a string in the form of "[,[.]]". void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, - uint32_t *minor) { + uint32_t *minor, bool *gotVersion) { StringRef sysStr, ver; std::tie(sysStr, ver) = arg.split(','); std::string sysStrLower = sysStr.lower(); @@ -132,6 +132,8 @@ void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, fatal("unknown subsystem: " + sysStr); if (!ver.empty()) parseVersion(ver, major, minor); + if (gotVersion) + *gotVersion = !ver.empty(); } // Parse a string of the form of "=". diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index d1badf0fdd2f..d27e95f9bd60 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -9,6 +9,11 @@ class F : Flag<["/", "-", "/?", "-?"], name>; class P : Joined<["/", "-", "/?", "-?"], name#":">, HelpText; +// Same as P<> above, but without help texts, for private undocumented +// options. +class P_priv : + Joined<["/", "-", "/?", "-?"], name#":">; + // Boolean flag which can be suffixed by ":no". Using it unsuffixed turns the // flag on and using it suffixed by ":no" turns it off. multiclass B { @@ -205,6 +210,7 @@ def include_optional : Joined<["/", "-", "/?", "-?"], "includeoptional:">, def kill_at : F<"kill-at">; def lldmingw : F<"lldmingw">; def noseh : F<"noseh">; +def osversion : P_priv<"osversion">; def output_def : Joined<["/", "-", "/?", "-?"], "output-def:">; def pdb_source_path : P<"pdbsourcepath", "Base path used to make relative source file path absolute in PDB">; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index d1081b008ea4..145d517c9c0e 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -1373,8 +1373,8 @@ template void Writer::writeHeader() { pe->MinorImageVersion = config->minorImageVersion; pe->MajorOperatingSystemVersion = config->majorOSVersion; pe->MinorOperatingSystemVersion = config->minorOSVersion; - pe->MajorSubsystemVersion = config->majorOSVersion; - pe->MinorSubsystemVersion = config->minorOSVersion; + pe->MajorSubsystemVersion = config->majorSubsystemVersion; + pe->MinorSubsystemVersion = config->minorSubsystemVersion; pe->Subsystem = config->subsystem; pe->SizeOfImage = sizeOfImage; pe->SizeOfHeaders = sizeOfHeaders; diff --git a/lld/test/COFF/subsystem.test b/lld/test/COFF/subsystem.test index a43035eb396e..e9a6966a01da 100644 --- a/lld/test/COFF/subsystem.test +++ b/lld/test/COFF/subsystem.test @@ -30,3 +30,21 @@ CHECK3: MajorOperatingSystemVersion: 8 CHECK3: MinorOperatingSystemVersion: 9 CHECK3: MajorSubsystemVersion: 8 CHECK3: MinorSubsystemVersion: 9 + +# RUN: lld-link /entry:main /out:%t.exe /osversion:1.2 \ +# RUN: %p/Inputs/ret42.obj +# RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK4 %s + +CHECK4: MajorOperatingSystemVersion: 1 +CHECK4: MinorOperatingSystemVersion: 2 +CHECK4: MajorSubsystemVersion: 6 +CHECK4: MinorSubsystemVersion: 0 + +# RUN: lld-link /entry:main /out:%t.exe /osversion:1.2 /subsystem:default,3.4 \ +# RUN: %p/Inputs/ret42.obj +# RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK5 %s + +CHECK5: MajorOperatingSystemVersion: 1 +CHECK5: MinorOperatingSystemVersion: 2 +CHECK5: MajorSubsystemVersion: 3 +CHECK5: MinorSubsystemVersion: 4