llvm-project

Форк
0
/
DriverUtils.cpp 
1028 строк · 34.4 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.