diff options
author | Rui Ueyama <ruiu@google.com> | 2016-04-19 01:21:58 +0000 |
---|---|---|
committer | Rui Ueyama <ruiu@google.com> | 2016-04-19 01:21:58 +0000 |
commit | afb1901e420e5994f953df063058ffe0c43c22d6 (patch) | |
tree | d8b3495d63443b0697fc6e2334a6c6a49ff62c58 | |
parent | 9795699a7282a29d1a0a5c202209c6e2a4cc5539 (diff) | |
download | bcm5719-llvm-afb1901e420e5994f953df063058ffe0c43c22d6.tar.gz bcm5719-llvm-afb1901e420e5994f953df063058ffe0c43c22d6.zip |
COFF: Support /manifestinput command line option.
Manifest file is a separate or embedded XML file having metadata
of an executable. As it is XML, it can contain various types of
information. Probably the most popular one is to request escalated
priviledges.
Usually the linker creates an XML file and embed that file into
an executable. However, there's a way to supply an XML file from
command line. /manifestniput is it.
Apparently it is over-designed here, but if you supply two or more
manifest files, then the linker needs to merge the files into a
single XML file. A good news is that we don't need to do that ourselves.
MT.exe command can do that, so we call the command from the linker
in this patch.
llvm-svn: 266704
-rw-r--r-- | lld/COFF/Config.h | 1 | ||||
-rw-r--r-- | lld/COFF/Driver.cpp | 4 | ||||
-rw-r--r-- | lld/COFF/DriverUtils.cpp | 53 | ||||
-rw-r--r-- | lld/COFF/Options.td | 1 | ||||
-rw-r--r-- | lld/test/COFF/Inputs/manifestinput.test | 13 | ||||
-rw-r--r-- | lld/test/COFF/manifestinput.test | 10 |
6 files changed, 76 insertions, 6 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 9cfccadba5f..4e6064a6a23 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -111,6 +111,7 @@ struct Configuration { int ManifestID = 1; StringRef ManifestDependency; bool ManifestUAC = true; + std::vector<std::string> ManifestInput; StringRef ManifestLevel = "'asInvoker'"; StringRef ManifestUIAccess = "'false'"; StringRef ManifestFile; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 2a71343aa30..8845d415469 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -423,6 +423,10 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) { if (auto *Arg = Args.getLastArg(OPT_manifestfile)) Config->ManifestFile = Arg->getValue(); + // Handle /manifestinput + for (auto *Arg : Args.filtered(OPT_manifestinput)) + Config->ManifestInput.push_back(Arg->getValue()); + // Handle miscellaneous boolean flags. if (Args.hasArg(OPT_allowbind_no)) Config->AllowBind = false; diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index 014fee7fefd..ba83f8691b3 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -240,10 +240,17 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) { } } -// Create a manifest file contents. -static std::string createManifestXml() { - std::string S; - llvm::raw_string_ostream OS(S); +// Create the default manifest file as a temporary file. +static std::string createDefaultXml() { + // Create a temporary file. + SmallString<128> Path; + std::error_code EC = sys::fs::createTemporaryFile("tmp", "manifest", Path); + error(EC, "cannot create a temporary file"); + + // Open the temporary file for writing. + llvm::raw_fd_ostream OS(Path, EC, sys::fs::F_Text); + error(EC, Twine("failed to open ") + Path); + // Emit the XML. Note that we do *not* verify that the XML attributes are // syntactically correct. This is intentional for link.exe compatibility. OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n" @@ -267,8 +274,42 @@ static std::string createManifestXml() { } } OS << "</assembly>\n"; - OS.flush(); - return S; + OS.close(); + return StringRef(Path); +} + +static std::string readFile(StringRef Path) { + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = MemoryBuffer::getFile(Path); + error(BufOrErr, "Could not open " + Path); + std::unique_ptr<MemoryBuffer> Buf(std::move(*BufOrErr)); + return Buf->getBuffer(); +} + +static std::string createManifestXml() { + // Create the default manifest file. + std::string Path1 = createDefaultXml(); + if (Config->ManifestInput.empty()) + return readFile(Path1); + + // If manifest files are supplied by the user using /MANIFESTINPUT + // option, we need to merge them with the default manifest. + SmallString<128> Path2; + std::error_code EC = sys::fs::createTemporaryFile("tmp", "manifest", Path2); + error(EC, "cannot create a temporary file"); + FileRemover Remover1(Path1); + FileRemover Remover2(Path2); + + Executor E("mt.exe"); + E.add("/manifest"); + E.add(Path1); + for (StringRef Filename : Config->ManifestInput) { + E.add("/manifest"); + E.add(Filename); + } + E.add("/nologo"); + E.add("/out:" + StringRef(Path2)); + E.run(); + return readFile(Path2); } // Create a resource file containing a manifest XML. diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index ceb25ccb5c7..e5c9c5b4635 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -48,6 +48,7 @@ def manifestuac : P<"manifestuac", "User access control">; def manifestfile : P<"manifestfile", "Manifest file path">; def manifestdependency : P<"manifestdependency", "Attributes for <dependency> in manifest file">; +def manifestinput : P<"manifestinput", "Specify manifest file">; // We cannot use multiclass P because class name "incl" is different // from its command line option name. We do this because "include" is diff --git a/lld/test/COFF/Inputs/manifestinput.test b/lld/test/COFF/Inputs/manifestinput.test new file mode 100644 index 00000000000..c65739225a5 --- /dev/null +++ b/lld/test/COFF/Inputs/manifestinput.test @@ -0,0 +1,13 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes'?> +<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> + <dependency> + <dependentAssembly> + <assemblyIdentity type='win32' + name='Microsoft.Windows.Common-Controls' + version='6.0.0.0' + processorArchitecture='*' + publicKeyToken='6595b64144ccf1df' + language='*' /> + </dependentAssembly> + </dependency> +</assembly> diff --git a/lld/test/COFF/manifestinput.test b/lld/test/COFF/manifestinput.test new file mode 100644 index 00000000000..376d404d604 --- /dev/null +++ b/lld/test/COFF/manifestinput.test @@ -0,0 +1,10 @@ +# REQUIRES: winres + +# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj +# RUN: lld-link /out:%t.exe /entry:main \ +# RUN: /manifestuac:"level='requireAdministrator'" \ +# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj +# RUN: FileCheck %s < %t.exe.manifest + +CHECK: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> +CHECK: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity></dependentAssembly></dependency><trustInfo><security><requestedPrivileges><requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel></requestedPrivileges></security></trustInfo></assembly> |