1//===- DriverUtils.cpp ----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains utility functions for the driver. Because there
10// are so many small functions, we created this separate file to make
11// Driver.cpp less cluttered.
12//
13//===----------------------------------------------------------------------===//
14
15#include "COFFLinkerContext.h"
16#include "Driver.h"
17#include "Symbols.h"
18#include "lld/Common/ErrorHandler.h"
19#include "lld/Common/Memory.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/StringSwitch.h"
22#include "llvm/BinaryFormat/COFF.h"
23#include "llvm/IR/Mangler.h"
24#include "llvm/Object/COFF.h"
25#include "llvm/Object/WindowsResource.h"
26#include "llvm/Option/Arg.h"
27#include "llvm/Option/ArgList.h"
28#include "llvm/Option/Option.h"
29#include "llvm/Support/CommandLine.h"
30#include "llvm/Support/MathExtras.h"
31#include "llvm/Support/Process.h"
32#include "llvm/Support/Program.h"
33#include "llvm/Support/raw_ostream.h"
34#include "llvm/WindowsManifest/WindowsManifestMerger.h"
35#include <memory>
36#include <optional>
37
38using namespace llvm::COFF;
39using namespace llvm::object;
40using namespace llvm::opt;
41using namespace llvm;
42using llvm::sys::Process;
43
44namespace lld {
45namespace coff {
46namespace {
47
48const uint16_t SUBLANG_ENGLISH_US = 0x0409;
49const uint16_t RT_MANIFEST = 24;
50
51class Executor {
52public:
53 explicit Executor(StringRef s) : prog(saver().save(S: s)) {}
54 void add(StringRef s) { args.push_back(x: saver().save(S: s)); }
55 void add(std::string &s) { args.push_back(x: saver().save(S: s)); }
56 void add(Twine s) { args.push_back(x: saver().save(S: s)); }
57 void add(const char *s) { args.push_back(x: saver().save(S: s)); }
58
59 void run() {
60 ErrorOr<std::string> exeOrErr = sys::findProgramByName(Name: prog);
61 if (auto ec = exeOrErr.getError())
62 fatal(msg: "unable to find " + prog + " in PATH: " + ec.message());
63 StringRef exe = saver().save(S: *exeOrErr);
64 args.insert(position: args.begin(), x: exe);
65
66 if (sys::ExecuteAndWait(Program: args[0], Args: args) != 0)
67 fatal(msg: "ExecuteAndWait failed: " +
68 llvm::join(Begin: args.begin(), End: args.end(), Separator: " "));
69 }
70
71private:
72 StringRef prog;
73 std::vector<StringRef> args;
74};
75
76} // anonymous namespace
77
78// Parses a string in the form of "<integer>[,<integer>]".
79void LinkerDriver::parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
80 auto [s1, s2] = arg.split(Separator: ',');
81 if (s1.getAsInteger(Radix: 0, Result&: *addr))
82 Fatal(ctx) << "invalid number: " << s1;
83 if (size && !s2.empty() && s2.getAsInteger(Radix: 0, Result&: *size))
84 Fatal(ctx) << "invalid number: " << s2;
85}
86
87// Parses a string in the form of "<integer>[.<integer>]".
88// If second number is not present, Minor is set to 0.
89void LinkerDriver::parseVersion(StringRef arg, uint32_t *major,
90 uint32_t *minor) {
91 auto [s1, s2] = arg.split(Separator: '.');
92 if (s1.getAsInteger(Radix: 10, Result&: *major))
93 Fatal(ctx) << "invalid number: " << s1;
94 *minor = 0;
95 if (!s2.empty() && s2.getAsInteger(Radix: 10, Result&: *minor))
96 Fatal(ctx) << "invalid number: " << s2;
97}
98
99void LinkerDriver::parseGuard(StringRef fullArg) {
100 SmallVector<StringRef, 1> splitArgs;
101 fullArg.split(A&: splitArgs, Separator: ",");
102 for (StringRef arg : splitArgs) {
103 if (arg.equals_insensitive(RHS: "no"))
104 ctx.config.guardCF = GuardCFLevel::Off;
105 else if (arg.equals_insensitive(RHS: "nolongjmp"))
106 ctx.config.guardCF &= ~GuardCFLevel::LongJmp;
107 else if (arg.equals_insensitive(RHS: "noehcont"))
108 ctx.config.guardCF &= ~GuardCFLevel::EHCont;
109 else if (arg.equals_insensitive(RHS: "cf") || arg.equals_insensitive(RHS: "longjmp"))
110 ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::LongJmp;
111 else if (arg.equals_insensitive(RHS: "ehcont"))
112 ctx.config.guardCF |= GuardCFLevel::CF | GuardCFLevel::EHCont;
113 else
114 Fatal(ctx) << "invalid argument to /guard: " << arg;
115 }
116}
117
118// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
119void LinkerDriver::parseSubsystem(StringRef arg, WindowsSubsystem *sys,
120 uint32_t *major, uint32_t *minor,
121 bool *gotVersion) {
122 auto [sysStr, ver] = arg.split(Separator: ',');
123 std::string sysStrLower = sysStr.lower();
124 *sys = StringSwitch<WindowsSubsystem>(sysStrLower)
125 .Case(S: "boot_application", Value: IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
126 .Case(S: "console", Value: IMAGE_SUBSYSTEM_WINDOWS_CUI)
127 .Case(S: "default", Value: IMAGE_SUBSYSTEM_UNKNOWN)
128 .Case(S: "efi_application", Value: IMAGE_SUBSYSTEM_EFI_APPLICATION)
129 .Case(S: "efi_boot_service_driver",
130 Value: IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
131 .Case(S: "efi_rom", Value: IMAGE_SUBSYSTEM_EFI_ROM)
132 .Case(S: "efi_runtime_driver", Value: IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
133 .Case(S: "native", Value: IMAGE_SUBSYSTEM_NATIVE)
134 .Case(S: "posix", Value: IMAGE_SUBSYSTEM_POSIX_CUI)
135 .Case(S: "windows", Value: IMAGE_SUBSYSTEM_WINDOWS_GUI)
136 .Case(S: "xbox", Value: IMAGE_SUBSYSTEM_XBOX)
137 .Default(Value: IMAGE_SUBSYSTEM_UNKNOWN);
138 if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default")
139 Fatal(ctx) << "unknown subsystem: " << sysStr;
140 if (!ver.empty())
141 parseVersion(arg: ver, major, minor);
142 if (gotVersion)
143 *gotVersion = !ver.empty();
144}
145
146// Parse a string of the form of "<from>=<to>".
147// Results are directly written to Config.
148void LinkerDriver::parseMerge(StringRef s) {
149 auto [from, to] = s.split(Separator: '=');
150 if (from.empty() || to.empty())
151 Fatal(ctx) << "/merge: invalid argument: " << s;
152 if (from == ".rsrc" || to == ".rsrc")
153 Fatal(ctx) << "/merge: cannot merge '.rsrc' with any section";
154 if (from == ".reloc" || to == ".reloc")
155 Fatal(ctx) << "/merge: cannot merge '.reloc' with any section";
156 auto pair = ctx.config.merge.insert(x: std::make_pair(x&: from, y&: to));
157 bool inserted = pair.second;
158 if (!inserted) {
159 StringRef existing = pair.first->second;
160 if (existing != to)
161 Warn(ctx) << s << ": already merged into " << existing;
162 }
163}
164
165void LinkerDriver::parsePDBPageSize(StringRef s) {
166 int v;
167 if (s.getAsInteger(Radix: 0, Result&: v)) {
168 Err(ctx) << "/pdbpagesize: invalid argument: " << s;
169 return;
170 }
171 if (v != 4096 && v != 8192 && v != 16384 && v != 32768) {
172 Err(ctx) << "/pdbpagesize: invalid argument: " << s;
173 return;
174 }
175
176 ctx.config.pdbPageSize = v;
177}
178
179static uint32_t parseSectionAttributes(COFFLinkerContext &ctx, StringRef s) {
180 uint32_t ret = 0;
181 for (char c : s.lower()) {
182 switch (c) {
183 case 'd':
184 ret |= IMAGE_SCN_MEM_DISCARDABLE;
185 break;
186 case 'e':
187 ret |= IMAGE_SCN_MEM_EXECUTE;
188 break;
189 case 'k':
190 ret |= IMAGE_SCN_MEM_NOT_CACHED;
191 break;
192 case 'p':
193 ret |= IMAGE_SCN_MEM_NOT_PAGED;
194 break;
195 case 'r':
196 ret |= IMAGE_SCN_MEM_READ;
197 break;
198 case 's':
199 ret |= IMAGE_SCN_MEM_SHARED;
200 break;
201 case 'w':
202 ret |= IMAGE_SCN_MEM_WRITE;
203 break;
204 default:
205 Fatal(ctx) << "/section: invalid argument: " << s;
206 }
207 }
208 return ret;
209}
210
211// Parses /section option argument.
212void LinkerDriver::parseSection(StringRef s) {
213 auto [name, attrs] = s.split(Separator: ',');
214 if (name.empty() || attrs.empty())
215 Fatal(ctx) << "/section: invalid argument: " << s;
216 ctx.config.section[name] = parseSectionAttributes(ctx, s: attrs);
217}
218
219// Parses /sectionlayout: option argument.
220void LinkerDriver::parseSectionLayout(StringRef path) {
221 if (path.starts_with(Prefix: "@"))
222 path = path.substr(Start: 1);
223 std::unique_ptr<MemoryBuffer> layoutFile =
224 CHECK(MemoryBuffer::getFile(path), "could not open " + path);
225 StringRef content = layoutFile->getBuffer();
226 int index = 0;
227
228 while (!content.empty()) {
229 size_t pos = content.find_first_of(Chars: "\r\n");
230 StringRef line;
231
232 if (pos == StringRef::npos) {
233 line = content;
234 content = StringRef();
235 } else {
236 line = content.substr(Start: 0, N: pos);
237 content = content.substr(Start: pos).ltrim(Chars: "\r\n");
238 }
239
240 line = line.trim();
241 if (line.empty())
242 continue;
243
244 StringRef sectionName = line.split(Separator: ' ').first;
245
246 if (ctx.config.sectionOrder.count(x: sectionName.str())) {
247 Warn(ctx) << "duplicate section '" << sectionName.str()
248 << "' in section layout file, ignoring";
249 continue;
250 }
251
252 ctx.config.sectionOrder[sectionName.str()] = index++;
253 }
254}
255
256void LinkerDriver::parseDosStub(StringRef path) {
257 std::unique_ptr<MemoryBuffer> stub =
258 CHECK(MemoryBuffer::getFile(path), "could not open " + path);
259 size_t bufferSize = stub->getBufferSize();
260 const char *bufferStart = stub->getBufferStart();
261 // MS link.exe compatibility:
262 // 1. stub must be greater than or equal to 64 bytes
263 // 2. stub must start with a valid dos signature 'MZ'
264 if (bufferSize < 64)
265 Err(ctx) << "/stub: stub must be greater than or equal to 64 bytes: "
266 << path;
267 if (bufferStart[0] != 'M' || bufferStart[1] != 'Z')
268 Err(ctx) << "/stub: invalid DOS signature: " << path;
269 ctx.config.dosStub = std::move(stub);
270}
271
272// Parses /functionpadmin option argument.
273void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
274 StringRef arg = a->getNumValues() ? a->getValue() : "";
275 if (!arg.empty()) {
276 // Optional padding in bytes is given.
277 if (arg.getAsInteger(Radix: 0, Result&: ctx.config.functionPadMin))
278 Err(ctx) << "/functionpadmin: invalid argument: " << arg;
279 return;
280 }
281 // No optional argument given.
282 // Set default padding based on machine, similar to link.exe.
283 // There is no default padding for ARM platforms.
284 if (ctx.config.machine == I386) {
285 ctx.config.functionPadMin = 5;
286 } else if (ctx.config.machine == AMD64) {
287 ctx.config.functionPadMin = 6;
288 } else {
289 Err(ctx) << "/functionpadmin: invalid argument for this machine: " << arg;
290 }
291}
292
293// Parses /dependentloadflag option argument.
294void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {
295 StringRef arg = a->getNumValues() ? a->getValue() : "";
296 if (!arg.empty()) {
297 if (arg.getAsInteger(Radix: 0, Result&: ctx.config.dependentLoadFlags))
298 Err(ctx) << "/dependentloadflag: invalid argument: " << arg;
299 return;
300 }
301 // MSVC linker reports error "no argument specified", although MSDN describes
302 // argument as optional.
303 Err(ctx) << "/dependentloadflag: no argument specified";
304}
305
306// Parses a string in the form of "EMBED[,=<integer>]|NO".
307// Results are directly written to
308// Config.
309void LinkerDriver::parseManifest(StringRef arg) {
310 if (arg.equals_insensitive(RHS: "no")) {
311 ctx.config.manifest = Configuration::No;
312 return;
313 }
314 if (!arg.starts_with_insensitive(Prefix: "embed"))
315 Fatal(ctx) << "invalid option " << arg;
316 ctx.config.manifest = Configuration::Embed;
317 arg = arg.substr(Start: strlen(s: "embed"));
318 if (arg.empty())
319 return;
320 if (!arg.starts_with_insensitive(Prefix: ",id="))
321 Fatal(ctx) << "invalid option " << arg;
322 arg = arg.substr(Start: strlen(s: ",id="));
323 if (arg.getAsInteger(Radix: 0, Result&: ctx.config.manifestID))
324 Fatal(ctx) << "invalid option " << arg;
325}
326
327// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
328// Results are directly written to Config.
329void LinkerDriver::parseManifestUAC(StringRef arg) {
330 if (arg.equals_insensitive(RHS: "no")) {
331 ctx.config.manifestUAC = false;
332 return;
333 }
334 for (;;) {
335 arg = arg.ltrim();
336 if (arg.empty())
337 return;
338 if (arg.consume_front_insensitive(Prefix: "level=")) {
339 std::tie(args&: ctx.config.manifestLevel, args&: arg) = arg.split(Separator: " ");
340 continue;
341 }
342 if (arg.consume_front_insensitive(Prefix: "uiaccess=")) {
343 std::tie(args&: ctx.config.manifestUIAccess, args&: arg) = arg.split(Separator: " ");
344 continue;
345 }
346 Fatal(ctx) << "invalid option " << arg;
347 }
348}
349
350// Parses a string in the form of "cd|net[,(cd|net)]*"
351// Results are directly written to Config.
352void LinkerDriver::parseSwaprun(StringRef arg) {
353 do {
354 auto [swaprun, newArg] = arg.split(Separator: ',');
355 if (swaprun.equals_insensitive(RHS: "cd"))
356 ctx.config.swaprunCD = true;
357 else if (swaprun.equals_insensitive(RHS: "net"))
358 ctx.config.swaprunNet = true;
359 else if (swaprun.empty())
360 Err(ctx) << "/swaprun: missing argument";
361 else
362 Err(ctx) << "/swaprun: invalid argument: " << swaprun;
363 // To catch trailing commas, e.g. `/spawrun:cd,`
364 if (newArg.empty() && arg.ends_with(Suffix: ","))
365 Err(ctx) << "/swaprun: missing argument";
366 arg = newArg;
367 } while (!arg.empty());
368}
369
370void LinkerDriver::parseSameAddress(StringRef arg) {
371 auto mangledName = getArm64ECMangledFunctionName(Name: arg);
372 Symbol *sym = ctx.symtab.addUndefined(name: mangledName ? *mangledName : arg);
373
374 // MSVC appears to generate thunks even for non-hybrid ARM64EC images.
375 // As a side effect, the native symbol is pulled in. Since this is used
376 // in the CRT for thread-local constructors, it results in the image
377 // containing unnecessary native code. As these thunks don't appear to
378 // be useful, we limit this behavior to actual hybrid targets. This may
379 // change if compatibility becomes necessary.
380 if (ctx.config.machine != ARM64X)
381 return;
382 Symbol *nativeSym = ctx.hybridSymtab->addUndefined(name: arg);
383 ctx.config.sameAddresses.emplace_back(args&: sym, args&: nativeSym);
384}
385
386// An RAII temporary file class that automatically removes a temporary file.
387namespace {
388class TemporaryFile {
389public:
390 TemporaryFile(COFFLinkerContext &ctx, StringRef prefix, StringRef extn,
391 StringRef contents = "")
392 : ctx(ctx) {
393 SmallString<128> s;
394 if (auto ec = sys::fs::createTemporaryFile(Prefix: "lld-" + prefix, Suffix: extn, ResultPath&: s))
395 Fatal(ctx) << "cannot create a temporary file: " << ec.message();
396 path = std::string(s);
397
398 if (!contents.empty()) {
399 std::error_code ec;
400 raw_fd_ostream os(path, ec, sys::fs::OF_None);
401 if (ec)
402 Fatal(ctx) << "failed to open " << path << ": " << ec.message();
403 os << contents;
404 }
405 }
406
407 TemporaryFile(TemporaryFile &&obj) noexcept : ctx(obj.ctx) {
408 std::swap(lhs&: path, rhs&: obj.path);
409 }
410
411 ~TemporaryFile() {
412 if (path.empty())
413 return;
414 if (sys::fs::remove(path))
415 Fatal(ctx) << "failed to remove " << path;
416 }
417
418 // Returns a memory buffer of this temporary file.
419 // Note that this function does not leave the file open,
420 // so it is safe to remove the file immediately after this function
421 // is called (you cannot remove an opened file on Windows.)
422 std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
423 // IsVolatile=true forces MemoryBuffer to not use mmap().
424 return CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
425 /*RequiresNullTerminator=*/false,
426 /*IsVolatile=*/true),
427 "could not open " + path);
428 }
429
430 COFFLinkerContext &ctx;
431 std::string path;
432};
433}
434
435std::string LinkerDriver::createDefaultXml() {
436 std::string ret;
437 raw_string_ostream os(ret);
438
439 // Emit the XML. Note that we do *not* verify that the XML attributes are
440 // syntactically correct. This is intentional for link.exe compatibility.
441 os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
442 << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
443 << " manifestVersion=\"1.0\">\n";
444 if (ctx.config.manifestUAC) {
445 os << " <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n"
446 << " <security>\n"
447 << " <requestedPrivileges>\n"
448 << " <requestedExecutionLevel level=" << ctx.config.manifestLevel
449 << " uiAccess=" << ctx.config.manifestUIAccess << "/>\n"
450 << " </requestedPrivileges>\n"
451 << " </security>\n"
452 << " </trustInfo>\n";
453 }
454 for (auto manifestDependency : ctx.config.manifestDependencies) {
455 os << " <dependency>\n"
456 << " <dependentAssembly>\n"
457 << " <assemblyIdentity " << manifestDependency << " />\n"
458 << " </dependentAssembly>\n"
459 << " </dependency>\n";
460 }
461 os << "</assembly>\n";
462 return ret;
463}
464
465std::string
466LinkerDriver::createManifestXmlWithInternalMt(StringRef defaultXml) {
467 std::unique_ptr<MemoryBuffer> defaultXmlCopy =
468 MemoryBuffer::getMemBufferCopy(InputData: defaultXml);
469
470 windows_manifest::WindowsManifestMerger merger;
471 if (auto e = merger.merge(Manifest: *defaultXmlCopy))
472 Fatal(ctx) << "internal manifest tool failed on default xml: "
473 << toString(E: std::move(e));
474
475 for (StringRef filename : ctx.config.manifestInput) {
476 std::unique_ptr<MemoryBuffer> manifest =
477 check(e: MemoryBuffer::getFile(Filename: filename));
478 // Call takeBuffer to include in /reproduce: output if applicable.
479 if (auto e = merger.merge(Manifest: takeBuffer(mb: std::move(manifest))))
480 Fatal(ctx) << "internal manifest tool failed on file " << filename << ": "
481 << toString(E: std::move(e));
482 }
483
484 return std::string(merger.getMergedManifest()->getBuffer());
485}
486
487std::string
488LinkerDriver::createManifestXmlWithExternalMt(StringRef defaultXml) {
489 // Create the default manifest file as a temporary file.
490 TemporaryFile Default(ctx, "defaultxml", "manifest");
491 std::error_code ec;
492 raw_fd_ostream os(Default.path, ec, sys::fs::OF_TextWithCRLF);
493 if (ec)
494 Fatal(ctx) << "failed to open " << Default.path << ": " << ec.message();
495 os << defaultXml;
496 os.close();
497
498 // Merge user-supplied manifests if they are given. Since libxml2 is not
499 // enabled, we must shell out to Microsoft's mt.exe tool.
500 TemporaryFile user(ctx, "user", "manifest");
501
502 Executor e("mt.exe");
503 e.add(s: "/manifest");
504 e.add(s&: Default.path);
505 for (StringRef filename : ctx.config.manifestInput) {
506 e.add(s: "/manifest");
507 e.add(s: filename);
508
509 // Manually add the file to the /reproduce: tar if needed.
510 if (tar)
511 if (auto mbOrErr = MemoryBuffer::getFile(Filename: filename))
512 takeBuffer(mb: std::move(*mbOrErr));
513 }
514 e.add(s: "/nologo");
515 e.add(s: "/out:" + StringRef(user.path));
516 e.run();
517
518 return std::string(
519 CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path)
520 .get()
521 ->getBuffer());
522}
523
524std::string LinkerDriver::createManifestXml() {
525 std::string defaultXml = createDefaultXml();
526 if (ctx.config.manifestInput.empty())
527 return defaultXml;
528
529 if (windows_manifest::isAvailable())
530 return createManifestXmlWithInternalMt(defaultXml);
531
532 return createManifestXmlWithExternalMt(defaultXml);
533}
534
535std::unique_ptr<WritableMemoryBuffer>
536LinkerDriver::createMemoryBufferForManifestRes(size_t manifestSize) {
537 size_t resSize = alignTo(
538 Value: object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
539 sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
540 sizeof(object::WinResHeaderSuffix) + manifestSize,
541 Align: object::WIN_RES_DATA_ALIGNMENT);
542 return WritableMemoryBuffer::getNewMemBuffer(Size: resSize, BufferName: ctx.config.outputFile +
543 ".manifest.res");
544}
545
546static void writeResFileHeader(char *&buf) {
547 memcpy(dest: buf, src: COFF::WinResMagic, n: sizeof(COFF::WinResMagic));
548 buf += sizeof(COFF::WinResMagic);
549 memset(s: buf, c: 0, n: object::WIN_RES_NULL_ENTRY_SIZE);
550 buf += object::WIN_RES_NULL_ENTRY_SIZE;
551}
552
553static void writeResEntryHeader(char *&buf, size_t manifestSize,
554 int manifestID) {
555 // Write the prefix.
556 auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf);
557 prefix->DataSize = manifestSize;
558 prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
559 sizeof(object::WinResIDs) +
560 sizeof(object::WinResHeaderSuffix);
561 buf += sizeof(object::WinResHeaderPrefix);
562
563 // Write the Type/Name IDs.
564 auto *iDs = reinterpret_cast<object::WinResIDs *>(buf);
565 iDs->setType(RT_MANIFEST);
566 iDs->setName(manifestID);
567 buf += sizeof(object::WinResIDs);
568
569 // Write the suffix.
570 auto *suffix = reinterpret_cast<object::WinResHeaderSuffix *>(buf);
571 suffix->DataVersion = 0;
572 suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
573 suffix->Language = SUBLANG_ENGLISH_US;
574 suffix->Version = 0;
575 suffix->Characteristics = 0;
576 buf += sizeof(object::WinResHeaderSuffix);
577}
578
579// Create a resource file containing a manifest XML.
580std::unique_ptr<MemoryBuffer> LinkerDriver::createManifestRes() {
581 std::string manifest = createManifestXml();
582
583 std::unique_ptr<WritableMemoryBuffer> res =
584 createMemoryBufferForManifestRes(manifestSize: manifest.size());
585
586 char *buf = res->getBufferStart();
587 writeResFileHeader(buf);
588 writeResEntryHeader(buf, manifestSize: manifest.size(), manifestID: ctx.config.manifestID);
589
590 // Copy the manifest data into the .res file.
591 std::copy(first: manifest.begin(), last: manifest.end(), result: buf);
592 return std::move(res);
593}
594
595void LinkerDriver::createSideBySideManifest() {
596 std::string path = std::string(ctx.config.manifestFile);
597 if (path == "")
598 path = ctx.config.outputFile + ".manifest";
599 std::error_code ec;
600 raw_fd_ostream out(path, ec, sys::fs::OF_TextWithCRLF);
601 if (ec)
602 Fatal(ctx) << "failed to create manifest: " << ec.message();
603 out << createManifestXml();
604}
605
606// Parse a string in the form of
607// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
608// or "<name>=<dllname>.<name>".
609// Used for parsing /export arguments.
610Export LinkerDriver::parseExport(StringRef arg) {
611 Export e;
612 e.source = ExportSource::Export;
613
614 StringRef rest;
615 std::tie(args&: e.name, args&: rest) = arg.split(Separator: ",");
616 if (e.name.empty())
617 goto err;
618
619 if (e.name.contains(C: '=')) {
620 auto [x, y] = e.name.split(Separator: "=");
621
622 // If "<name>=<dllname>.<name>".
623 if (y.contains(Other: ".")) {
624 e.name = x;
625 e.forwardTo = y;
626 } else {
627 e.extName = x;
628 e.name = y;
629 if (e.name.empty())
630 goto err;
631 }
632 }
633
634 // Optional parameters
635 // "[,@ordinal[,NONAME]][,DATA][,PRIVATE][,EXPORTAS,exportname]"
636 while (!rest.empty()) {
637 StringRef tok;
638 std::tie(args&: tok, args&: rest) = rest.split(Separator: ",");
639 if (tok.equals_insensitive(RHS: "noname")) {
640 if (e.ordinal == 0)
641 goto err;
642 e.noname = true;
643 continue;
644 }
645 if (tok.equals_insensitive(RHS: "data")) {
646 e.data = true;
647 continue;
648 }
649 if (tok.equals_insensitive(RHS: "constant")) {
650 e.constant = true;
651 continue;
652 }
653 if (tok.equals_insensitive(RHS: "private")) {
654 e.isPrivate = true;
655 continue;
656 }
657 if (tok.equals_insensitive(RHS: "exportas")) {
658 if (!rest.empty() && !rest.contains(C: ','))
659 e.exportAs = rest;
660 else
661 Err(ctx) << "invalid EXPORTAS value: " << rest;
662 break;
663 }
664 if (tok.starts_with(Prefix: "@")) {
665 int32_t ord;
666 if (tok.substr(Start: 1).getAsInteger(Radix: 0, Result&: ord))
667 goto err;
668 if (ord <= 0 || 65535 < ord)
669 goto err;
670 e.ordinal = ord;
671 continue;
672 }
673 goto err;
674 }
675 return e;
676
677err:
678 Fatal(ctx) << "invalid /export: " << arg;
679 llvm_unreachable("");
680}
681
682// Parses a string in the form of "key=value" and check
683// if value matches previous values for the same key.
684void LinkerDriver::checkFailIfMismatch(StringRef arg, InputFile *source) {
685 auto [k, v] = arg.split(Separator: '=');
686 if (k.empty() || v.empty())
687 Fatal(ctx) << "/failifmismatch: invalid argument: " << arg;
688 std::pair<StringRef, InputFile *> existing = ctx.config.mustMatch[k];
689 if (!existing.first.empty() && v != existing.first) {
690 std::string sourceStr = source ? toString(file: source) : "cmd-line";
691 std::string existingStr =
692 existing.second ? toString(file: existing.second) : "cmd-line";
693 Fatal(ctx) << "/failifmismatch: mismatch detected for '" << k << "':\n>>> "
694 << existingStr << " has value " << existing.first << "\n>>> "
695 << sourceStr << " has value " << v;
696 }
697 ctx.config.mustMatch[k] = {v, source};
698}
699
700// Convert Windows resource files (.res files) to a .obj file.
701// Does what cvtres.exe does, but in-process and cross-platform.
702MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
703 ArrayRef<ObjFile *> objs) {
704 object::WindowsResourceParser parser(/* MinGW */ ctx.config.mingw);
705
706 std::vector<std::string> duplicates;
707 for (MemoryBufferRef mb : mbs) {
708 std::unique_ptr<object::Binary> bin = check(e: object::createBinary(Source: mb));
709 object::WindowsResource *rf = dyn_cast<object::WindowsResource>(Val: bin.get());
710 if (!rf)
711 Fatal(ctx) << "cannot compile non-resource file as resource";
712
713 if (auto ec = parser.parse(WR: rf, Duplicates&: duplicates))
714 Fatal(ctx) << toString(E: std::move(ec));
715 }
716
717 // Note: This processes all .res files before all objs. Ideally they'd be
718 // handled in the same order they were linked (to keep the right one, if
719 // there are duplicates that are tolerated due to forceMultipleRes).
720 for (ObjFile *f : objs) {
721 object::ResourceSectionRef rsf;
722 if (auto ec = rsf.load(O: f->getCOFFObj()))
723 Fatal(ctx) << toString(file: f) << ": " << toString(E: std::move(ec));
724
725 if (auto ec = parser.parse(RSR&: rsf, Filename: f->getName(), Duplicates&: duplicates))
726 Fatal(ctx) << toString(E: std::move(ec));
727 }
728
729 if (ctx.config.mingw)
730 parser.cleanUpManifests(Duplicates&: duplicates);
731
732 for (const auto &dupeDiag : duplicates)
733 if (ctx.config.forceMultipleRes)
734 Warn(ctx) << dupeDiag;
735 else
736 Err(ctx) << dupeDiag;
737
738 Expected<std::unique_ptr<MemoryBuffer>> e =
739 llvm::object::writeWindowsResourceCOFF(MachineType: ctx.config.machine, Parser: parser,
740 TimeDateStamp: ctx.config.timestamp);
741 if (!e)
742 Fatal(ctx) << "failed to write .res to COFF: " << toString(E: e.takeError());
743
744 MemoryBufferRef mbref = **e;
745 make<std::unique_ptr<MemoryBuffer>>(args: std::move(*e)); // take ownership
746 return mbref;
747}
748
749// Create OptTable
750
751#define OPTTABLE_STR_TABLE_CODE
752#include "Options.inc"
753#undef OPTTABLE_STR_TABLE_CODE
754
755// Create prefix string literals used in Options.td
756#define OPTTABLE_PREFIXES_TABLE_CODE
757#include "Options.inc"
758#undef OPTTABLE_PREFIXES_TABLE_CODE
759
760// Create table mapping all options defined in Options.td
761static constexpr llvm::opt::OptTable::Info infoTable[] = {
762#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
763#include "Options.inc"
764#undef OPTION
765};
766
767COFFOptTable::COFFOptTable()
768 : GenericOptTable(OptionStrTable, OptionPrefixesTable, infoTable, true) {}
769
770// Set color diagnostics according to --color-diagnostics={auto,always,never}
771// or --no-color-diagnostics flags.
772static void handleColorDiagnostics(COFFLinkerContext &ctx,
773 opt::InputArgList &args) {
774 auto *arg = args.getLastArg(Ids: OPT_color_diagnostics, Ids: OPT_color_diagnostics_eq,
775 Ids: OPT_no_color_diagnostics);
776 if (!arg)
777 return;
778 if (arg->getOption().getID() == OPT_color_diagnostics) {
779 ctx.e.errs().enable_colors(enable: true);
780 } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
781 ctx.e.errs().enable_colors(enable: false);
782 } else {
783 StringRef s = arg->getValue();
784 if (s == "always")
785 ctx.e.errs().enable_colors(enable: true);
786 else if (s == "never")
787 ctx.e.errs().enable_colors(enable: false);
788 else if (s != "auto")
789 Err(ctx) << "unknown option: --color-diagnostics=" << s;
790 }
791}
792
793static cl::TokenizerCallback getQuotingStyle(COFFLinkerContext &ctx,
794 opt::InputArgList &args) {
795 if (auto *arg = args.getLastArg(Ids: OPT_rsp_quoting)) {
796 StringRef s = arg->getValue();
797 if (s != "windows" && s != "posix")
798 Err(ctx) << "invalid response file quoting: " << s;
799 if (s == "windows")
800 return cl::TokenizeWindowsCommandLine;
801 return cl::TokenizeGNUCommandLine;
802 }
803 // The COFF linker always defaults to Windows quoting.
804 return cl::TokenizeWindowsCommandLine;
805}
806
807ArgParser::ArgParser(COFFLinkerContext &c) : ctx(c) {}
808
809// Parses a given list of options.
810opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
811 // Make InputArgList from string vectors.
812 unsigned missingIndex;
813 unsigned missingCount;
814
815 // We need to get the quoting style for response files before parsing all
816 // options so we parse here before and ignore all the options but
817 // --rsp-quoting and /lldignoreenv.
818 // (This means --rsp-quoting can't be added through %LINK%.)
819 opt::InputArgList args =
820 ctx.optTable.ParseArgs(Args: argv, MissingArgIndex&: missingIndex, MissingArgCount&: missingCount);
821
822 // Expand response files (arguments in the form of @<filename>) and insert
823 // flags from %LINK% and %_LINK_%, and then parse the argument again.
824 SmallVector<const char *, 256> expandedArgv(argv.data(),
825 argv.data() + argv.size());
826 if (!args.hasArg(Ids: OPT_lldignoreenv))
827 addLINK(argv&: expandedArgv);
828 cl::ExpandResponseFiles(Saver&: saver(), Tokenizer: getQuotingStyle(ctx, args), Argv&: expandedArgv);
829 args = ctx.optTable.ParseArgs(Args: ArrayRef(expandedArgv).drop_front(),
830 MissingArgIndex&: missingIndex, MissingArgCount&: missingCount);
831
832 // Print the real command line if response files are expanded.
833 if (args.hasArg(Ids: OPT_verbose) && argv.size() != expandedArgv.size()) {
834 std::string msg = "Command line:";
835 for (const char *s : expandedArgv)
836 msg += " " + std::string(s);
837 Msg(ctx) << msg;
838 }
839
840 // Save the command line after response file expansion so we can write it to
841 // the PDB if necessary. Mimic MSVC, which skips input files.
842 ctx.config.argv = {argv[0]};
843 for (opt::Arg *arg : args) {
844 if (arg->getOption().getKind() != opt::Option::InputClass) {
845 ctx.config.argv.emplace_back(args: args.getArgString(Index: arg->getIndex()));
846 }
847 }
848
849 // Handle /WX early since it converts missing argument warnings to errors.
850 ctx.e.fatalWarnings = args.hasFlag(Pos: OPT_WX, Neg: OPT_WX_no, Default: false);
851
852 if (missingCount)
853 Fatal(ctx) << args.getArgString(Index: missingIndex) << ": missing argument";
854
855 handleColorDiagnostics(ctx, args);
856
857 for (opt::Arg *arg : args.filtered(Ids: OPT_UNKNOWN)) {
858 std::string nearest;
859 if (ctx.optTable.findNearest(Option: arg->getAsString(Args: args), NearestString&: nearest) > 1)
860 Warn(ctx) << "ignoring unknown argument '" << arg->getAsString(Args: args)
861 << "'";
862 else
863 Warn(ctx) << "ignoring unknown argument '" << arg->getAsString(Args: args)
864 << "', did you mean '" << nearest << "'";
865 }
866
867 if (args.hasArg(Ids: OPT_link))
868 Warn(ctx) << "ignoring /link, did you pass it multiple times?";
869
870 if (args.hasArg(Ids: OPT_lib))
871 Warn(ctx) << "ignoring /lib since it's not the first argument";
872
873 return args;
874}
875
876// Tokenizes and parses a given string as command line in .drective section.
877ParsedDirectives ArgParser::parseDirectives(StringRef s) {
878 ParsedDirectives result;
879 SmallVector<const char *, 16> rest;
880
881 // Handle /EXPORT and /INCLUDE in a fast path. These directives can appear for
882 // potentially every symbol in the object, so they must be handled quickly.
883 SmallVector<StringRef, 16> tokens;
884 cl::TokenizeWindowsCommandLineNoCopy(Source: s, Saver&: saver(), NewArgv&: tokens);
885 for (StringRef tok : tokens) {
886 if (tok.starts_with_insensitive(Prefix: "/export:") ||
887 tok.starts_with_insensitive(Prefix: "-export:"))
888 result.exports.push_back(x: tok.substr(Start: strlen(s: "/export:")));
889 else if (tok.starts_with_insensitive(Prefix: "/include:") ||
890 tok.starts_with_insensitive(Prefix: "-include:"))
891 result.includes.push_back(x: tok.substr(Start: strlen(s: "/include:")));
892 else if (tok.starts_with_insensitive(Prefix: "/exclude-symbols:") ||
893 tok.starts_with_insensitive(Prefix: "-exclude-symbols:"))
894 result.excludes.push_back(x: tok.substr(Start: strlen(s: "/exclude-symbols:")));
895 else {
896 // Copy substrings that are not valid C strings. The tokenizer may have
897 // already copied quoted arguments for us, so those do not need to be
898 // copied again.
899 bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0';
900 rest.push_back(Elt: HasNul ? tok.data() : saver().save(S: tok).data());
901 }
902 }
903
904 // Make InputArgList from unparsed string vectors.
905 unsigned missingIndex;
906 unsigned missingCount;
907
908 result.args = ctx.optTable.ParseArgs(Args: rest, MissingArgIndex&: missingIndex, MissingArgCount&: missingCount);
909
910 if (missingCount)
911 Fatal(ctx) << result.args.getArgString(Index: missingIndex)
912 << ": missing argument";
913 for (auto *arg : result.args.filtered(Ids: OPT_UNKNOWN))
914 Warn(ctx) << "ignoring unknown argument: " << arg->getAsString(Args: result.args);
915 return result;
916}
917
918// link.exe has an interesting feature. If LINK or _LINK_ environment
919// variables exist, their contents are handled as command line strings.
920// So you can pass extra arguments using them.
921void ArgParser::addLINK(SmallVector<const char *, 256> &argv) {
922 // Concatenate LINK env and command line arguments, and then parse them.
923 if (std::optional<std::string> s = Process::GetEnv(name: "LINK")) {
924 std::vector<const char *> v = tokenize(s: *s);
925 argv.insert(I: std::next(x: argv.begin()), From: v.begin(), To: v.end());
926 }
927 if (std::optional<std::string> s = Process::GetEnv(name: "_LINK_")) {
928 std::vector<const char *> v = tokenize(s: *s);
929 argv.insert(I: std::next(x: argv.begin()), From: v.begin(), To: v.end());
930 }
931}
932
933std::vector<const char *> ArgParser::tokenize(StringRef s) {
934 SmallVector<const char *, 16> tokens;
935 cl::TokenizeWindowsCommandLine(Source: s, Saver&: saver(), NewArgv&: tokens);
936 return std::vector<const char *>(tokens.begin(), tokens.end());
937}
938
939void LinkerDriver::printHelp(const char *argv0) {
940 ctx.optTable.printHelp(OS&: ctx.e.outs(),
941 Usage: (std::string(argv0) + " [options] file...").c_str(),
942 Title: "LLVM Linker", ShowHidden: false);
943}
944
945} // namespace coff
946} // namespace lld
947