summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2016-04-19 01:21:58 +0000
committerRui Ueyama <ruiu@google.com>2016-04-19 01:21:58 +0000
commitafb1901e420e5994f953df063058ffe0c43c22d6 (patch)
treed8b3495d63443b0697fc6e2334a6c6a49ff62c58
parent9795699a7282a29d1a0a5c202209c6e2a4cc5539 (diff)
downloadbcm5719-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.h1
-rw-r--r--lld/COFF/Driver.cpp4
-rw-r--r--lld/COFF/DriverUtils.cpp53
-rw-r--r--lld/COFF/Options.td1
-rw-r--r--lld/test/COFF/Inputs/manifestinput.test13
-rw-r--r--lld/test/COFF/manifestinput.test10
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>
OpenPOWER on IntegriCloud