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