diff options
-rw-r--r-- | lld/COFF/DriverUtils.cpp | 109 | ||||
-rw-r--r-- | lld/test/COFF/manifestinput.test | 25 | ||||
-rw-r--r-- | lld/test/lit.cfg | 5 | ||||
-rw-r--r-- | llvm/include/llvm/BinaryFormat/COFF.h | 6 | ||||
-rw-r--r-- | llvm/include/llvm/Object/WindowsResource.h | 48 | ||||
-rw-r--r-- | llvm/lib/BinaryFormat/Magic.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/Object/WindowsResource.cpp | 24 | ||||
-rw-r--r-- | llvm/unittests/BinaryFormat/TestFileMagic.cpp | 3 |
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............"; |