[lld] 400a1de - [lld/COFF] Improve handling of the /manifestdependency: flag
Nico Weber via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 25 11:36:39 PDT 2021
Author: Nico Weber
Date: 2021-08-25T14:36:32-04:00
New Revision: 400a1de3ac4583794797852aab49aaa821c95b7d
URL: https://github.com/llvm/llvm-project/commit/400a1de3ac4583794797852aab49aaa821c95b7d
DIFF: https://github.com/llvm/llvm-project/commit/400a1de3ac4583794797852aab49aaa821c95b7d.diff
LOG: [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
Added:
lld/test/COFF/Inputs/manifestdependency-drectve.yaml
Modified:
lld/COFF/Config.h
lld/COFF/Driver.cpp
lld/COFF/DriverUtils.cpp
lld/test/COFF/linkrepro-manifest.test
lld/test/COFF/manifest.test
Removed:
################################################################################
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 002d128838ce2..feaad55da871b 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -10,6 +10,7 @@
#define LLD_COFF_CONFIG_H
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
@@ -91,7 +92,7 @@ enum class ICFLevel {
// Global configuration.
struct Configuration {
- enum ManifestKind { SideBySide, Embed, No };
+ enum ManifestKind { Default, SideBySide, Embed, No };
bool is64() { return machine == AMD64 || machine == ARM64; }
llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN;
@@ -178,9 +179,9 @@ struct Configuration {
std::map<StringRef, uint32_t> section;
// Options for manifest files.
- ManifestKind manifest = No;
+ ManifestKind manifest = Default;
int manifestID = 1;
- StringRef manifestDependency;
+ llvm::SetVector<StringRef> manifestDependencies;
bool manifestUAC = true;
std::vector<std::string> manifestInput;
StringRef manifestLevel = "'asInvoker'";
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 5f6bc91c90487..fd9ae7f47bf87 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -383,6 +383,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
for (StringRef inc : directives.includes)
addUndefined(inc);
+ // https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160
for (auto *arg : directives.args) {
switch (arg->getOption().getID()) {
case OPT_aligncomm:
@@ -404,6 +405,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
case OPT_incl:
addUndefined(arg->getValue());
break;
+ case OPT_manifestdependency:
+ config->manifestDependencies.insert(arg->getValue());
+ break;
case OPT_merge:
parseMerge(arg->getValue());
break;
@@ -651,15 +655,10 @@ static std::string createResponseFile(const opt::InputArgList &args,
case OPT_INPUT:
case OPT_defaultlib:
case OPT_libpath:
- case OPT_manifest:
- case OPT_manifest_colon:
- case OPT_manifestdependency:
- case OPT_manifestfile:
- case OPT_manifestinput:
- case OPT_manifestuac:
break;
case OPT_call_graph_ordering_file:
case OPT_deffile:
+ case OPT_manifestinput:
case OPT_natvis:
os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << '\n';
break;
@@ -677,6 +676,7 @@ static std::string createResponseFile(const opt::InputArgList &args,
break;
}
case OPT_implib:
+ case OPT_manifestfile:
case OPT_pdb:
case OPT_pdbstripped:
case OPT_out:
@@ -1705,12 +1705,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
for (auto *arg : args.filtered(OPT_aligncomm))
parseAligncomm(arg->getValue());
- // Handle /manifestdependency. This enables /manifest unless /manifest:no is
- // also passed.
- if (auto *arg = args.getLastArg(OPT_manifestdependency)) {
- config->manifestDependency = arg->getValue();
- config->manifest = Configuration::SideBySide;
- }
+ // Handle /manifestdependency.
+ for (auto *arg : args.filtered(OPT_manifestdependency))
+ config->manifestDependencies.insert(arg->getValue());
// Handle /manifest and /manifest:
if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
@@ -1873,10 +1870,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (Optional<StringRef> path = findLib(arg->getValue()))
enqueuePath(*path, false, false);
- // Windows specific -- Create a resource file containing a manifest file.
- if (config->manifest == Configuration::Embed)
- addBuffer(createManifestRes(), false, false);
-
// Read all input files given via the command line.
run();
@@ -2230,8 +2223,14 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
c->setAlignment(std::max(c->getAlignment(), alignment));
}
- // Windows specific -- Create a side-by-side manifest file.
- if (config->manifest == Configuration::SideBySide)
+ // Windows specific -- Create an embedded or side-by-side manifest.
+ // /manifestdependency: enables /manifest unless an explicit /manifest:no is
+ // also passed.
+ if (config->manifest == Configuration::Embed)
+ addBuffer(createManifestRes(), false, false);
+ else if (config->manifest == Configuration::SideBySide ||
+ (config->manifest == Configuration::Default &&
+ !config->manifestDependencies.empty()))
createSideBySideManifest();
// Handle /order. We want to do this at this moment because we
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index b5abe8b1196d9..9775e37f004fc 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -385,10 +385,10 @@ static std::string createDefaultXml() {
<< " </security>\n"
<< " </trustInfo>\n";
}
- if (!config->manifestDependency.empty()) {
+ for (auto manifestDependency : config->manifestDependencies) {
os << " <dependency>\n"
<< " <dependentAssembly>\n"
- << " <assemblyIdentity " << config->manifestDependency << " />\n"
+ << " <assemblyIdentity " << manifestDependency << " />\n"
<< " </dependentAssembly>\n"
<< " </dependency>\n";
}
@@ -408,7 +408,8 @@ static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
for (StringRef filename : config->manifestInput) {
std::unique_ptr<MemoryBuffer> manifest =
check(MemoryBuffer::getFile(filename));
- if (auto e = merger.merge(*manifest.get()))
+ // Call takeBuffer to include in /reproduce: output if applicable.
+ if (auto e = merger.merge(driver->takeBuffer(std::move(manifest))))
fatal("internal manifest tool failed on file " + filename + ": " +
toString(std::move(e)));
}
@@ -436,6 +437,11 @@ static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
for (StringRef filename : config->manifestInput) {
e.add("/manifest");
e.add(filename);
+
+ // Manually add the file to the /reproduce: tar if needed.
+ if (driver->tar)
+ if (auto mbOrErr = MemoryBuffer::getFile(filename))
+ driver->takeBuffer(std::move(*mbOrErr));
}
e.add("/nologo");
e.add("/out:" + StringRef(user.path));
diff --git a/lld/test/COFF/Inputs/manifestdependency-drectve.yaml b/lld/test/COFF/Inputs/manifestdependency-drectve.yaml
new file mode 100644
index 0000000000000..7c6b447437759
--- /dev/null
+++ b/lld/test/COFF/Inputs/manifestdependency-drectve.yaml
@@ -0,0 +1,14 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ # "/manifestdependency:foo='bar'" "/manifestdependency:baz='quux'"
+ # (pipe into `xxd -p -r` to recover raw contents; pipe into `xxd -p` to put
+ # something new here.)
+ SectionData: 222f6d616e6966657374646570656e64656e63793a666f6f3d27626172272220222f6d616e6966657374646570656e64656e63793a62617a3d27717575782722
+symbols:
+...
diff --git a/lld/test/COFF/linkrepro-manifest.test b/lld/test/COFF/linkrepro-manifest.test
index 2640588bc5ca9..ab198afcbf64d 100644
--- a/lld/test/COFF/linkrepro-manifest.test
+++ b/lld/test/COFF/linkrepro-manifest.test
@@ -1,18 +1,15 @@
REQUIRES: x86, gnutar, manifest_tool
-manifest-related files are compiled to a .res file and the .res file is
-added to the repro archive, instead of adding the inputs.
-
RUN: rm -rf %t && mkdir %t && cd %t
RUN: lld-link -entry:__ImageBase -nodefaultlib -linkrepro:%t \
RUN: -manifest:embed %p/Inputs/std32.lib -subsystem:console \
RUN: -manifestinput:%p/Inputs/manifestinput.test
RUN: tar tf repro.tar | FileCheck --check-prefix=LIST %s
-RUN: tar xOf repro.tar repro/response.txt | FileCheck %s
+RUN: tar xOf repro.tar repro/response.txt \
+RUN: | FileCheck --implicit-check-not=.manifest.res %s
-LIST: manifest.res
+LIST: {{.*}}manifestinput.test
-CHECK-NOT: -manifest:
-CHECK: .manifest.res
-CHECK-NOT: -manifest:
+CHECK-DAG: -manifest:embed
+CHECK-DAG: -manifestinput:{{.*}}manifestinput.test
diff --git a/lld/test/COFF/manifest.test b/lld/test/COFF/manifest.test
index f3a388f8bbe16..4910600bd3a17 100644
--- a/lld/test/COFF/manifest.test
+++ b/lld/test/COFF/manifest.test
@@ -78,3 +78,92 @@ NOUACNODEP: <?xml version="1.0" standalone="yes"?>
NOUACNODEP: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
NOUACNODEP: manifestVersion="1.0">
NOUACNODEP: </assembly>
+
+# Several /manifestdependency: flags are naively dedup'd.
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN: /manifestdependency:"foo='bar'" \
+# RUN: /manifestdependency:"foo='bar'" \
+# RUN: /manifestdependency:"baz='quux'" \
+# RUN: %t.obj
+# RUN: FileCheck -check-prefix=SEVERALDEPS %s < %t.exe.manifest
+
+SEVERALDEPS: <?xml version="1.0" standalone="yes"?>
+SEVERALDEPS: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+SEVERALDEPS: manifestVersion="1.0">
+SEVERALDEPS: <trustInfo>
+SEVERALDEPS: <security>
+SEVERALDEPS: <requestedPrivileges>
+SEVERALDEPS: <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+SEVERALDEPS: </requestedPrivileges>
+SEVERALDEPS: </security>
+SEVERALDEPS: </trustInfo>
+SEVERALDEPS: <dependency>
+SEVERALDEPS: <dependentAssembly>
+SEVERALDEPS: <assemblyIdentity foo='bar' />
+SEVERALDEPS: </dependentAssembly>
+SEVERALDEPS: <dependency>
+SEVERALDEPS: <dependentAssembly>
+SEVERALDEPS: <assemblyIdentity baz='quux' />
+SEVERALDEPS: </dependentAssembly>
+SEVERALDEPS: </dependency>
+SEVERALDEPS: </assembly>
+
+# /manifestdependency: flags can be in .drectve sections.
+# RUN: yaml2obj %p/Inputs/manifestdependency-drectve.yaml -o %t.dir.obj
+# RUN: rm %t.exe.manifest
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN: %t.obj %t.dir.obj
+# RUN: FileCheck -check-prefix=SEVERALDEPS %s < %t.exe.manifest
+
+# /manifestdependency: flags in .drectve sections are ignored with an
+# explicit /manifest:no.
+# RUN: rm %t.exe.manifest
+# RUN: lld-link /out:%t.exe /entry:main /manifest:no \
+# RUN: %t.obj %t.dir.obj
+# RUN: test ! -e %t.exe.manifest
+
+# Test that /manifestdependency: flags in .drectve sections work
+# with /manifest:embed too.
+# RUN: lld-link /out:%t.exe /entry:main /manifest:embed \
+# RUN: %t.obj %t.dir.obj
+# RUN: test ! -e %t.exe.manifest
+# RUN: llvm-readobj --coff-resources %t.exe \
+# RUN: | FileCheck --check-prefix EMBED %s
+
+EMBED: Data (
+EMBED: 0000: 3C3F786D 6C207665 7273696F 6E3D2231 |<?xml version="1|
+EMBED: 0010: 2E302220 7374616E 64616C6F 6E653D22 |.0" standalone="|
+EMBED: 0020: 79657322 3F3E0A3C 61737365 6D626C79 |yes"?>.<assembly|
+EMBED: 0030: 20786D6C 6E733D22 75726E3A 73636865 | xmlns="urn:sche|
+EMBED: 0040: 6D61732D 6D696372 6F736F66 742D636F |mas-microsoft-co|
+EMBED: 0050: 6D3A6173 6D2E7631 220A2020 20202020 |m:asm.v1". |
+EMBED: 0060: 20202020 6D616E69 66657374 56657273 | manifestVers|
+EMBED: 0070: 696F6E3D 22312E30 223E0A20 203C7472 |ion="1.0">. <tr|
+EMBED: 0080: 75737449 6E666F3E 0A202020 203C7365 |ustInfo>. <se|
+EMBED: 0090: 63757269 74793E0A 20202020 20203C72 |curity>. <r|
+EMBED: 00A0: 65717565 73746564 50726976 696C6567 |equestedPrivileg|
+EMBED: 00B0: 65733E0A 20202020 20202020 203C7265 |es>. <re|
+EMBED: 00C0: 71756573 74656445 78656375 74696F6E |questedExecution|
+EMBED: 00D0: 4C657665 6C206C65 76656C3D 27617349 |Level level='asI|
+EMBED: 00E0: 6E766F6B 65722720 75694163 63657373 |nvoker' uiAccess|
+EMBED: 00F0: 3D276661 6C736527 2F3E0A20 20202020 |='false'/>. |
+EMBED: 0100: 203C2F72 65717565 73746564 50726976 | </requestedPriv|
+EMBED: 0110: 696C6567 65733E0A 20202020 3C2F7365 |ileges>. </se|
+EMBED: 0120: 63757269 74793E0A 20203C2F 74727573 |curity>. </trus|
+EMBED: 0130: 74496E66 6F3E0A20 203C6465 70656E64 |tInfo>. <depend|
+EMBED: 0140: 656E6379 3E0A2020 20203C64 6570656E |ency>. <depen|
+EMBED: 0150: 64656E74 41737365 6D626C79 3E0A2020 |dentAssembly>. |
+EMBED: 0160: 20202020 3C617373 656D626C 79496465 | <assemblyIde|
+EMBED: 0170: 6E746974 7920666F 6F3D2762 61722720 |ntity foo='bar' |
+EMBED: 0180: 2F3E0A20 2020203C 2F646570 656E6465 |/>. </depende|
+EMBED: 0190: 6E744173 73656D62 6C793E0A 20203C2F |ntAssembly>. </|
+EMBED: 01A0: 64657065 6E64656E 63793E0A 20203C64 |dependency>. <d|
+EMBED: 01B0: 6570656E 64656E63 793E0A20 2020203C |ependency>. <|
+EMBED: 01C0: 64657065 6E64656E 74417373 656D626C |dependentAssembl|
+EMBED: 01D0: 793E0A20 20202020 203C6173 73656D62 |y>. <assemb|
+EMBED: 01E0: 6C794964 656E7469 74792062 617A3D27 |lyIdentity baz='|
+EMBED: 01F0: 71757578 27202F3E 0A202020 203C2F64 |quux' />. </d|
+EMBED: 0200: 6570656E 64656E74 41737365 6D626C79 |ependentAssembly|
+EMBED: 0210: 3E0A2020 3C2F6465 70656E64 656E6379 |>. </dependency|
+EMBED: 0220: 3E0A3C2F 61737365 6D626C79 3E0A |>.</assembly>.|
+EMBED: )
More information about the llvm-commits
mailing list