Skip to content

Commit 400a1de

Browse files
committed
[lld/COFF] Improve handling of the /manifestdependency: flag
If multiple /manifestdependency: flags are passed, they are naively deduped, but after that each of them should have an effect, instead of just the last one. Also, /manifestdependency: flags are allowed in .drectve sections (from `#pragma comment(linker, ...`). To make the interaction between /manifestdependency: flags enabling manifest by default but /manifest:no overriding this work, add an explict ManifestKind::Default state to represent no explicit /manifest flag being passed. To make /manifestdependency: flags from input file .drectve sections work with /manifest:embed, delay embedded manifest emission until after input files have been read. Differential Revision: https://reviews.llvm.org/D108628
1 parent ea1c01d commit 400a1de

File tree

6 files changed

+138
-32
lines changed

6 files changed

+138
-32
lines changed

lld/COFF/Config.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLD_COFF_CONFIG_H
1111

1212
#include "llvm/ADT/MapVector.h"
13+
#include "llvm/ADT/SetVector.h"
1314
#include "llvm/ADT/StringMap.h"
1415
#include "llvm/ADT/StringRef.h"
1516
#include "llvm/Object/COFF.h"
@@ -91,7 +92,7 @@ enum class ICFLevel {
9192

9293
// Global configuration.
9394
struct Configuration {
94-
enum ManifestKind { SideBySide, Embed, No };
95+
enum ManifestKind { Default, SideBySide, Embed, No };
9596
bool is64() { return machine == AMD64 || machine == ARM64; }
9697

9798
llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN;
@@ -178,9 +179,9 @@ struct Configuration {
178179
std::map<StringRef, uint32_t> section;
179180

180181
// Options for manifest files.
181-
ManifestKind manifest = No;
182+
ManifestKind manifest = Default;
182183
int manifestID = 1;
183-
StringRef manifestDependency;
184+
llvm::SetVector<StringRef> manifestDependencies;
184185
bool manifestUAC = true;
185186
std::vector<std::string> manifestInput;
186187
StringRef manifestLevel = "'asInvoker'";

lld/COFF/Driver.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
383383
for (StringRef inc : directives.includes)
384384
addUndefined(inc);
385385

386+
// https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160
386387
for (auto *arg : directives.args) {
387388
switch (arg->getOption().getID()) {
388389
case OPT_aligncomm:
@@ -404,6 +405,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
404405
case OPT_incl:
405406
addUndefined(arg->getValue());
406407
break;
408+
case OPT_manifestdependency:
409+
config->manifestDependencies.insert(arg->getValue());
410+
break;
407411
case OPT_merge:
408412
parseMerge(arg->getValue());
409413
break;
@@ -651,15 +655,10 @@ static std::string createResponseFile(const opt::InputArgList &args,
651655
case OPT_INPUT:
652656
case OPT_defaultlib:
653657
case OPT_libpath:
654-
case OPT_manifest:
655-
case OPT_manifest_colon:
656-
case OPT_manifestdependency:
657-
case OPT_manifestfile:
658-
case OPT_manifestinput:
659-
case OPT_manifestuac:
660658
break;
661659
case OPT_call_graph_ordering_file:
662660
case OPT_deffile:
661+
case OPT_manifestinput:
663662
case OPT_natvis:
664663
os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << '\n';
665664
break;
@@ -677,6 +676,7 @@ static std::string createResponseFile(const opt::InputArgList &args,
677676
break;
678677
}
679678
case OPT_implib:
679+
case OPT_manifestfile:
680680
case OPT_pdb:
681681
case OPT_pdbstripped:
682682
case OPT_out:
@@ -1705,12 +1705,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
17051705
for (auto *arg : args.filtered(OPT_aligncomm))
17061706
parseAligncomm(arg->getValue());
17071707

1708-
// Handle /manifestdependency. This enables /manifest unless /manifest:no is
1709-
// also passed.
1710-
if (auto *arg = args.getLastArg(OPT_manifestdependency)) {
1711-
config->manifestDependency = arg->getValue();
1712-
config->manifest = Configuration::SideBySide;
1713-
}
1708+
// Handle /manifestdependency.
1709+
for (auto *arg : args.filtered(OPT_manifestdependency))
1710+
config->manifestDependencies.insert(arg->getValue());
17141711

17151712
// Handle /manifest and /manifest:
17161713
if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
@@ -1873,10 +1870,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
18731870
if (Optional<StringRef> path = findLib(arg->getValue()))
18741871
enqueuePath(*path, false, false);
18751872

1876-
// Windows specific -- Create a resource file containing a manifest file.
1877-
if (config->manifest == Configuration::Embed)
1878-
addBuffer(createManifestRes(), false, false);
1879-
18801873
// Read all input files given via the command line.
18811874
run();
18821875

@@ -2230,8 +2223,14 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
22302223
c->setAlignment(std::max(c->getAlignment(), alignment));
22312224
}
22322225

2233-
// Windows specific -- Create a side-by-side manifest file.
2234-
if (config->manifest == Configuration::SideBySide)
2226+
// Windows specific -- Create an embedded or side-by-side manifest.
2227+
// /manifestdependency: enables /manifest unless an explicit /manifest:no is
2228+
// also passed.
2229+
if (config->manifest == Configuration::Embed)
2230+
addBuffer(createManifestRes(), false, false);
2231+
else if (config->manifest == Configuration::SideBySide ||
2232+
(config->manifest == Configuration::Default &&
2233+
!config->manifestDependencies.empty()))
22352234
createSideBySideManifest();
22362235

22372236
// Handle /order. We want to do this at this moment because we

lld/COFF/DriverUtils.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,10 @@ static std::string createDefaultXml() {
385385
<< " </security>\n"
386386
<< " </trustInfo>\n";
387387
}
388-
if (!config->manifestDependency.empty()) {
388+
for (auto manifestDependency : config->manifestDependencies) {
389389
os << " <dependency>\n"
390390
<< " <dependentAssembly>\n"
391-
<< " <assemblyIdentity " << config->manifestDependency << " />\n"
391+
<< " <assemblyIdentity " << manifestDependency << " />\n"
392392
<< " </dependentAssembly>\n"
393393
<< " </dependency>\n";
394394
}
@@ -408,7 +408,8 @@ static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
408408
for (StringRef filename : config->manifestInput) {
409409
std::unique_ptr<MemoryBuffer> manifest =
410410
check(MemoryBuffer::getFile(filename));
411-
if (auto e = merger.merge(*manifest.get()))
411+
// Call takeBuffer to include in /reproduce: output if applicable.
412+
if (auto e = merger.merge(driver->takeBuffer(std::move(manifest))))
412413
fatal("internal manifest tool failed on file " + filename + ": " +
413414
toString(std::move(e)));
414415
}
@@ -436,6 +437,11 @@ static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
436437
for (StringRef filename : config->manifestInput) {
437438
e.add("/manifest");
438439
e.add(filename);
440+
441+
// Manually add the file to the /reproduce: tar if needed.
442+
if (driver->tar)
443+
if (auto mbOrErr = MemoryBuffer::getFile(filename))
444+
driver->takeBuffer(std::move(*mbOrErr));
439445
}
440446
e.add("/nologo");
441447
e.add("/out:" + StringRef(user.path));
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--- !COFF
2+
header:
3+
Machine: IMAGE_FILE_MACHINE_AMD64
4+
Characteristics: []
5+
sections:
6+
- Name: .drectve
7+
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
8+
Alignment: 1
9+
# "/manifestdependency:foo='bar'" "/manifestdependency:baz='quux'"
10+
# (pipe into `xxd -p -r` to recover raw contents; pipe into `xxd -p` to put
11+
# something new here.)
12+
SectionData: 222f6d616e6966657374646570656e64656e63793a666f6f3d27626172272220222f6d616e6966657374646570656e64656e63793a62617a3d27717575782722
13+
symbols:
14+
...

lld/test/COFF/linkrepro-manifest.test

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
REQUIRES: x86, gnutar, manifest_tool
22

3-
manifest-related files are compiled to a .res file and the .res file is
4-
added to the repro archive, instead of adding the inputs.
5-
63
RUN: rm -rf %t && mkdir %t && cd %t
74
RUN: lld-link -entry:__ImageBase -nodefaultlib -linkrepro:%t \
85
RUN: -manifest:embed %p/Inputs/std32.lib -subsystem:console \
96
RUN: -manifestinput:%p/Inputs/manifestinput.test
107

118
RUN: tar tf repro.tar | FileCheck --check-prefix=LIST %s
12-
RUN: tar xOf repro.tar repro/response.txt | FileCheck %s
9+
RUN: tar xOf repro.tar repro/response.txt \
10+
RUN: | FileCheck --implicit-check-not=.manifest.res %s
1311

14-
LIST: manifest.res
12+
LIST: {{.*}}manifestinput.test
1513

16-
CHECK-NOT: -manifest:
17-
CHECK: .manifest.res
18-
CHECK-NOT: -manifest:
14+
CHECK-DAG: -manifest:embed
15+
CHECK-DAG: -manifestinput:{{.*}}manifestinput.test

lld/test/COFF/manifest.test

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,92 @@ NOUACNODEP: <?xml version="1.0" standalone="yes"?>
7878
NOUACNODEP: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
7979
NOUACNODEP: manifestVersion="1.0">
8080
NOUACNODEP: </assembly>
81+
82+
# Several /manifestdependency: flags are naively dedup'd.
83+
# RUN: lld-link /out:%t.exe /entry:main \
84+
# RUN: /manifestdependency:"foo='bar'" \
85+
# RUN: /manifestdependency:"foo='bar'" \
86+
# RUN: /manifestdependency:"baz='quux'" \
87+
# RUN: %t.obj
88+
# RUN: FileCheck -check-prefix=SEVERALDEPS %s < %t.exe.manifest
89+
90+
SEVERALDEPS: <?xml version="1.0" standalone="yes"?>
91+
SEVERALDEPS: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
92+
SEVERALDEPS: manifestVersion="1.0">
93+
SEVERALDEPS: <trustInfo>
94+
SEVERALDEPS: <security>
95+
SEVERALDEPS: <requestedPrivileges>
96+
SEVERALDEPS: <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
97+
SEVERALDEPS: </requestedPrivileges>
98+
SEVERALDEPS: </security>
99+
SEVERALDEPS: </trustInfo>
100+
SEVERALDEPS: <dependency>
101+
SEVERALDEPS: <dependentAssembly>
102+
SEVERALDEPS: <assemblyIdentity foo='bar' />
103+
SEVERALDEPS: </dependentAssembly>
104+
SEVERALDEPS: <dependency>
105+
SEVERALDEPS: <dependentAssembly>
106+
SEVERALDEPS: <assemblyIdentity baz='quux' />
107+
SEVERALDEPS: </dependentAssembly>
108+
SEVERALDEPS: </dependency>
109+
SEVERALDEPS: </assembly>
110+
111+
# /manifestdependency: flags can be in .drectve sections.
112+
# RUN: yaml2obj %p/Inputs/manifestdependency-drectve.yaml -o %t.dir.obj
113+
# RUN: rm %t.exe.manifest
114+
# RUN: lld-link /out:%t.exe /entry:main \
115+
# RUN: %t.obj %t.dir.obj
116+
# RUN: FileCheck -check-prefix=SEVERALDEPS %s < %t.exe.manifest
117+
118+
# /manifestdependency: flags in .drectve sections are ignored with an
119+
# explicit /manifest:no.
120+
# RUN: rm %t.exe.manifest
121+
# RUN: lld-link /out:%t.exe /entry:main /manifest:no \
122+
# RUN: %t.obj %t.dir.obj
123+
# RUN: test ! -e %t.exe.manifest
124+
125+
# Test that /manifestdependency: flags in .drectve sections work
126+
# with /manifest:embed too.
127+
# RUN: lld-link /out:%t.exe /entry:main /manifest:embed \
128+
# RUN: %t.obj %t.dir.obj
129+
# RUN: test ! -e %t.exe.manifest
130+
# RUN: llvm-readobj --coff-resources %t.exe \
131+
# RUN: | FileCheck --check-prefix EMBED %s
132+
133+
EMBED: Data (
134+
EMBED: 0000: 3C3F786D 6C207665 7273696F 6E3D2231 |<?xml version="1|
135+
EMBED: 0010: 2E302220 7374616E 64616C6F 6E653D22 |.0" standalone="|
136+
EMBED: 0020: 79657322 3F3E0A3C 61737365 6D626C79 |yes"?>.<assembly|
137+
EMBED: 0030: 20786D6C 6E733D22 75726E3A 73636865 | xmlns="urn:sche|
138+
EMBED: 0040: 6D61732D 6D696372 6F736F66 742D636F |mas-microsoft-co|
139+
EMBED: 0050: 6D3A6173 6D2E7631 220A2020 20202020 |m:asm.v1". |
140+
EMBED: 0060: 20202020 6D616E69 66657374 56657273 | manifestVers|
141+
EMBED: 0070: 696F6E3D 22312E30 223E0A20 203C7472 |ion="1.0">. <tr|
142+
EMBED: 0080: 75737449 6E666F3E 0A202020 203C7365 |ustInfo>. <se|
143+
EMBED: 0090: 63757269 74793E0A 20202020 20203C72 |curity>. <r|
144+
EMBED: 00A0: 65717565 73746564 50726976 696C6567 |equestedPrivileg|
145+
EMBED: 00B0: 65733E0A 20202020 20202020 203C7265 |es>. <re|
146+
EMBED: 00C0: 71756573 74656445 78656375 74696F6E |questedExecution|
147+
EMBED: 00D0: 4C657665 6C206C65 76656C3D 27617349 |Level level='asI|
148+
EMBED: 00E0: 6E766F6B 65722720 75694163 63657373 |nvoker' uiAccess|
149+
EMBED: 00F0: 3D276661 6C736527 2F3E0A20 20202020 |='false'/>. |
150+
EMBED: 0100: 203C2F72 65717565 73746564 50726976 | </requestedPriv|
151+
EMBED: 0110: 696C6567 65733E0A 20202020 3C2F7365 |ileges>. </se|
152+
EMBED: 0120: 63757269 74793E0A 20203C2F 74727573 |curity>. </trus|
153+
EMBED: 0130: 74496E66 6F3E0A20 203C6465 70656E64 |tInfo>. <depend|
154+
EMBED: 0140: 656E6379 3E0A2020 20203C64 6570656E |ency>. <depen|
155+
EMBED: 0150: 64656E74 41737365 6D626C79 3E0A2020 |dentAssembly>. |
156+
EMBED: 0160: 20202020 3C617373 656D626C 79496465 | <assemblyIde|
157+
EMBED: 0170: 6E746974 7920666F 6F3D2762 61722720 |ntity foo='bar' |
158+
EMBED: 0180: 2F3E0A20 2020203C 2F646570 656E6465 |/>. </depende|
159+
EMBED: 0190: 6E744173 73656D62 6C793E0A 20203C2F |ntAssembly>. </|
160+
EMBED: 01A0: 64657065 6E64656E 63793E0A 20203C64 |dependency>. <d|
161+
EMBED: 01B0: 6570656E 64656E63 793E0A20 2020203C |ependency>. <|
162+
EMBED: 01C0: 64657065 6E64656E 74417373 656D626C |dependentAssembl|
163+
EMBED: 01D0: 793E0A20 20202020 203C6173 73656D62 |y>. <assemb|
164+
EMBED: 01E0: 6C794964 656E7469 74792062 617A3D27 |lyIdentity baz='|
165+
EMBED: 01F0: 71757578 27202F3E 0A202020 203C2F64 |quux' />. </d|
166+
EMBED: 0200: 6570656E 64656E74 41737365 6D626C79 |ependentAssembly|
167+
EMBED: 0210: 3E0A2020 3C2F6465 70656E64 656E6379 |>. </dependency|
168+
EMBED: 0220: 3E0A3C2F 61737365 6D626C79 3E0A |>.</assembly>.|
169+
EMBED: )

0 commit comments

Comments
 (0)