Skip to content

Commit 1d50926

Browse files
author
Eric Beckmann
committed
Revert "Revert "Replace trivial use of external rc.exe by writing our own .res file.""
This reverts commit 8c8dce3b8f15d6ebaefc35ce88f15a85c8cdbd6e. llvm-svn: 307191
1 parent 0eafa58 commit 1d50926

File tree

8 files changed

+145
-78
lines changed

8 files changed

+145
-78
lines changed

lld/COFF/DriverUtils.cpp

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
#include "Symbols.h"
2121
#include "llvm/ADT/Optional.h"
2222
#include "llvm/ADT/StringSwitch.h"
23+
#include "llvm/BinaryFormat/COFF.h"
2324
#include "llvm/Object/COFF.h"
2425
#include "llvm/Object/WindowsResource.h"
2526
#include "llvm/Option/Arg.h"
2627
#include "llvm/Option/ArgList.h"
2728
#include "llvm/Option/Option.h"
2829
#include "llvm/Support/CommandLine.h"
2930
#include "llvm/Support/FileUtilities.h"
31+
#include "llvm/Support/MathExtras.h"
3032
#include "llvm/Support/Process.h"
3133
#include "llvm/Support/Program.h"
3234
#include "llvm/Support/raw_ostream.h"
@@ -42,6 +44,9 @@ namespace lld {
4244
namespace coff {
4345
namespace {
4446

47+
const uint16_t SUBLANG_ENGLISH_US = 0x0409;
48+
const uint16_t RT_MANIFEST = 24;
49+
4550
class Executor {
4651
public:
4752
explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
@@ -261,26 +266,6 @@ void parseManifestUAC(StringRef Arg) {
261266
}
262267
}
263268

264-
// Quote each line with "". Existing double-quote is converted
265-
// to two double-quotes.
266-
static void quoteAndPrint(raw_ostream &Out, StringRef S) {
267-
while (!S.empty()) {
268-
StringRef Line;
269-
std::tie(Line, S) = S.split("\n");
270-
if (Line.empty())
271-
continue;
272-
Out << '\"';
273-
for (int I = 0, E = Line.size(); I != E; ++I) {
274-
if (Line[I] == '\"') {
275-
Out << "\"\"";
276-
} else {
277-
Out << Line[I];
278-
}
279-
}
280-
Out << "\"\n";
281-
}
282-
}
283-
284269
// An RAII temporary file class that automatically removes a temporary file.
285270
namespace {
286271
class TemporaryFile {
@@ -394,38 +379,64 @@ static std::string createManifestXml() {
394379
return readFile(File2.Path);
395380
}
396381

382+
static std::unique_ptr<MemoryBuffer>
383+
createMemoryBufferForManifestRes(size_t ManifestSize) {
384+
size_t ResSize = alignTo(object::WIN_RES_MAGIC_SIZE +
385+
object::WIN_RES_NULL_ENTRY_SIZE +
386+
sizeof(object::WinResHeaderPrefix) +
387+
sizeof(object::WinResIDs) +
388+
sizeof(object::WinResHeaderSuffix) +
389+
ManifestSize,
390+
object::WIN_RES_DATA_ALIGNMENT);
391+
return MemoryBuffer::getNewMemBuffer(ResSize);
392+
}
393+
394+
static void writeResFileHeader(char *&Buf) {
395+
memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
396+
Buf += sizeof(COFF::WinResMagic);
397+
memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
398+
Buf += object::WIN_RES_NULL_ENTRY_SIZE;
399+
}
400+
401+
static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
402+
// Write the prefix.
403+
auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf);
404+
Prefix->DataSize = ManifestSize;
405+
Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
406+
sizeof(object::WinResIDs) +
407+
sizeof(object::WinResHeaderSuffix);
408+
Buf += sizeof(object::WinResHeaderPrefix);
409+
410+
// Write the Type/Name IDs.
411+
auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf);
412+
IDs->setType(RT_MANIFEST);
413+
IDs->setName(Config->ManifestID);
414+
Buf += sizeof(object::WinResIDs);
415+
416+
// Write the suffix.
417+
auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf);
418+
Suffix->DataVersion = 0;
419+
Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
420+
Suffix->Language = SUBLANG_ENGLISH_US;
421+
Suffix->Version = 0;
422+
Suffix->Characteristics = 0;
423+
Buf += sizeof(object::WinResHeaderSuffix);
424+
}
425+
397426
// Create a resource file containing a manifest XML.
398427
std::unique_ptr<MemoryBuffer> createManifestRes() {
399-
// Create a temporary file for the resource script file.
400-
TemporaryFile RCFile("manifest", "rc");
428+
std::string Manifest = createManifestXml();
401429

402-
// Open the temporary file for writing.
403-
std::error_code EC;
404-
raw_fd_ostream Out(RCFile.Path, EC, sys::fs::F_Text);
405-
if (EC)
406-
fatal(EC, "failed to open " + RCFile.Path);
407-
408-
// Write resource script to the RC file.
409-
Out << "#define LANG_ENGLISH 9\n"
410-
<< "#define SUBLANG_DEFAULT 1\n"
411-
<< "#define APP_MANIFEST " << Config->ManifestID << "\n"
412-
<< "#define RT_MANIFEST 24\n"
413-
<< "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
414-
<< "APP_MANIFEST RT_MANIFEST {\n";
415-
quoteAndPrint(Out, createManifestXml());
416-
Out << "}\n";
417-
Out.close();
418-
419-
// Create output resource file.
420-
TemporaryFile ResFile("output-resource", "res");
421-
422-
Executor E("rc.exe");
423-
E.add("/fo");
424-
E.add(ResFile.Path);
425-
E.add("/nologo");
426-
E.add(RCFile.Path);
427-
E.run();
428-
return ResFile.getMemoryBuffer();
430+
std::unique_ptr<MemoryBuffer> Res =
431+
createMemoryBufferForManifestRes(Manifest.size());
432+
433+
char *Buf = const_cast<char *>(Res->getBufferStart());
434+
writeResFileHeader(Buf);
435+
writeResEntryHeader(Buf, Manifest.size());
436+
437+
// Copy the manifest data into the .res file.
438+
std::copy(Manifest.begin(), Manifest.end(), Buf);
439+
return Res;
429440
}
430441

431442
void createSideBySideManifest() {

lld/test/COFF/manifestinput.test

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,28 @@
88

99
CHECK: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
1010
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>
11+
12+
# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
13+
# RUN: lld-link /out:%t.exe /entry:main \
14+
# RUN: /manifest:embed \
15+
# RUN: /manifestuac:"level='requireAdministrator'" \
16+
# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj
17+
# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \
18+
# RUN: -check-prefix TEST_EMBED
19+
20+
TEST_EMBED: ResourceTableRVA: 0x1000
21+
TEST_EMBED-NEXT: ResourceTableSize: 0x298
22+
TEST_EMBED-DAG: Resources [
23+
TEST_EMBED-NEXT: Total Number of Resources: 1
24+
TEST_EMBED-DAG: Number of String Entries: 0
25+
TEST_EMBED-NEXT: Number of ID Entries: 1
26+
TEST_EMBED-NEXT: Type: kRT_MANIFEST (ID 24) [
27+
TEST_EMBED-NEXT: Table Offset: 0x18
28+
TEST_EMBED-NEXT: Number of String Entries: 0
29+
TEST_EMBED-NEXT: Number of ID Entries: 1
30+
TEST_EMBED-NEXT: Name: (ID 1) [
31+
TEST_EMBED-NEXT: Table Offset: 0x30
32+
TEST_EMBED-NEXT: Number of String Entries: 0
33+
TEST_EMBED-NEXT: Number of ID Entries: 1
34+
TEST_EMBED-NEXT: Language: (ID 1033) [
35+
TEST_EMBED-NEXT: Entry Offset: 0x48

lld/test/lit.cfg

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ llvm_config_cmd.wait()
264264
# Set a fake constant version so that we get consitent output.
265265
config.environment['LLD_VERSION'] = 'LLD 1.0'
266266

267-
# Check if the mt.exe Microsoft utility exists.
268-
if lit.util.which('mt.exe', config.environment['PATH']):
267+
# Indirectly check if the mt.exe Microsoft utility exists by searching for
268+
# cvtres, which always accompanies it.
269+
if lit.util.which('cvtres', config.environment['PATH']):
269270
config.available_features.add('win_mt')

llvm/include/llvm/BinaryFormat/COFF.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ static const char ClGlObjMagic[] = {
4646
'\xac', '\x9b', '\xd6', '\xb6', '\x22', '\x26', '\x53', '\xc2',
4747
};
4848

49+
// The signature bytes that start a .res file.
50+
static const char WinResMagic[] = {
51+
'\x00', '\x00', '\x00', '\x00', '\x20', '\x00', '\x00', '\x00',
52+
'\xff', '\xff', '\x00', '\x00', '\xff', '\xff', '\x00', '\x00',
53+
};
54+
4955
// Sizes in bytes of various things in the COFF format.
5056
enum {
5157
Header16Size = 20,

llvm/include/llvm/Object/WindowsResource.h

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,44 @@ namespace object {
4747

4848
class WindowsResource;
4949

50+
const size_t WIN_RES_MAGIC_SIZE = 16;
51+
const size_t WIN_RES_NULL_ENTRY_SIZE = 16;
52+
const uint32_t WIN_RES_HEADER_ALIGNMENT = 4;
53+
const uint32_t WIN_RES_DATA_ALIGNMENT = 4;
54+
const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030;
55+
56+
struct WinResHeaderPrefix {
57+
support::ulittle32_t DataSize;
58+
support::ulittle32_t HeaderSize;
59+
};
60+
61+
// Type and Name may each either be an integer ID or a string. This struct is
62+
// only used in the case where they are both IDs.
63+
struct WinResIDs {
64+
uint16_t TypeFlag;
65+
support::ulittle16_t TypeID;
66+
uint16_t NameFlag;
67+
support::ulittle16_t NameID;
68+
69+
void setType(uint16_t ID) {
70+
TypeFlag = 0xffff;
71+
TypeID = ID;
72+
}
73+
74+
void setName(uint16_t ID) {
75+
NameFlag = 0xffff;
76+
NameID = ID;
77+
}
78+
};
79+
80+
struct WinResHeaderSuffix {
81+
support::ulittle32_t DataVersion;
82+
support::ulittle16_t MemoryFlags;
83+
support::ulittle16_t Language;
84+
support::ulittle32_t Version;
85+
support::ulittle32_t Characteristics;
86+
};
87+
5088
class ResourceEntryRef {
5189
public:
5290
Error moveNext(bool &End);
@@ -70,22 +108,14 @@ class ResourceEntryRef {
70108

71109
Error loadNext();
72110

73-
struct HeaderSuffix {
74-
support::ulittle32_t DataVersion;
75-
support::ulittle16_t MemoryFlags;
76-
support::ulittle16_t Language;
77-
support::ulittle32_t Version;
78-
support::ulittle32_t Characteristics;
79-
};
80-
81111
BinaryStreamReader Reader;
82112
bool IsStringType;
83113
ArrayRef<UTF16> Type;
84114
uint16_t TypeID;
85115
bool IsStringName;
86116
ArrayRef<UTF16> Name;
87117
uint16_t NameID;
88-
const HeaderSuffix *Suffix = nullptr;
118+
const WinResHeaderSuffix *Suffix = nullptr;
89119
ArrayRef<uint8_t> Data;
90120
const WindowsResource *OwningRes = nullptr;
91121
};

llvm/lib/BinaryFormat/Magic.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ file_magic llvm::identify_magic(StringRef Magic) {
5151
return file_magic::coff_import_library;
5252
}
5353
// Windows resource file
54-
if (startswith(Magic, "\0\0\0\0\x20\0\0\0\xFF"))
54+
if (Magic.size() >= sizeof(COFF::WinResMagic) &&
55+
memcmp(Magic.data(), COFF::WinResMagic, sizeof(COFF::WinResMagic)) == 0)
5556
return file_magic::windows_resource;
5657
// 0x0000 = COFF unknown machine type
5758
if (Magic[1] == 0)

llvm/lib/Object/WindowsResource.cpp

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,19 @@ const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
3636
// 8-byte because it makes everyone happy.
3737
const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
3838

39-
static const size_t ResourceMagicSize = 16;
40-
41-
static const size_t NullEntrySize = 16;
42-
4339
uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
4440
uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
4541

4642
WindowsResource::WindowsResource(MemoryBufferRef Source)
4743
: Binary(Binary::ID_WinRes, Source) {
48-
size_t LeadingSize = ResourceMagicSize + NullEntrySize;
44+
size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
4945
BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
5046
support::little);
5147
}
5248

5349
Expected<std::unique_ptr<WindowsResource>>
5450
WindowsResource::createWindowsResource(MemoryBufferRef Source) {
55-
if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
51+
if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
5652
return make_error<GenericBinaryError>(
5753
"File too small to be a resource file",
5854
object_error::invalid_file_type);
@@ -105,26 +101,24 @@ static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
105101
}
106102

107103
Error ResourceEntryRef::loadNext() {
108-
uint32_t DataSize;
109-
RETURN_IF_ERROR(Reader.readInteger(DataSize));
110-
uint32_t HeaderSize;
111-
RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
104+
const WinResHeaderPrefix *Prefix;
105+
RETURN_IF_ERROR(Reader.readObject(Prefix));
112106

113-
if (HeaderSize < MIN_HEADER_SIZE)
107+
if (Prefix->HeaderSize < MIN_HEADER_SIZE)
114108
return make_error<GenericBinaryError>("Header size is too small.",
115109
object_error::parse_failed);
116110

117111
RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
118112

119113
RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
120114

121-
RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
115+
RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
122116

123117
RETURN_IF_ERROR(Reader.readObject(Suffix));
124118

125-
RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
119+
RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
126120

127-
RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
121+
RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
128122

129123
return Error::success();
130124
}
@@ -468,8 +462,6 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
468462
SectionOneHeader->PointerToLinenumbers = 0;
469463
SectionOneHeader->NumberOfRelocations = Data.size();
470464
SectionOneHeader->NumberOfLinenumbers = 0;
471-
SectionOneHeader->Characteristics = COFF::IMAGE_SCN_ALIGN_1BYTES;
472-
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
473465
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
474466
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
475467
}

llvm/unittests/BinaryFormat/TestFileMagic.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ const char macho_dsym_companion[] =
7676
"\xfe\xed\xfa\xce........\x00\x00\x00\x0a............";
7777
const char macho_kext_bundle[] =
7878
"\xfe\xed\xfa\xce........\x00\x00\x00\x0b............";
79-
const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff";
79+
const char windows_resource[] =
80+
"\x00\x00\x00\x00\x020\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00";
8081
const char macho_dynamically_linked_shared_lib_stub[] =
8182
"\xfe\xed\xfa\xce........\x00\x00\x00\x09............";
8283

0 commit comments

Comments
 (0)