[lld] r307460 - Revert "Revert "Revert "Revert "Switch external cvtres.exe for llvm's own resource library.""""

Eric Beckmann via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 7 20:06:10 PDT 2017


Author: ecbeckmann
Date: Fri Jul  7 20:06:10 2017
New Revision: 307460

URL: http://llvm.org/viewvc/llvm-project?rev=307460&view=rev
Log:
Revert "Revert "Revert "Revert "Switch external cvtres.exe for llvm's own resource library.""""

This reverts commit 147f45ff24456aea59575fa4ac16c8fa554df46a.

Revert "Revert "Revert "Revert "Replace trivial use of external rc.exe by writing our own .res file.""""

This reverts commit 61a90a67ed54a1f0dfeab457b65abffa129569e4.

The patches were intially reverted because they were causing a failure
on CrWinClangLLD.  Unfortunately, this was done haphazardly and didn't
compile, so the revert was reverted again quickly to fix this.  One that
was done, the revert of the revert was itself reverted.  This allowed me
to finally fix the actual bug in r307452.  This patch re-enables the
code path that had originally been causing the bug, now that it (should)
be fixed.

Modified:
    lld/trunk/COFF/DriverUtils.cpp
    lld/trunk/test/COFF/combined-resources.test
    lld/trunk/test/COFF/def-name.test
    lld/trunk/test/COFF/dll.test
    lld/trunk/test/COFF/dllimport-gc.test
    lld/trunk/test/COFF/manifestinput.test
    lld/trunk/test/COFF/noentry.test
    lld/trunk/test/COFF/out.test
    lld/trunk/test/COFF/resource.test
    lld/trunk/test/lit.cfg

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Fri Jul  7 20:06:10 2017
@@ -20,12 +20,15 @@
 #include "Symbols.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
 #include "llvm/Object/COFF.h"
+#include "llvm/Object/WindowsResource.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
@@ -41,6 +44,9 @@ namespace lld {
 namespace coff {
 namespace {
 
+const uint16_t SUBLANG_ENGLISH_US = 0x0409;
+const uint16_t RT_MANIFEST = 24;
+
 class Executor {
 public:
   explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
@@ -260,26 +266,6 @@ void parseManifestUAC(StringRef Arg) {
   }
 }
 
-// Quote each line with "". Existing double-quote is converted
-// to two double-quotes.
-static void quoteAndPrint(raw_ostream &Out, StringRef S) {
-  while (!S.empty()) {
-    StringRef Line;
-    std::tie(Line, S) = S.split("\n");
-    if (Line.empty())
-      continue;
-    Out << '\"';
-    for (int I = 0, E = Line.size(); I != E; ++I) {
-      if (Line[I] == '\"') {
-        Out << "\"\"";
-      } else {
-        Out << Line[I];
-      }
-    }
-    Out << "\"\n";
-  }
-}
-
 // An RAII temporary file class that automatically removes a temporary file.
 namespace {
 class TemporaryFile {
@@ -393,38 +379,62 @@ static std::string createManifestXml() {
   return readFile(File2.Path);
 }
 
+static std::unique_ptr<MemoryBuffer>
+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);
+}
+
+static void writeResFileHeader(char *&Buf) {
+  memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
+  Buf += sizeof(COFF::WinResMagic);
+  memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
+  Buf += object::WIN_RES_NULL_ENTRY_SIZE;
+}
+
+static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
+  // Write the prefix.
+  auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf);
+  Prefix->DataSize = ManifestSize;
+  Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
+                       sizeof(object::WinResIDs) +
+                       sizeof(object::WinResHeaderSuffix);
+  Buf += sizeof(object::WinResHeaderPrefix);
+
+  // Write the Type/Name IDs.
+  auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf);
+  IDs->setType(RT_MANIFEST);
+  IDs->setName(Config->ManifestID);
+  Buf += sizeof(object::WinResIDs);
+
+  // Write the suffix.
+  auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf);
+  Suffix->DataVersion = 0;
+  Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
+  Suffix->Language = SUBLANG_ENGLISH_US;
+  Suffix->Version = 0;
+  Suffix->Characteristics = 0;
+  Buf += sizeof(object::WinResHeaderSuffix);
+}
+
 // Create a resource file containing a manifest XML.
 std::unique_ptr<MemoryBuffer> createManifestRes() {
-  // Create a temporary file for the resource script file.
-  TemporaryFile RCFile("manifest", "rc");
+  std::string Manifest = createManifestXml();
 
-  // Open the temporary file for writing.
-  std::error_code EC;
-  raw_fd_ostream Out(RCFile.Path, EC, sys::fs::F_Text);
-  if (EC)
-    fatal(EC, "failed to open " + RCFile.Path);
+  std::unique_ptr<MemoryBuffer> Res =
+      createMemoryBufferForManifestRes(Manifest.size());
 
-  // Write resource script to the RC file.
-  Out << "#define LANG_ENGLISH 9\n"
-      << "#define SUBLANG_DEFAULT 1\n"
-      << "#define APP_MANIFEST " << Config->ManifestID << "\n"
-      << "#define RT_MANIFEST 24\n"
-      << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
-      << "APP_MANIFEST RT_MANIFEST {\n";
-  quoteAndPrint(Out, createManifestXml());
-  Out << "}\n";
-  Out.close();
-
-  // Create output resource file.
-  TemporaryFile ResFile("output-resource", "res");
-
-  Executor E("rc.exe");
-  E.add("/fo");
-  E.add(ResFile.Path);
-  E.add("/nologo");
-  E.add(RCFile.Path);
-  E.run();
-  return ResFile.getMemoryBuffer();
+  char *Buf = const_cast<char *>(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;
 }
 
 void createSideBySideManifest() {
@@ -595,40 +605,22 @@ void checkFailIfMismatch(StringRef Arg)
 // using cvtres.exe.
 std::unique_ptr<MemoryBuffer>
 convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
-  // Create an output file path.
-  TemporaryFile File("resource-file", "obj");
+  object::WindowsResourceParser Parser;
 
-  // Execute cvtres.exe.
-  Executor E("cvtres.exe");
-  E.add("/machine:" + machineToStr(Config->Machine));
-  E.add("/readonly");
-  E.add("/nologo");
-  E.add("/out:" + Twine(File.Path));
-
-  // We must create new files because the memory buffers we have may have no
-  // underlying file still existing on the disk.
-  // It happens if it was created from a TemporaryFile, which usually delete
-  // the file just after creating the MemoryBuffer.
-  std::vector<TemporaryFile> ResFiles;
-  ResFiles.reserve(MBs.size());
   for (MemoryBufferRef MB : MBs) {
-    // We store the temporary file in a vector to avoid deletion
-    // before running cvtres
-    ResFiles.emplace_back("resource-file", "res");
-    TemporaryFile& ResFile = ResFiles.back();
-    // Write the content of the resource in a temporary file
-    std::error_code EC;
-    raw_fd_ostream OS(ResFile.Path, EC, sys::fs::F_None);
-    if (EC)
-      fatal(EC, "failed to open " + ResFile.Path);
-    OS << MB.getBuffer();
-    OS.close();
-
-    E.add(ResFile.Path);
+    std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB));
+    object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
+    if (!RF)
+      fatal("cannot compile non-resource file as resource");
+    if (auto EC = Parser.parse(RF))
+      fatal(EC, "failed to parse .res file");
   }
 
-  E.run();
-  return File.getMemoryBuffer();
+  Expected<std::unique_ptr<MemoryBuffer>> E =
+      llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser);
+  if (!E)
+    fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF");
+  return std::move(E.get());
 }
 
 // Run MSVC link.exe for given in-memory object files.

Modified: lld/trunk/test/COFF/combined-resources.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/combined-resources.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/combined-resources.test (original)
+++ lld/trunk/test/COFF/combined-resources.test Fri Jul  7 20:06:10 2017
@@ -4,8 +4,6 @@
 // > rc /fo combined-resources.res /nologo combined-resources.rc
 // > rc /fo combined-resources-2.res /nologo combined-resources-2.rc
 
-# REQUIRES: winres
-
 # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
 # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \
 # RUN:   %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res

Modified: lld/trunk/test/COFF/def-name.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/def-name.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/def-name.test (original)
+++ lld/trunk/test/COFF/def-name.test Fri Jul  7 20:06:10 2017
@@ -1,5 +1,3 @@
-# REQUIRES: winres
-
 # RUN: rm -rf %t
 # RUN: mkdir -p %t
 # RUN: cd %t

Modified: lld/trunk/test/COFF/dll.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/dll.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/dll.test (original)
+++ lld/trunk/test/COFF/dll.test Fri Jul  7 20:06:10 2017
@@ -1,5 +1,3 @@
-# REQUIRES: winres
-
 # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
 # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
 # RUN:   /export:mangled

Modified: lld/trunk/test/COFF/dllimport-gc.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/dllimport-gc.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/dllimport-gc.test (original)
+++ lld/trunk/test/COFF/dllimport-gc.test Fri Jul  7 20:06:10 2017
@@ -1,5 +1,3 @@
-# REQUIRES: winres
-
 # RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj
 # RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1
 

Modified: lld/trunk/test/COFF/manifestinput.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/manifestinput.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/manifestinput.test (original)
+++ lld/trunk/test/COFF/manifestinput.test Fri Jul  7 20:06:10 2017
@@ -1,4 +1,4 @@
-# REQUIRES: winres
+# REQUIRES: win_mt
 
 # RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
 # RUN: lld-link /out:%t.exe /entry:main \
@@ -8,3 +8,28 @@
 
 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>
+
+# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN:   /manifest:embed \
+# RUN:   /manifestuac:"level='requireAdministrator'" \
+# RUN:   /manifestinput:%p/Inputs/manifestinput.test %t.obj
+# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \
+# RUN:   -check-prefix TEST_EMBED
+
+TEST_EMBED:          ResourceTableRVA: 0x1000
+TEST_EMBED-NEXT:     ResourceTableSize: 0x298
+TEST_EMBED-DAG:      Resources [
+TEST_EMBED-NEXT:       Total Number of Resources: 1 
+TEST_EMBED-DAG:        Number of String Entries: 0
+TEST_EMBED-NEXT:       Number of ID Entries: 1
+TEST_EMBED-NEXT:       Type: kRT_MANIFEST (ID 24) [
+TEST_EMBED-NEXT:         Table Offset: 0x18
+TEST_EMBED-NEXT:         Number of String Entries: 0
+TEST_EMBED-NEXT:         Number of ID Entries: 1
+TEST_EMBED-NEXT:         Name: (ID 1) [
+TEST_EMBED-NEXT:           Table Offset: 0x30
+TEST_EMBED-NEXT:           Number of String Entries: 0
+TEST_EMBED-NEXT:           Number of ID Entries: 1
+TEST_EMBED-NEXT:           Language: (ID 1033) [
+TEST_EMBED-NEXT:             Entry Offset: 0x48

Modified: lld/trunk/test/COFF/noentry.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/noentry.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/noentry.test (original)
+++ lld/trunk/test/COFF/noentry.test Fri Jul  7 20:06:10 2017
@@ -1,5 +1,3 @@
-# REQUIRES: winres
-
 # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
 # RUN: lld-link /out:%t.dll /dll %t.obj
 # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s

Modified: lld/trunk/test/COFF/out.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/out.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/out.test (original)
+++ lld/trunk/test/COFF/out.test Fri Jul  7 20:06:10 2017
@@ -1,4 +1,3 @@
-# REQUIRES: winres
 # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
 
 # RUN: mkdir -p %T/out/tmp

Modified: lld/trunk/test/COFF/resource.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/resource.test?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/COFF/resource.test (original)
+++ lld/trunk/test/COFF/resource.test Fri Jul  7 20:06:10 2017
@@ -1,5 +1,3 @@
-# REQUIRES: winres
-
 # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
 # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
 

Modified: lld/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/lit.cfg?rev=307460&r1=307459&r2=307460&view=diff
==============================================================================
--- lld/trunk/test/lit.cfg (original)
+++ lld/trunk/test/lit.cfg Fri Jul  7 20:06:10 2017
@@ -264,8 +264,7 @@ llvm_config_cmd.wait()
 # Set a fake constant version so that we get consitent output.
 config.environment['LLD_VERSION'] = 'LLD 1.0'
 
-# Check if Windows resource file compiler exists.
-cvtres = lit.util.which('cvtres', config.environment['PATH'])
-rc = lit.util.which('rc', config.environment['PATH'])
-if cvtres and rc:
-    config.available_features.add('winres')
+# Indirectly check if the mt.exe Microsoft utility exists by searching for
+# cvtres, which always accompanies it.
+if lit.util.which('cvtres', config.environment['PATH']):
+    config.available_features.add('win_mt')




More information about the llvm-commits mailing list