[lld] r266704 - COFF: Support /manifestinput command line option.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 18 18:21:58 PDT 2016


Author: ruiu
Date: Mon Apr 18 20:21:58 2016
New Revision: 266704

URL: http://llvm.org/viewvc/llvm-project?rev=266704&view=rev
Log:
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.

Added:
    lld/trunk/test/COFF/Inputs/manifestinput.test
    lld/trunk/test/COFF/manifestinput.test
Modified:
    lld/trunk/COFF/Config.h
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/DriverUtils.cpp
    lld/trunk/COFF/Options.td

Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=266704&r1=266703&r2=266704&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Mon Apr 18 20:21:58 2016
@@ -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;

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=266704&r1=266703&r2=266704&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Mon Apr 18 20:21:58 2016
@@ -423,6 +423,10 @@ void LinkerDriver::link(llvm::ArrayRef<c
   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;

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=266704&r1=266703&r2=266704&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Mon Apr 18 20:21:58 2016
@@ -240,10 +240,17 @@ static void quoteAndPrint(raw_ostream &O
   }
 }
 
-// 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.

Modified: lld/trunk/COFF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=266704&r1=266703&r2=266704&view=diff
==============================================================================
--- lld/trunk/COFF/Options.td (original)
+++ lld/trunk/COFF/Options.td Mon Apr 18 20:21:58 2016
@@ -48,6 +48,7 @@ def manifestuac : P<"manifestuac", "User
 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

Added: lld/trunk/test/COFF/Inputs/manifestinput.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/manifestinput.test?rev=266704&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/manifestinput.test (added)
+++ lld/trunk/test/COFF/Inputs/manifestinput.test Mon Apr 18 20:21:58 2016
@@ -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>

Added: lld/trunk/test/COFF/manifestinput.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/manifestinput.test?rev=266704&view=auto
==============================================================================
--- lld/trunk/test/COFF/manifestinput.test (added)
+++ lld/trunk/test/COFF/manifestinput.test Mon Apr 18 20:21:58 2016
@@ -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>




More information about the llvm-commits mailing list