Skip to content

Commit 81979b0

Browse files
author
Eric Beckmann
committed
Revert "Revert "Revert "Replace trivial use of external rc.exe by writing our own .res file."""
This reverts commit 5fecbbbe5049665d86834cf69d8f75db4f392308. The initial revert was done in order to prevent ongoing errors on chromium bots such as CrWinClangLLD. However, this was done haphazardly and I didn't realize there were test and compilation failures, so this revert was reverted. Now that those have been fixed, we can revert the revert of the revert. llvm-svn: 307226
1 parent 2126334 commit 81979b0

File tree

8 files changed

+78
-145
lines changed

8 files changed

+78
-145
lines changed

lld/COFF/DriverUtils.cpp

+49-60
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@
2020
#include "Symbols.h"
2121
#include "llvm/ADT/Optional.h"
2222
#include "llvm/ADT/StringSwitch.h"
23-
#include "llvm/BinaryFormat/COFF.h"
2423
#include "llvm/Object/COFF.h"
2524
#include "llvm/Object/WindowsResource.h"
2625
#include "llvm/Option/Arg.h"
2726
#include "llvm/Option/ArgList.h"
2827
#include "llvm/Option/Option.h"
2928
#include "llvm/Support/CommandLine.h"
3029
#include "llvm/Support/FileUtilities.h"
31-
#include "llvm/Support/MathExtras.h"
3230
#include "llvm/Support/Process.h"
3331
#include "llvm/Support/Program.h"
3432
#include "llvm/Support/raw_ostream.h"
@@ -44,9 +42,6 @@ namespace lld {
4442
namespace coff {
4543
namespace {
4644

47-
const uint16_t SUBLANG_ENGLISH_US = 0x0409;
48-
const uint16_t RT_MANIFEST = 24;
49-
5045
class Executor {
5146
public:
5247
explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
@@ -266,6 +261,26 @@ void parseManifestUAC(StringRef Arg) {
266261
}
267262
}
268263

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+
269284
// An RAII temporary file class that automatically removes a temporary file.
270285
namespace {
271286
class TemporaryFile {
@@ -379,64 +394,38 @@ static std::string createManifestXml() {
379394
return readFile(File2.Path);
380395
}
381396

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-
426397
// Create a resource file containing a manifest XML.
427398
std::unique_ptr<MemoryBuffer> createManifestRes() {
428-
std::string Manifest = createManifestXml();
429-
430-
std::unique_ptr<MemoryBuffer> Res =
431-
createMemoryBufferForManifestRes(Manifest.size());
399+
// Create a temporary file for the resource script file.
400+
TemporaryFile RCFile("manifest", "rc");
432401

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;
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();
440429
}
441430

442431
void createSideBySideManifest() {

lld/test/COFF/manifestinput.test

-25
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,3 @@
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

+2-3
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ 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-
# 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']):
267+
# Check if the mt.exe Microsoft utility exists.
268+
if lit.util.which('mt.exe', config.environment['PATH']):
270269
config.available_features.add('win_mt')

llvm/include/llvm/BinaryFormat/COFF.h

-6
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ 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-
5549
// Sizes in bytes of various things in the COFF format.
5650
enum {
5751
Header16Size = 20,

llvm/include/llvm/Object/WindowsResource.h

+9-39
Original file line numberDiff line numberDiff line change
@@ -47,44 +47,6 @@ 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-
8850
class ResourceEntryRef {
8951
public:
9052
Error moveNext(bool &End);
@@ -108,14 +70,22 @@ class ResourceEntryRef {
10870

10971
Error loadNext();
11072

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+
11181
BinaryStreamReader Reader;
11282
bool IsStringType;
11383
ArrayRef<UTF16> Type;
11484
uint16_t TypeID;
11585
bool IsStringName;
11686
ArrayRef<UTF16> Name;
11787
uint16_t NameID;
118-
const WinResHeaderSuffix *Suffix = nullptr;
88+
const HeaderSuffix *Suffix = nullptr;
11989
ArrayRef<uint8_t> Data;
12090
const WindowsResource *OwningRes = nullptr;
12191
};

llvm/lib/BinaryFormat/Magic.cpp

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

llvm/lib/Object/WindowsResource.cpp

+16-8
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,23 @@ 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+
3943
uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
4044
uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
4145

4246
WindowsResource::WindowsResource(MemoryBufferRef Source)
4347
: Binary(Binary::ID_WinRes, Source) {
44-
size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
48+
size_t LeadingSize = ResourceMagicSize + NullEntrySize;
4549
BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
4650
support::little);
4751
}
4852

4953
Expected<std::unique_ptr<WindowsResource>>
5054
WindowsResource::createWindowsResource(MemoryBufferRef Source) {
51-
if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
55+
if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
5256
return make_error<GenericBinaryError>(
5357
"File too small to be a resource file",
5458
object_error::invalid_file_type);
@@ -101,24 +105,26 @@ static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
101105
}
102106

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

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

111117
RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
112118

113119
RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
114120

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

117123
RETURN_IF_ERROR(Reader.readObject(Suffix));
118124

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

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

123129
return Error::success();
124130
}
@@ -462,6 +468,8 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
462468
SectionOneHeader->PointerToLinenumbers = 0;
463469
SectionOneHeader->NumberOfRelocations = Data.size();
464470
SectionOneHeader->NumberOfLinenumbers = 0;
471+
SectionOneHeader->Characteristics = COFF::IMAGE_SCN_ALIGN_1BYTES;
472+
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
465473
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
466474
SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
467475
}

llvm/unittests/BinaryFormat/TestFileMagic.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ 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[] =
80-
"\x00\x00\x00\x00\x020\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00";
79+
const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff";
8180
const char macho_dynamically_linked_shared_lib_stub[] =
8281
"\xfe\xed\xfa\xce........\x00\x00\x00\x09............";
8382

0 commit comments

Comments
 (0)