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