[lld] r192830 - Run CVTRES.EXE on resource files.

Rui Ueyama ruiu at google.com
Wed Oct 16 12:21:46 PDT 2013


Author: ruiu
Date: Wed Oct 16 14:21:45 2013
New Revision: 192830

URL: http://llvm.org/viewvc/llvm-project?rev=192830&view=rev
Log:
Run CVTRES.EXE on resource files.

Modified:
    lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
    lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp

Modified: lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h?rev=192830&r1=192829&r2=192830&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/IdataPass.h Wed Oct 16 14:21:45 2013
@@ -243,7 +243,9 @@ public:
 class IdataPassFile : public SimpleFile {
 public:
   IdataPassFile(const LinkingContext &ctx)
-      : SimpleFile(ctx, "<idata-pass-file>") {}
+      : SimpleFile(ctx, "<idata-pass-file>") {
+    setOrdinal(ctx.getNextOrdinalAndIncrement());
+  }
 };
 
 class IdataPass : public lld::Pass {

Modified: lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp?rev=192830&r1=192829&r2=192830&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp Wed Oct 16 14:21:45 2013
@@ -23,8 +23,12 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Memory.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
 
@@ -726,11 +730,15 @@ public:
   error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
                        std::vector<std::unique_ptr<File> > &result) const {
     StringRef magic(mb->getBufferStart(), mb->getBufferSize());
-    // The input file should be an archive file, a regular COFF file, or an
-    // import library member file. Try to parse in that order. If the input file
-    // does not start with a known magic, parseCOFFImportLibrary will return an
-    // error object.
+
+    // The input file should be a resource file, an archive file, a regular COFF
+    // file, or an import library member file. Try to parse in that order. If
+    // the input file does not start with a known magic, parseCOFFImportLibrary
+    // will return an error object.
     llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(magic);
+
+    if (fileType == llvm::sys::fs::file_magic::windows_resource)
+      return convertAndParseResourceFile(mb, result);
     if (fileType == llvm::sys::fs::file_magic::coff_object)
       return parseCOFFFile(mb, result);
     return lld::coff::parseCOFFImportLibrary(_context, mb, result);
@@ -775,6 +783,104 @@ private:
     }
   }
 
+  //
+  // RC file Reader
+  //
+
+  ErrorOr<std::string>
+  writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const {
+    // Get a temporary file path for .rc file.
+    SmallString<128> tempFilePath;
+    if (error_code ec = llvm::sys::fs::createTemporaryFile(
+            "tmp", "rc", tempFilePath))
+      return ec;
+
+    // Write the memory buffer contents to .rc file, so that we can run
+    // cvtres.exe on it.
+    OwningPtr<llvm::FileOutputBuffer> buffer;
+    if (error_code ec = llvm::FileOutputBuffer::create(
+            tempFilePath.str(), mb->getBufferSize(), buffer))
+      return ec;
+    memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize());
+    if (error_code ec = buffer->commit())
+      return ec;
+
+    // Convert SmallString -> StringRef -> std::string.
+    return tempFilePath.str().str();
+  }
+
+  ErrorOr<std::string>
+  convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const {
+    // Write the resource file to a temporary file.
+    ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb));
+    if (!inFilePath)
+      return error_code(inFilePath);
+    llvm::FileRemover inFileRemover(*inFilePath);
+
+    // Create an output file path.
+    SmallString<128> outFilePath;
+    if (error_code ec = llvm::sys::fs::createTemporaryFile(
+            "tmp", "obj", outFilePath))
+      return ec;
+    std::string outFileArg = ("/out:" + outFilePath).str();
+
+    // Construct CVTRES.EXE command line and execute it.
+    std::string program = "cvtres.exe";
+    std::string programPath = llvm::sys::FindProgramByName(program);
+    if (programPath.empty()) {
+      llvm::errs() << "Unable to find " << program << " in PATH\n";
+      return llvm::errc::broken_pipe;
+    }
+    std::vector<const char *> args;
+    args.push_back(programPath.c_str());
+    args.push_back("/machine:x86");
+    args.push_back("/readonly");
+    args.push_back(outFileArg.c_str());
+    args.push_back(inFilePath->c_str());
+    args.push_back(nullptr);
+
+    DEBUG({
+      for (const char **p = &args[0]; *p; ++p)
+        llvm::dbgs() << *p << " ";
+      llvm::dbgs() << "\n";
+    });
+
+    if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+      llvm::errs() << program << " failed\n";
+      return llvm::errc::broken_pipe;
+    }
+    return outFilePath.str().str();
+  }
+
+  // Convert .rc file to .coff file and then parse it. Resource file is a file
+  // containing various types of data, such as icons, translation texts,
+  // etc. "cvtres.exe" command reads an RC file to create a COFF file which
+  // encapsulates resource data into rsrc$N sections, where N is an integer.
+  //
+  // The linker is not capable to handle RC files directly. Instead, it runs
+  // cvtres.exe on RC files and then then link its outputs.
+  error_code
+  convertAndParseResourceFile(
+      std::unique_ptr<MemoryBuffer> &mb,
+      std::vector<std::unique_ptr<File> > &result) const {
+    // Convert an RC to a COFF
+    ErrorOr<std::string> coffFilePath = convertResourceFileToCOFF(std::move(mb));
+    if (!coffFilePath)
+      return error_code(coffFilePath);
+    llvm::FileRemover coffFileRemover(*coffFilePath);
+
+    // Read and parse the COFF
+    OwningPtr<llvm::MemoryBuffer> opmb;
+    if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(*coffFilePath, opmb))
+      return ec;
+    std::unique_ptr<llvm::MemoryBuffer> newmb(opmb.take());
+    return parseCOFFFile(newmb, result);
+  }
+
+  //
+  // COFF file Reader
+  //
+
   error_code parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb,
                            std::vector<std::unique_ptr<File> > &result) const {
     // Parse the memory buffer as PECOFF file.





More information about the llvm-commits mailing list