summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/DriverUtils.cpp109
-rw-r--r--lld/test/COFF/manifestinput.test25
-rw-r--r--lld/test/lit.cfg5
-rw-r--r--llvm/include/llvm/BinaryFormat/COFF.h6
-rw-r--r--llvm/include/llvm/Object/WindowsResource.h48
-rw-r--r--llvm/lib/BinaryFormat/Magic.cpp3
-rw-r--r--llvm/lib/Object/WindowsResource.cpp24
-rw-r--r--llvm/unittests/BinaryFormat/TestFileMagic.cpp3
8 files changed, 78 insertions, 145 deletions
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 14b40f2c217..1d2c8811386 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -20,7 +20,6 @@
#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"
@@ -28,7 +27,6 @@
#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"
@@ -44,9 +42,6 @@ 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)) {}
@@ -266,6 +261,26 @@ 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 {
@@ -379,64 +394,38 @@ 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() {
- std::string Manifest = createManifestXml();
-
- std::unique_ptr<MemoryBuffer> Res =
- createMemoryBufferForManifestRes(Manifest.size());
+ // Create a temporary file for the resource script file.
+ TemporaryFile RCFile("manifest", "rc");
- 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;
+ // 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);
+
+ // 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();
}
void createSideBySideManifest() {
diff --git a/lld/test/COFF/manifestinput.test b/lld/test/COFF/manifestinput.test
index 4eb1730bb0e..7fc37c98fc5 100644
--- a/lld/test/COFF/manifestinput.test
+++ b/lld/test/COFF/manifestinput.test
@@ -8,28 +8,3 @@
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
diff --git a/lld/test/lit.cfg b/lld/test/lit.cfg
index cba56c64290..83df50957be 100644
--- a/lld/test/lit.cfg
+++ b/lld/test/lit.cfg
@@ -264,7 +264,6 @@ llvm_config_cmd.wait()
# Set a fake constant version so that we get consitent output.
config.environment['LLD_VERSION'] = 'LLD 1.0'
-# 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']):
+# Check if the mt.exe Microsoft utility exists.
+if lit.util.which('mt.exe', config.environment['PATH']):
config.available_features.add('win_mt')
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index b395db6eaa8..138e44bfec2 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -46,12 +46,6 @@ static const char ClGlObjMagic[] = {
'\xac', '\x9b', '\xd6', '\xb6', '\x22', '\x26', '\x53', '\xc2',
};
-// The signature bytes that start a .res file.
-static const char WinResMagic[] = {
- '\x00', '\x00', '\x00', '\x00', '\x20', '\x00', '\x00', '\x00',
- '\xff', '\xff', '\x00', '\x00', '\xff', '\xff', '\x00', '\x00',
-};
-
// Sizes in bytes of various things in the COFF format.
enum {
Header16Size = 20,
diff --git a/llvm/include/llvm/Object/WindowsResource.h b/llvm/include/llvm/Object/WindowsResource.h
index 3d32409fd4a..844256478cf 100644
--- a/llvm/include/llvm/Object/WindowsResource.h
+++ b/llvm/include/llvm/Object/WindowsResource.h
@@ -47,44 +47,6 @@ namespace object {
class WindowsResource;
-const size_t WIN_RES_MAGIC_SIZE = 16;
-const size_t WIN_RES_NULL_ENTRY_SIZE = 16;
-const uint32_t WIN_RES_HEADER_ALIGNMENT = 4;
-const uint32_t WIN_RES_DATA_ALIGNMENT = 4;
-const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030;
-
-struct WinResHeaderPrefix {
- support::ulittle32_t DataSize;
- support::ulittle32_t HeaderSize;
-};
-
-// Type and Name may each either be an integer ID or a string. This struct is
-// only used in the case where they are both IDs.
-struct WinResIDs {
- uint16_t TypeFlag;
- support::ulittle16_t TypeID;
- uint16_t NameFlag;
- support::ulittle16_t NameID;
-
- void setType(uint16_t ID) {
- TypeFlag = 0xffff;
- TypeID = ID;
- }
-
- void setName(uint16_t ID) {
- NameFlag = 0xffff;
- NameID = ID;
- }
-};
-
-struct WinResHeaderSuffix {
- support::ulittle32_t DataVersion;
- support::ulittle16_t MemoryFlags;
- support::ulittle16_t Language;
- support::ulittle32_t Version;
- support::ulittle32_t Characteristics;
-};
-
class ResourceEntryRef {
public:
Error moveNext(bool &End);
@@ -108,6 +70,14 @@ private:
Error loadNext();
+ struct HeaderSuffix {
+ support::ulittle32_t DataVersion;
+ support::ulittle16_t MemoryFlags;
+ support::ulittle16_t Language;
+ support::ulittle32_t Version;
+ support::ulittle32_t Characteristics;
+ };
+
BinaryStreamReader Reader;
bool IsStringType;
ArrayRef<UTF16> Type;
@@ -115,7 +85,7 @@ private:
bool IsStringName;
ArrayRef<UTF16> Name;
uint16_t NameID;
- const WinResHeaderSuffix *Suffix = nullptr;
+ const HeaderSuffix *Suffix = nullptr;
ArrayRef<uint8_t> Data;
const WindowsResource *OwningRes = nullptr;
};
diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp
index b19a07a9066..5d0a71fc780 100644
--- a/llvm/lib/BinaryFormat/Magic.cpp
+++ b/llvm/lib/BinaryFormat/Magic.cpp
@@ -51,8 +51,7 @@ file_magic llvm::identify_magic(StringRef Magic) {
return file_magic::coff_import_library;
}
// Windows resource file
- if (Magic.size() >= sizeof(COFF::WinResMagic) &&
- memcmp(Magic.data(), COFF::WinResMagic, sizeof(COFF::WinResMagic)) == 0)
+ if (startswith(Magic, "\0\0\0\0\x20\0\0\0\xFF"))
return file_magic::windows_resource;
// 0x0000 = COFF unknown machine type
if (Magic[1] == 0)
diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp
index 1371eacdf8f..f675a8389e6 100644
--- a/llvm/lib/Object/WindowsResource.cpp
+++ b/llvm/lib/Object/WindowsResource.cpp
@@ -36,19 +36,23 @@ const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
// 8-byte because it makes everyone happy.
const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
+static const size_t ResourceMagicSize = 16;
+
+static const size_t NullEntrySize = 16;
+
uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
WindowsResource::WindowsResource(MemoryBufferRef Source)
: Binary(Binary::ID_WinRes, Source) {
- size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
+ size_t LeadingSize = ResourceMagicSize + NullEntrySize;
BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
support::little);
}
Expected<std::unique_ptr<WindowsResource>>
WindowsResource::createWindowsResource(MemoryBufferRef Source) {
- if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
+ if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
return make_error<GenericBinaryError>(
"File too small to be a resource file",
object_error::invalid_file_type);
@@ -101,10 +105,12 @@ static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
}
Error ResourceEntryRef::loadNext() {
- const WinResHeaderPrefix *Prefix;
- RETURN_IF_ERROR(Reader.readObject(Prefix));
+ uint32_t DataSize;
+ RETURN_IF_ERROR(Reader.readInteger(DataSize));
+ uint32_t HeaderSize;
+ RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
- if (Prefix->HeaderSize < MIN_HEADER_SIZE)
+ if (HeaderSize < MIN_HEADER_SIZE)
return make_error<GenericBinaryError>("Header size is too small.",
object_error::parse_failed);
@@ -112,13 +118,13 @@ Error ResourceEntryRef::loadNext() {
RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
- RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
+ RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
RETURN_IF_ERROR(Reader.readObject(Suffix));
- RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
+ RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
- RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
+ RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
return Error::success();
}
@@ -462,6 +468,8 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
SectionOneHeader->PointerToLinenumbers = 0;
SectionOneHeader->NumberOfRelocations = Data.size();
SectionOneHeader->NumberOfLinenumbers = 0;
+ SectionOneHeader->Characteristics = COFF::IMAGE_SCN_ALIGN_1BYTES;
+ SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
}
diff --git a/llvm/unittests/BinaryFormat/TestFileMagic.cpp b/llvm/unittests/BinaryFormat/TestFileMagic.cpp
index 68b3ade0095..fc2c1eef9fb 100644
--- a/llvm/unittests/BinaryFormat/TestFileMagic.cpp
+++ b/llvm/unittests/BinaryFormat/TestFileMagic.cpp
@@ -76,8 +76,7 @@ const char macho_dsym_companion[] =
"\xfe\xed\xfa\xce........\x00\x00\x00\x0a............";
const char macho_kext_bundle[] =
"\xfe\xed\xfa\xce........\x00\x00\x00\x0b............";
-const char windows_resource[] =
- "\x00\x00\x00\x00\x020\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00";
+const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff";
const char macho_dynamically_linked_shared_lib_stub[] =
"\xfe\xed\xfa\xce........\x00\x00\x00\x09............";
OpenPOWER on IntegriCloud