[lld] r306941 - Revert "Revert "Replace trivial use of external rc.exe by writing our own .res file.""

Eric Beckmann via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 30 20:59:55 PDT 2017


Author: ecbeckmann
Date: Fri Jun 30 20:59:54 2017
New Revision: 306941

URL: http://llvm.org/viewvc/llvm-project?rev=306941&view=rev
Log:
Revert "Revert "Replace trivial use of external rc.exe by writing our own .res file.""

Summary:
This reverts commit 51931072a7c9a52540baf76fc30ef391d2529a2f.

This revert was originally done because the integrations of the new
WindowsResource library into LLD was causing error in chromium, due to
bugs in how resource sections were handled.  These bugs were fixed,
meaning that the features may be reintegrated.

Subscribers: hiraditya, llvm-commits

Differential Revision: https://reviews.llvm.org/D34922

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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Fri Jun 30 20:59:54 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)) {}
@@ -257,26 +263,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 {
@@ -390,38 +376,64 @@ 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() {
@@ -592,40 +604,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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/combined-resources.test (original)
+++ lld/trunk/test/COFF/combined-resources.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/def-name.test (original)
+++ lld/trunk/test/COFF/def-name.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/dll.test (original)
+++ lld/trunk/test/COFF/dll.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/dllimport-gc.test (original)
+++ lld/trunk/test/COFF/dllimport-gc.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/manifestinput.test (original)
+++ lld/trunk/test/COFF/manifestinput.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/noentry.test (original)
+++ lld/trunk/test/COFF/noentry.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/out.test (original)
+++ lld/trunk/test/COFF/out.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/COFF/resource.test (original)
+++ lld/trunk/test/COFF/resource.test Fri Jun 30 20:59:54 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=306941&r1=306940&r2=306941&view=diff
==============================================================================
--- lld/trunk/test/lit.cfg (original)
+++ lld/trunk/test/lit.cfg Fri Jun 30 20:59:54 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