forked from OSchip/llvm-project
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. llvm-svn: 307460
This commit is contained in:
parent
41f6a453e4
commit
c8dba240b1
|
@ -20,12 +20,15 @@
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
#include "llvm/BinaryFormat/COFF.h"
|
||||||
#include "llvm/Object/COFF.h"
|
#include "llvm/Object/COFF.h"
|
||||||
|
#include "llvm/Object/WindowsResource.h"
|
||||||
#include "llvm/Option/Arg.h"
|
#include "llvm/Option/Arg.h"
|
||||||
#include "llvm/Option/ArgList.h"
|
#include "llvm/Option/ArgList.h"
|
||||||
#include "llvm/Option/Option.h"
|
#include "llvm/Option/Option.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/FileUtilities.h"
|
#include "llvm/Support/FileUtilities.h"
|
||||||
|
#include "llvm/Support/MathExtras.h"
|
||||||
#include "llvm/Support/Process.h"
|
#include "llvm/Support/Process.h"
|
||||||
#include "llvm/Support/Program.h"
|
#include "llvm/Support/Program.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
@ -41,6 +44,9 @@ namespace lld {
|
||||||
namespace coff {
|
namespace coff {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const uint16_t SUBLANG_ENGLISH_US = 0x0409;
|
||||||
|
const uint16_t RT_MANIFEST = 24;
|
||||||
|
|
||||||
class Executor {
|
class Executor {
|
||||||
public:
|
public:
|
||||||
explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
|
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.
|
// An RAII temporary file class that automatically removes a temporary file.
|
||||||
namespace {
|
namespace {
|
||||||
class TemporaryFile {
|
class TemporaryFile {
|
||||||
|
@ -393,38 +379,62 @@ static std::string createManifestXml() {
|
||||||
return readFile(File2.Path);
|
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.
|
// Create a resource file containing a manifest XML.
|
||||||
std::unique_ptr<MemoryBuffer> createManifestRes() {
|
std::unique_ptr<MemoryBuffer> createManifestRes() {
|
||||||
// Create a temporary file for the resource script file.
|
std::string Manifest = createManifestXml();
|
||||||
TemporaryFile RCFile("manifest", "rc");
|
|
||||||
|
|
||||||
// Open the temporary file for writing.
|
std::unique_ptr<MemoryBuffer> Res =
|
||||||
std::error_code EC;
|
createMemoryBufferForManifestRes(Manifest.size());
|
||||||
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.
|
char *Buf = const_cast<char *>(Res->getBufferStart());
|
||||||
Out << "#define LANG_ENGLISH 9\n"
|
writeResFileHeader(Buf);
|
||||||
<< "#define SUBLANG_DEFAULT 1\n"
|
writeResEntryHeader(Buf, Manifest.size());
|
||||||
<< "#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.
|
// Copy the manifest data into the .res file.
|
||||||
TemporaryFile ResFile("output-resource", "res");
|
std::copy(Manifest.begin(), Manifest.end(), Buf);
|
||||||
|
return 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() {
|
void createSideBySideManifest() {
|
||||||
|
@ -595,40 +605,22 @@ void checkFailIfMismatch(StringRef Arg) {
|
||||||
// using cvtres.exe.
|
// using cvtres.exe.
|
||||||
std::unique_ptr<MemoryBuffer>
|
std::unique_ptr<MemoryBuffer>
|
||||||
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
|
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
|
||||||
// Create an output file path.
|
object::WindowsResourceParser Parser;
|
||||||
TemporaryFile File("resource-file", "obj");
|
|
||||||
|
|
||||||
// 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) {
|
for (MemoryBufferRef MB : MBs) {
|
||||||
// We store the temporary file in a vector to avoid deletion
|
std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB));
|
||||||
// before running cvtres
|
object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
|
||||||
ResFiles.emplace_back("resource-file", "res");
|
if (!RF)
|
||||||
TemporaryFile& ResFile = ResFiles.back();
|
fatal("cannot compile non-resource file as resource");
|
||||||
// Write the content of the resource in a temporary file
|
if (auto EC = Parser.parse(RF))
|
||||||
std::error_code EC;
|
fatal(EC, "failed to parse .res file");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
E.run();
|
Expected<std::unique_ptr<MemoryBuffer>> E =
|
||||||
return File.getMemoryBuffer();
|
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.
|
// Run MSVC link.exe for given in-memory object files.
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
// > rc /fo combined-resources.res /nologo combined-resources.rc
|
// > rc /fo combined-resources.res /nologo combined-resources.rc
|
||||||
// > rc /fo combined-resources-2.res /nologo combined-resources-2.rc
|
// > rc /fo combined-resources-2.res /nologo combined-resources-2.rc
|
||||||
|
|
||||||
# REQUIRES: winres
|
|
||||||
|
|
||||||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||||
# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \
|
# 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
|
# RUN: %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# REQUIRES: winres
|
|
||||||
|
|
||||||
# RUN: rm -rf %t
|
# RUN: rm -rf %t
|
||||||
# RUN: mkdir -p %t
|
# RUN: mkdir -p %t
|
||||||
# RUN: cd %t
|
# RUN: cd %t
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# REQUIRES: winres
|
|
||||||
|
|
||||||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||||
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \
|
||||||
# RUN: /export:mangled
|
# RUN: /export:mangled
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# REQUIRES: winres
|
|
||||||
|
|
||||||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj
|
# RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj
|
||||||
# RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1
|
# RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# REQUIRES: winres
|
# REQUIRES: win_mt
|
||||||
|
|
||||||
# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
|
# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
|
||||||
# RUN: lld-link /out:%t.exe /entry:main \
|
# RUN: lld-link /out:%t.exe /entry:main \
|
||||||
|
@ -8,3 +8,28 @@
|
||||||
|
|
||||||
CHECK: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
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>
|
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
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# REQUIRES: winres
|
|
||||||
|
|
||||||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||||
# RUN: lld-link /out:%t.dll /dll %t.obj
|
# RUN: lld-link /out:%t.dll /dll %t.obj
|
||||||
# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s
|
# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# REQUIRES: winres
|
|
||||||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||||
|
|
||||||
# RUN: mkdir -p %T/out/tmp
|
# RUN: mkdir -p %T/out/tmp
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
# REQUIRES: winres
|
|
||||||
|
|
||||||
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj
|
||||||
# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
|
# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res
|
||||||
|
|
||||||
|
|
|
@ -264,8 +264,7 @@ llvm_config_cmd.wait()
|
||||||
# Set a fake constant version so that we get consitent output.
|
# Set a fake constant version so that we get consitent output.
|
||||||
config.environment['LLD_VERSION'] = 'LLD 1.0'
|
config.environment['LLD_VERSION'] = 'LLD 1.0'
|
||||||
|
|
||||||
# Check if Windows resource file compiler exists.
|
# Indirectly check if the mt.exe Microsoft utility exists by searching for
|
||||||
cvtres = lit.util.which('cvtres', config.environment['PATH'])
|
# cvtres, which always accompanies it.
|
||||||
rc = lit.util.which('rc', config.environment['PATH'])
|
if lit.util.which('cvtres', config.environment['PATH']):
|
||||||
if cvtres and rc:
|
config.available_features.add('win_mt')
|
||||||
config.available_features.add('winres')
|
|
||||||
|
|
|
@ -46,6 +46,12 @@ static const char ClGlObjMagic[] = {
|
||||||
'\xac', '\x9b', '\xd6', '\xb6', '\x22', '\x26', '\x53', '\xc2',
|
'\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.
|
// Sizes in bytes of various things in the COFF format.
|
||||||
enum {
|
enum {
|
||||||
Header16Size = 20,
|
Header16Size = 20,
|
||||||
|
|
|
@ -43,12 +43,47 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
namespace object {
|
namespace object {
|
||||||
|
|
||||||
class WindowsResource;
|
class WindowsResource;
|
||||||
|
|
||||||
enum class Machine { UNKNOWN, ARM, X64, X86 };
|
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 {
|
class ResourceEntryRef {
|
||||||
public:
|
public:
|
||||||
|
@ -73,14 +108,6 @@ private:
|
||||||
|
|
||||||
Error loadNext();
|
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;
|
BinaryStreamReader Reader;
|
||||||
bool IsStringType;
|
bool IsStringType;
|
||||||
ArrayRef<UTF16> Type;
|
ArrayRef<UTF16> Type;
|
||||||
|
@ -88,7 +115,7 @@ private:
|
||||||
bool IsStringName;
|
bool IsStringName;
|
||||||
ArrayRef<UTF16> Name;
|
ArrayRef<UTF16> Name;
|
||||||
uint16_t NameID;
|
uint16_t NameID;
|
||||||
const HeaderSuffix *Suffix = nullptr;
|
const WinResHeaderSuffix *Suffix = nullptr;
|
||||||
ArrayRef<uint8_t> Data;
|
ArrayRef<uint8_t> Data;
|
||||||
const WindowsResource *OwningRes = nullptr;
|
const WindowsResource *OwningRes = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,7 +51,8 @@ file_magic llvm::identify_magic(StringRef Magic) {
|
||||||
return file_magic::coff_import_library;
|
return file_magic::coff_import_library;
|
||||||
}
|
}
|
||||||
// Windows resource file
|
// Windows resource file
|
||||||
if (startswith(Magic, "\0\0\0\0\x20\0\0\0\xFF"))
|
if (Magic.size() >= sizeof(COFF::WinResMagic) &&
|
||||||
|
memcmp(Magic.data(), COFF::WinResMagic, sizeof(COFF::WinResMagic)) == 0)
|
||||||
return file_magic::windows_resource;
|
return file_magic::windows_resource;
|
||||||
// 0x0000 = COFF unknown machine type
|
// 0x0000 = COFF unknown machine type
|
||||||
if (Magic[1] == 0)
|
if (Magic[1] == 0)
|
||||||
|
|
|
@ -36,23 +36,19 @@ const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
|
||||||
// 8-byte because it makes everyone happy.
|
// 8-byte because it makes everyone happy.
|
||||||
const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
|
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::StringCount = 0;
|
||||||
uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
|
uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
|
||||||
|
|
||||||
WindowsResource::WindowsResource(MemoryBufferRef Source)
|
WindowsResource::WindowsResource(MemoryBufferRef Source)
|
||||||
: Binary(Binary::ID_WinRes, Source) {
|
: Binary(Binary::ID_WinRes, Source) {
|
||||||
size_t LeadingSize = ResourceMagicSize + NullEntrySize;
|
size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
|
||||||
BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
|
BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
|
||||||
support::little);
|
support::little);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expected<std::unique_ptr<WindowsResource>>
|
Expected<std::unique_ptr<WindowsResource>>
|
||||||
WindowsResource::createWindowsResource(MemoryBufferRef Source) {
|
WindowsResource::createWindowsResource(MemoryBufferRef Source) {
|
||||||
if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
|
if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
|
||||||
return make_error<GenericBinaryError>(
|
return make_error<GenericBinaryError>(
|
||||||
"File too small to be a resource file",
|
"File too small to be a resource file",
|
||||||
object_error::invalid_file_type);
|
object_error::invalid_file_type);
|
||||||
|
@ -105,12 +101,10 @@ static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
Error ResourceEntryRef::loadNext() {
|
Error ResourceEntryRef::loadNext() {
|
||||||
uint32_t DataSize;
|
const WinResHeaderPrefix *Prefix;
|
||||||
RETURN_IF_ERROR(Reader.readInteger(DataSize));
|
RETURN_IF_ERROR(Reader.readObject(Prefix));
|
||||||
uint32_t HeaderSize;
|
|
||||||
RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
|
|
||||||
|
|
||||||
if (HeaderSize < MIN_HEADER_SIZE)
|
if (Prefix->HeaderSize < MIN_HEADER_SIZE)
|
||||||
return make_error<GenericBinaryError>("Header size is too small.",
|
return make_error<GenericBinaryError>("Header size is too small.",
|
||||||
object_error::parse_failed);
|
object_error::parse_failed);
|
||||||
|
|
||||||
|
@ -118,13 +112,13 @@ Error ResourceEntryRef::loadNext() {
|
||||||
|
|
||||||
RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
|
RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
|
||||||
|
|
||||||
RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
|
RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
|
||||||
|
|
||||||
RETURN_IF_ERROR(Reader.readObject(Suffix));
|
RETURN_IF_ERROR(Reader.readObject(Suffix));
|
||||||
|
|
||||||
RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
|
RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
|
||||||
|
|
||||||
RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
|
RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
@ -350,6 +344,7 @@ WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
|
||||||
: MachineType(MachineType), Resources(Parser.getTree()),
|
: MachineType(MachineType), Resources(Parser.getTree()),
|
||||||
Data(Parser.getData()), StringTable(Parser.getStringTable()) {
|
Data(Parser.getData()), StringTable(Parser.getStringTable()) {
|
||||||
performFileLayout();
|
performFileLayout();
|
||||||
|
|
||||||
OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize);
|
OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,8 +462,6 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
|
||||||
SectionOneHeader->PointerToLinenumbers = 0;
|
SectionOneHeader->PointerToLinenumbers = 0;
|
||||||
SectionOneHeader->NumberOfRelocations = Data.size();
|
SectionOneHeader->NumberOfRelocations = Data.size();
|
||||||
SectionOneHeader->NumberOfLinenumbers = 0;
|
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_CNT_INITIALIZED_DATA;
|
||||||
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
|
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,6 +207,7 @@ int main(int argc_, const char *argv_[]) {
|
||||||
std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
|
std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
|
||||||
FileBuffer->getBufferStart());
|
FileBuffer->getBufferStart());
|
||||||
error(FileBuffer->commit());
|
error(FileBuffer->commit());
|
||||||
|
|
||||||
if (Verbose) {
|
if (Verbose) {
|
||||||
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
|
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
|
||||||
if (!BinaryOrErr)
|
if (!BinaryOrErr)
|
||||||
|
|
|
@ -76,7 +76,8 @@ const char macho_dsym_companion[] =
|
||||||
"\xfe\xed\xfa\xce........\x00\x00\x00\x0a............";
|
"\xfe\xed\xfa\xce........\x00\x00\x00\x0a............";
|
||||||
const char macho_kext_bundle[] =
|
const char macho_kext_bundle[] =
|
||||||
"\xfe\xed\xfa\xce........\x00\x00\x00\x0b............";
|
"\xfe\xed\xfa\xce........\x00\x00\x00\x0b............";
|
||||||
const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff";
|
const char windows_resource[] =
|
||||||
|
"\x00\x00\x00\x00\x020\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00";
|
||||||
const char macho_dynamically_linked_shared_lib_stub[] =
|
const char macho_dynamically_linked_shared_lib_stub[] =
|
||||||
"\xfe\xed\xfa\xce........\x00\x00\x00\x09............";
|
"\xfe\xed\xfa\xce........\x00\x00\x00\x09............";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue