2015-08-14 22:12:54 +08:00
|
|
|
//===- Driver.h -------------------------------------------------*- C++ -*-===//
|
2015-05-29 03:09:30 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-05-29 03:09:30 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLD_COFF_DRIVER_H
|
|
|
|
#define LLD_COFF_DRIVER_H
|
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
#include "Config.h"
|
2015-06-24 07:56:39 +08:00
|
|
|
#include "SymbolTable.h"
|
2017-10-03 05:00:41 +08:00
|
|
|
#include "lld/Common/LLVM.h"
|
|
|
|
#include "lld/Common/Reproduce.h"
|
2015-06-01 03:17:14 +08:00
|
|
|
#include "llvm/ADT/Optional.h"
|
2015-05-29 03:09:30 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2017-12-28 15:41:19 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2016-12-15 12:02:23 +08:00
|
|
|
#include "llvm/Object/Archive.h"
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
#include "llvm/Option/Arg.h"
|
|
|
|
#include "llvm/Option/ArgList.h"
|
2018-06-13 05:47:31 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2017-01-06 10:33:53 +08:00
|
|
|
#include "llvm/Support/TarWriter.h"
|
2015-05-29 03:09:30 +08:00
|
|
|
#include <memory>
|
2015-06-01 03:17:09 +08:00
|
|
|
#include <set>
|
2015-05-29 03:09:30 +08:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
namespace coff {
|
|
|
|
|
2015-06-01 03:17:09 +08:00
|
|
|
class LinkerDriver;
|
|
|
|
extern LinkerDriver *driver;
|
|
|
|
|
2015-05-30 00:06:00 +08:00
|
|
|
using llvm::COFF::MachineTypes;
|
2015-05-30 00:34:31 +08:00
|
|
|
using llvm::COFF::WindowsSubsystem;
|
2015-06-01 03:17:14 +08:00
|
|
|
using llvm::Optional;
|
2015-05-29 03:09:30 +08:00
|
|
|
|
2017-08-29 04:46:30 +08:00
|
|
|
class COFFOptTable : public llvm::opt::OptTable {
|
|
|
|
public:
|
|
|
|
COFFOptTable();
|
|
|
|
};
|
|
|
|
|
2020-05-03 05:53:59 +08:00
|
|
|
// Constructing the option table is expensive. Use a global table to avoid doing
|
|
|
|
// it more than once.
|
|
|
|
extern COFFOptTable optTable;
|
|
|
|
|
[COFF] Add a fastpath for /INCLUDE: in .drective sections
This speeds up linking chrome.dll with PGO instrumentation by 13%
(154271ms -> 134033ms).
LLVM's Option library is very slow. In particular, it allocates at least
one large-ish heap object (Arg) for every argument. When PGO
instrumentation is enabled, all the __profd_* symbols are added to the
@llvm.used list, which compiles down to these /INCLUDE: directives. This
means we have O(#symbols) directives to parse in the section, so we end
up allocating an Arg for every function symbol in the object file. This
is unnecessary.
To address the issue and speed up the link, extend the fast path that we
already have for /EXPORT:, which has similar scaling issues.
I promise that I took a hard look at optimizing the Option library, but
its data structures are very general and would need a lot of cleanup. We
have accumulated lots of optional features (option groups, aliases,
multiple values) over the years, and these are now properties of every
parsed argument, when the vast majority of arguments do not use these
features.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D78845
2020-04-25 08:26:17 +08:00
|
|
|
// The result of parsing the .drective section. The /export: and /include:
|
|
|
|
// options are handled separately because they reference symbols, and the number
|
|
|
|
// of symbols can be quite large. The LLVM Option library will perform at least
|
|
|
|
// one memory allocation per argument, and that is prohibitively slow for
|
|
|
|
// parsing directives.
|
|
|
|
struct ParsedDirectives {
|
|
|
|
std::vector<StringRef> exports;
|
|
|
|
std::vector<StringRef> includes;
|
|
|
|
llvm::opt::InputArgList args;
|
|
|
|
};
|
|
|
|
|
2015-06-07 10:55:19 +08:00
|
|
|
class ArgParser {
|
|
|
|
public:
|
2019-09-13 21:13:52 +08:00
|
|
|
// Parses command line options.
|
|
|
|
llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args);
|
2015-06-28 10:35:31 +08:00
|
|
|
|
2015-06-07 10:55:19 +08:00
|
|
|
// Tokenizes a given string and then parses as command line options.
|
2015-08-06 22:58:50 +08:00
|
|
|
llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); }
|
2015-06-07 10:55:19 +08:00
|
|
|
|
2017-12-27 14:08:10 +08:00
|
|
|
// Tokenizes a given string and then parses as command line options in
|
2018-01-10 04:36:42 +08:00
|
|
|
// .drectve section. /EXPORT options are returned in second element
|
|
|
|
// to be processed in fastpath.
|
[COFF] Add a fastpath for /INCLUDE: in .drective sections
This speeds up linking chrome.dll with PGO instrumentation by 13%
(154271ms -> 134033ms).
LLVM's Option library is very slow. In particular, it allocates at least
one large-ish heap object (Arg) for every argument. When PGO
instrumentation is enabled, all the __profd_* symbols are added to the
@llvm.used list, which compiles down to these /INCLUDE: directives. This
means we have O(#symbols) directives to parse in the section, so we end
up allocating an Arg for every function symbol in the object file. This
is unnecessary.
To address the issue and speed up the link, extend the fast path that we
already have for /EXPORT:, which has similar scaling issues.
I promise that I took a hard look at optimizing the Option library, but
its data structures are very general and would need a lot of cleanup. We
have accumulated lots of optional features (option groups, aliases,
multiple values) over the years, and these are now properties of every
parsed argument, when the vast majority of arguments do not use these
features.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D78845
2020-04-25 08:26:17 +08:00
|
|
|
ParsedDirectives parseDirectives(StringRef s);
|
2017-12-27 14:08:10 +08:00
|
|
|
|
2015-06-07 10:55:19 +08:00
|
|
|
private:
|
2019-09-13 21:13:52 +08:00
|
|
|
// Concatenate LINK environment variable.
|
|
|
|
void addLINK(SmallVector<const char *, 256> &argv);
|
2017-09-06 07:46:45 +08:00
|
|
|
|
2015-06-07 10:55:19 +08:00
|
|
|
std::vector<const char *> tokenize(StringRef s);
|
|
|
|
};
|
|
|
|
|
2015-06-01 03:17:09 +08:00
|
|
|
class LinkerDriver {
|
|
|
|
public:
|
2020-12-18 14:39:01 +08:00
|
|
|
void linkerMain(llvm::ArrayRef<const char *> args);
|
2015-06-01 03:17:09 +08:00
|
|
|
|
|
|
|
// Used by the resolver to parse .drectve section contents.
|
2019-03-07 04:18:38 +08:00
|
|
|
void parseDirectives(InputFile *file);
|
2015-06-01 03:17:09 +08:00
|
|
|
|
2016-12-15 12:02:23 +08:00
|
|
|
// Used by ArchiveFile to enqueue members.
|
2019-07-19 21:29:10 +08:00
|
|
|
void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym,
|
2016-12-15 12:02:23 +08:00
|
|
|
StringRef parentName);
|
2016-07-26 10:00:42 +08:00
|
|
|
|
2020-05-09 21:58:15 +08:00
|
|
|
void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false); }
|
|
|
|
|
2017-10-21 03:48:26 +08:00
|
|
|
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
|
|
|
|
|
2019-09-04 04:32:16 +08:00
|
|
|
void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
|
2019-06-03 20:39:47 +08:00
|
|
|
|
2015-06-01 03:17:09 +08:00
|
|
|
private:
|
2017-01-06 10:33:53 +08:00
|
|
|
std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
|
2016-12-15 12:02:23 +08:00
|
|
|
|
2015-06-01 03:17:12 +08:00
|
|
|
// Searches a file from search paths.
|
2015-06-01 03:17:14 +08:00
|
|
|
Optional<StringRef> findFile(StringRef filename);
|
|
|
|
Optional<StringRef> findLib(StringRef filename);
|
|
|
|
StringRef doFindFile(StringRef filename);
|
|
|
|
StringRef doFindLib(StringRef filename);
|
2018-10-10 17:00:10 +08:00
|
|
|
StringRef doFindLibMinGW(StringRef filename);
|
2015-06-01 03:17:12 +08:00
|
|
|
|
|
|
|
// Parses LIB environment which contains a list of search paths.
|
2015-06-20 06:39:48 +08:00
|
|
|
void addLibSearchPaths();
|
2015-06-01 03:17:12 +08:00
|
|
|
|
2015-06-20 06:39:48 +08:00
|
|
|
// Library search path. The first element is always "" (current directory).
|
2015-06-01 03:17:12 +08:00
|
|
|
std::vector<StringRef> searchPaths;
|
2018-06-13 05:47:31 +08:00
|
|
|
|
2019-08-30 14:56:33 +08:00
|
|
|
// Convert resource files and potentially merge input resource object
|
|
|
|
// trees into one resource tree.
|
|
|
|
void convertResources();
|
|
|
|
|
2019-02-20 06:06:44 +08:00
|
|
|
void maybeExportMinGWSymbols(const llvm::opt::InputArgList &args);
|
|
|
|
|
2018-06-13 05:47:31 +08:00
|
|
|
// We don't want to add the same file more than once.
|
|
|
|
// Files are uniquified by their filesystem and file number.
|
|
|
|
std::set<llvm::sys::fs::UniqueID> visitedFiles;
|
|
|
|
|
2016-12-16 11:45:59 +08:00
|
|
|
std::set<std::string> visitedLibs;
|
2015-06-01 05:04:56 +08:00
|
|
|
|
2017-11-04 05:21:47 +08:00
|
|
|
Symbol *addUndefined(StringRef sym);
|
2015-06-26 11:44:00 +08:00
|
|
|
|
[COFF] Fix /export:foo=bar when bar is a weak alias
Summary:
When handling exports from the command line or from .def files, the
linker does a "fuzzy" string lookup to allow finding mangled symbols.
However, when the symbol is re-exported under a new name, the linker has
to transfer the decorations from the exported symbol over to the new
name. This is implemented by taking the mangled symbol that was found in
the object and replacing the original symbol name with the export name.
Before this patch, LLD implemented the fuzzy search by adding an
undefined symbol with the unmangled name, and then during symbol
resolution, checking if similar mangled symbols had been added after the
last round of symbol resolution. If so, LLD makes the original symbol a
weak alias of the mangled symbol. Later, to get the original symbol
name, LLD would look through the weak alias and forward it on to the
import library writer, which copies the symbol decorations. This
approach doesn't work when bar is itself a weak alias, as is the case in
asan. It's especially bad when the aliasee of bar contains the string
"bar", consider "bar_default". In this case, we would end up exporting
the symbol "foo_default" when we should've exported just "foo".
To fix this, don't look through weak aliases to find the mangled name.
Save the mangled name earlier during fuzzy symbol lookup.
Fixes PR42074
Reviewers: mstorsjo, ruiu
Subscribers: thakis, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62984
llvm-svn: 362849
2019-06-08 06:05:12 +08:00
|
|
|
StringRef mangleMaybe(Symbol *s);
|
|
|
|
|
2015-06-29 09:03:53 +08:00
|
|
|
// Windows specific -- "main" is not the only main function in Windows.
|
|
|
|
// You can choose one from these four -- {w,}{WinMain,main}.
|
|
|
|
// There are four different entry point functions for them,
|
|
|
|
// {w,}{WinMain,main}CRTStartup, respectively. The linker needs to
|
|
|
|
// choose the right one depending on which "main" function is defined.
|
|
|
|
// This function looks up the symbol table and resolve corresponding
|
|
|
|
// entry point name.
|
|
|
|
StringRef findDefaultEntry();
|
|
|
|
WindowsSubsystem inferSubsystem();
|
|
|
|
|
2019-09-04 04:32:16 +08:00
|
|
|
void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
|
|
|
|
bool lazy);
|
2016-12-15 12:02:23 +08:00
|
|
|
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
|
2019-04-16 03:48:32 +08:00
|
|
|
StringRef parentName, uint64_t offsetInArchive);
|
2016-12-15 12:02:23 +08:00
|
|
|
|
|
|
|
void enqueueTask(std::function<void()> task);
|
|
|
|
bool run();
|
|
|
|
|
|
|
|
std::list<std::function<void()>> taskQueue;
|
|
|
|
std::vector<StringRef> filePaths;
|
|
|
|
std::vector<MemoryBufferRef> resources;
|
2017-12-28 15:41:19 +08:00
|
|
|
|
|
|
|
llvm::StringSet<> directivesExports;
|
2015-06-01 03:17:09 +08:00
|
|
|
};
|
|
|
|
|
2015-05-29 04:30:06 +08:00
|
|
|
// Functions below this line are defined in DriverUtils.cpp.
|
|
|
|
|
2015-05-30 00:11:52 +08:00
|
|
|
void printHelp(const char *argv0);
|
|
|
|
|
2015-05-30 00:18:15 +08:00
|
|
|
// Parses a string in the form of "<integer>[,<integer>]".
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr);
|
2015-05-30 00:18:15 +08:00
|
|
|
|
2018-02-06 09:58:26 +08:00
|
|
|
void parseGuard(StringRef arg);
|
|
|
|
|
2015-05-30 00:28:29 +08:00
|
|
|
// Parses a string in the form of "<integer>[.<integer>]".
|
|
|
|
// Minor's default value is 0.
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor);
|
2015-05-30 00:28:29 +08:00
|
|
|
|
2015-05-30 00:34:31 +08:00
|
|
|
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
|
2020-10-04 06:29:45 +08:00
|
|
|
uint32_t *minor, bool *gotVersion = nullptr);
|
2015-05-30 00:34:31 +08:00
|
|
|
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseAlternateName(StringRef);
|
|
|
|
void parseMerge(StringRef);
|
2016-06-20 11:39:39 +08:00
|
|
|
void parseSection(StringRef);
|
2017-08-15 03:07:27 +08:00
|
|
|
void parseAligncomm(StringRef);
|
2015-06-19 03:09:30 +08:00
|
|
|
|
2019-02-23 09:46:18 +08:00
|
|
|
// Parses a string in the form of "[:<integer>]"
|
|
|
|
void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine);
|
|
|
|
|
2015-06-18 08:12:42 +08:00
|
|
|
// Parses a string in the form of "EMBED[,=<integer>]|NO".
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseManifest(StringRef arg);
|
2015-06-18 08:12:42 +08:00
|
|
|
|
|
|
|
// Parses a string in the form of "level=<string>|uiAccess=<string>"
|
2015-08-06 22:58:50 +08:00
|
|
|
void parseManifestUAC(StringRef arg);
|
2015-06-18 08:12:42 +08:00
|
|
|
|
2019-04-25 22:02:26 +08:00
|
|
|
// Parses a string in the form of "cd|net[,(cd|net)]*"
|
|
|
|
void parseSwaprun(StringRef arg);
|
|
|
|
|
2015-06-18 08:12:42 +08:00
|
|
|
// Create a resource file containing a manifest XML.
|
2015-08-06 22:58:50 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> createManifestRes();
|
|
|
|
void createSideBySideManifest();
|
2015-06-18 08:12:42 +08:00
|
|
|
|
2015-06-17 08:16:33 +08:00
|
|
|
// Used for dllexported symbols.
|
2015-08-06 22:58:50 +08:00
|
|
|
Export parseExport(StringRef arg);
|
|
|
|
void fixupExports();
|
2015-07-16 06:21:08 +08:00
|
|
|
void assignExportOrdinals();
|
2015-06-17 08:16:33 +08:00
|
|
|
|
2015-06-05 03:21:24 +08:00
|
|
|
// Parses a string in the form of "key=value" and check
|
|
|
|
// if value matches previous values for the key.
|
|
|
|
// This feature used in the directive section to reject
|
|
|
|
// incompatible objects.
|
2019-03-30 03:58:58 +08:00
|
|
|
void checkFailIfMismatch(StringRef arg, InputFile *source);
|
2015-06-05 03:21:24 +08:00
|
|
|
|
2017-10-17 07:15:04 +08:00
|
|
|
// Convert Windows resource files (.res files) to a .obj file.
|
2019-08-30 14:56:33 +08:00
|
|
|
MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
|
|
|
|
ArrayRef<ObjFile *> objs);
|
2015-06-15 05:50:50 +08:00
|
|
|
|
2015-05-29 04:30:06 +08:00
|
|
|
// Create enum with OPT_xxx values for each option in Options.td
|
|
|
|
enum {
|
|
|
|
OPT_INVALID = 0,
|
2017-06-21 00:31:31 +08:00
|
|
|
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
|
2015-05-29 04:30:06 +08:00
|
|
|
#include "Options.inc"
|
|
|
|
#undef OPTION
|
|
|
|
};
|
|
|
|
|
2015-05-29 03:09:30 +08:00
|
|
|
} // namespace coff
|
|
|
|
} // namespace lld
|
|
|
|
|
|
|
|
#endif
|