xref: /openbsd-src/gnu/llvm/lld/wasm/Driver.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- Driver.cpp ---------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9ece8a530Spatrick #include "lld/Common/Driver.h"
10ece8a530Spatrick #include "Config.h"
11ece8a530Spatrick #include "InputChunks.h"
121cf9926bSpatrick #include "InputElement.h"
13ece8a530Spatrick #include "MarkLive.h"
14ece8a530Spatrick #include "SymbolTable.h"
15ece8a530Spatrick #include "Writer.h"
16ece8a530Spatrick #include "lld/Common/Args.h"
17*dfe94b16Srobert #include "lld/Common/CommonLinkerContext.h"
18ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
19bb684c34Spatrick #include "lld/Common/Filesystem.h"
20ece8a530Spatrick #include "lld/Common/Memory.h"
21ece8a530Spatrick #include "lld/Common/Reproduce.h"
22ece8a530Spatrick #include "lld/Common/Strings.h"
23ece8a530Spatrick #include "lld/Common/Version.h"
24ece8a530Spatrick #include "llvm/ADT/Twine.h"
251cf9926bSpatrick #include "llvm/Config/llvm-config.h"
26ece8a530Spatrick #include "llvm/Object/Wasm.h"
27ece8a530Spatrick #include "llvm/Option/Arg.h"
28ece8a530Spatrick #include "llvm/Option/ArgList.h"
29ece8a530Spatrick #include "llvm/Support/CommandLine.h"
30bb684c34Spatrick #include "llvm/Support/Host.h"
31bb684c34Spatrick #include "llvm/Support/Parallel.h"
32ece8a530Spatrick #include "llvm/Support/Path.h"
33ece8a530Spatrick #include "llvm/Support/Process.h"
34ece8a530Spatrick #include "llvm/Support/TarWriter.h"
35ece8a530Spatrick #include "llvm/Support/TargetSelect.h"
36*dfe94b16Srobert #include <optional>
37ece8a530Spatrick 
38ece8a530Spatrick #define DEBUG_TYPE "lld"
39ece8a530Spatrick 
40ece8a530Spatrick using namespace llvm;
41ece8a530Spatrick using namespace llvm::object;
42ece8a530Spatrick using namespace llvm::sys;
43ece8a530Spatrick using namespace llvm::wasm;
44ece8a530Spatrick 
45ece8a530Spatrick namespace lld {
46ece8a530Spatrick namespace wasm {
47ece8a530Spatrick Configuration *config;
48ece8a530Spatrick 
49ece8a530Spatrick namespace {
50ece8a530Spatrick 
51ece8a530Spatrick // Create enum with OPT_xxx values for each option in Options.td
52ece8a530Spatrick enum {
53ece8a530Spatrick   OPT_INVALID = 0,
54ece8a530Spatrick #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
55ece8a530Spatrick #include "Options.inc"
56ece8a530Spatrick #undef OPTION
57ece8a530Spatrick };
58ece8a530Spatrick 
59ece8a530Spatrick // This function is called on startup. We need this for LTO since
60ece8a530Spatrick // LTO calls LLVM functions to compile bitcode files to native code.
61ece8a530Spatrick // Technically this can be delayed until we read bitcode files, but
62ece8a530Spatrick // we don't bother to do lazily because the initialization is fast.
initLLVM()63ece8a530Spatrick static void initLLVM() {
64ece8a530Spatrick   InitializeAllTargets();
65ece8a530Spatrick   InitializeAllTargetMCs();
66ece8a530Spatrick   InitializeAllAsmPrinters();
67ece8a530Spatrick   InitializeAllAsmParsers();
68ece8a530Spatrick }
69ece8a530Spatrick 
70ece8a530Spatrick class LinkerDriver {
71ece8a530Spatrick public:
721cf9926bSpatrick   void linkerMain(ArrayRef<const char *> argsArr);
73ece8a530Spatrick 
74ece8a530Spatrick private:
75ece8a530Spatrick   void createFiles(opt::InputArgList &args);
76ece8a530Spatrick   void addFile(StringRef path);
77ece8a530Spatrick   void addLibrary(StringRef name);
78ece8a530Spatrick 
79ece8a530Spatrick   // True if we are in --whole-archive and --no-whole-archive.
80ece8a530Spatrick   bool inWholeArchive = false;
81ece8a530Spatrick 
82ece8a530Spatrick   std::vector<InputFile *> files;
83ece8a530Spatrick };
84ece8a530Spatrick } // anonymous namespace
85ece8a530Spatrick 
link(ArrayRef<const char * > args,llvm::raw_ostream & stdoutOS,llvm::raw_ostream & stderrOS,bool exitEarly,bool disableOutput)86*dfe94b16Srobert bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
87*dfe94b16Srobert           llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
88*dfe94b16Srobert   // This driver-specific context will be freed later by lldMain().
89*dfe94b16Srobert   auto *ctx = new CommonLinkerContext;
90ece8a530Spatrick 
91*dfe94b16Srobert   ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
92*dfe94b16Srobert   ctx->e.logName = args::getFilenameWithoutExe(args[0]);
93*dfe94b16Srobert   ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
94ece8a530Spatrick                                  "-error-limit=0 to see all errors)";
95ece8a530Spatrick 
96ece8a530Spatrick   config = make<Configuration>();
97ece8a530Spatrick   symtab = make<SymbolTable>();
98ece8a530Spatrick 
99ece8a530Spatrick   initLLVM();
1001cf9926bSpatrick   LinkerDriver().linkerMain(args);
101ece8a530Spatrick 
102*dfe94b16Srobert   return errorCount() == 0;
103ece8a530Spatrick }
104ece8a530Spatrick 
105ece8a530Spatrick // Create prefix string literals used in Options.td
106*dfe94b16Srobert #define PREFIX(NAME, VALUE)                                                    \
107*dfe94b16Srobert   static constexpr StringLiteral NAME##_init[] = VALUE;                        \
108*dfe94b16Srobert   static constexpr ArrayRef<StringLiteral> NAME(NAME##_init,                   \
109*dfe94b16Srobert                                                 std::size(NAME##_init) - 1);
110ece8a530Spatrick #include "Options.inc"
111ece8a530Spatrick #undef PREFIX
112ece8a530Spatrick 
113ece8a530Spatrick // Create table mapping all options defined in Options.td
114*dfe94b16Srobert static constexpr opt::OptTable::Info optInfo[] = {
115ece8a530Spatrick #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
116ece8a530Spatrick   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
117ece8a530Spatrick    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
118ece8a530Spatrick #include "Options.inc"
119ece8a530Spatrick #undef OPTION
120ece8a530Spatrick };
121ece8a530Spatrick 
122ece8a530Spatrick namespace {
123*dfe94b16Srobert class WasmOptTable : public opt::GenericOptTable {
124ece8a530Spatrick public:
WasmOptTable()125*dfe94b16Srobert   WasmOptTable() : opt::GenericOptTable(optInfo) {}
126ece8a530Spatrick   opt::InputArgList parse(ArrayRef<const char *> argv);
127ece8a530Spatrick };
128ece8a530Spatrick } // namespace
129ece8a530Spatrick 
130ece8a530Spatrick // Set color diagnostics according to -color-diagnostics={auto,always,never}
131ece8a530Spatrick // or -no-color-diagnostics flags.
handleColorDiagnostics(opt::InputArgList & args)132ece8a530Spatrick static void handleColorDiagnostics(opt::InputArgList &args) {
133ece8a530Spatrick   auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
134ece8a530Spatrick                               OPT_no_color_diagnostics);
135ece8a530Spatrick   if (!arg)
136ece8a530Spatrick     return;
137ece8a530Spatrick   if (arg->getOption().getID() == OPT_color_diagnostics) {
138ece8a530Spatrick     lld::errs().enable_colors(true);
139ece8a530Spatrick   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
140ece8a530Spatrick     lld::errs().enable_colors(false);
141ece8a530Spatrick   } else {
142ece8a530Spatrick     StringRef s = arg->getValue();
143ece8a530Spatrick     if (s == "always")
144ece8a530Spatrick       lld::errs().enable_colors(true);
145ece8a530Spatrick     else if (s == "never")
146ece8a530Spatrick       lld::errs().enable_colors(false);
147ece8a530Spatrick     else if (s != "auto")
148ece8a530Spatrick       error("unknown option: --color-diagnostics=" + s);
149ece8a530Spatrick   }
150ece8a530Spatrick }
151ece8a530Spatrick 
getQuotingStyle(opt::InputArgList & args)152bb684c34Spatrick static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
153bb684c34Spatrick   if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
154bb684c34Spatrick     StringRef s = arg->getValue();
155bb684c34Spatrick     if (s != "windows" && s != "posix")
156bb684c34Spatrick       error("invalid response file quoting: " + s);
157bb684c34Spatrick     if (s == "windows")
158bb684c34Spatrick       return cl::TokenizeWindowsCommandLine;
159bb684c34Spatrick     return cl::TokenizeGNUCommandLine;
160bb684c34Spatrick   }
161bb684c34Spatrick   if (Triple(sys::getProcessTriple()).isOSWindows())
162bb684c34Spatrick     return cl::TokenizeWindowsCommandLine;
163bb684c34Spatrick   return cl::TokenizeGNUCommandLine;
164bb684c34Spatrick }
165bb684c34Spatrick 
166ece8a530Spatrick // Find a file by concatenating given paths.
findFile(StringRef path1,const Twine & path2)167*dfe94b16Srobert static std::optional<std::string> findFile(StringRef path1,
168*dfe94b16Srobert                                            const Twine &path2) {
169ece8a530Spatrick   SmallString<128> s;
170ece8a530Spatrick   path::append(s, path1, path2);
171ece8a530Spatrick   if (fs::exists(s))
172bb684c34Spatrick     return std::string(s);
173*dfe94b16Srobert   return std::nullopt;
174ece8a530Spatrick }
175ece8a530Spatrick 
parse(ArrayRef<const char * > argv)176ece8a530Spatrick opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) {
177ece8a530Spatrick   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
178ece8a530Spatrick 
179ece8a530Spatrick   unsigned missingIndex;
180ece8a530Spatrick   unsigned missingCount;
181ece8a530Spatrick 
182bb684c34Spatrick   // We need to get the quoting style for response files before parsing all
183bb684c34Spatrick   // options so we parse here before and ignore all the options but
184bb684c34Spatrick   // --rsp-quoting.
185ece8a530Spatrick   opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
186ece8a530Spatrick 
187bb684c34Spatrick   // Expand response files (arguments in the form of @<filename>)
188bb684c34Spatrick   // and then parse the argument again.
189*dfe94b16Srobert   cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec);
190bb684c34Spatrick   args = this->ParseArgs(vec, missingIndex, missingCount);
191bb684c34Spatrick 
192ece8a530Spatrick   handleColorDiagnostics(args);
193*dfe94b16Srobert   if (missingCount)
194*dfe94b16Srobert     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
195*dfe94b16Srobert 
196ece8a530Spatrick   for (auto *arg : args.filtered(OPT_UNKNOWN))
197ece8a530Spatrick     error("unknown argument: " + arg->getAsString(args));
198ece8a530Spatrick   return args;
199ece8a530Spatrick }
200ece8a530Spatrick 
201ece8a530Spatrick // Currently we allow a ".imports" to live alongside a library. This can
202ece8a530Spatrick // be used to specify a list of symbols which can be undefined at link
203ece8a530Spatrick // time (imported from the environment.  For example libc.a include an
204ece8a530Spatrick // import file that lists the syscall functions it relies on at runtime.
205ece8a530Spatrick // In the long run this information would be better stored as a symbol
206ece8a530Spatrick // attribute/flag in the object file itself.
207ece8a530Spatrick // See: https://github.com/WebAssembly/tool-conventions/issues/35
readImportFile(StringRef filename)208ece8a530Spatrick static void readImportFile(StringRef filename) {
209*dfe94b16Srobert   if (std::optional<MemoryBufferRef> buf = readFile(filename))
210ece8a530Spatrick     for (StringRef sym : args::getLines(*buf))
211ece8a530Spatrick       config->allowUndefinedSymbols.insert(sym);
212ece8a530Spatrick }
213ece8a530Spatrick 
214ece8a530Spatrick // Returns slices of MB by parsing MB as an archive file.
215ece8a530Spatrick // Each slice consists of a member file in the archive.
getArchiveMembers(MemoryBufferRef mb)216ece8a530Spatrick std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef mb) {
217ece8a530Spatrick   std::unique_ptr<Archive> file =
218ece8a530Spatrick       CHECK(Archive::create(mb),
219ece8a530Spatrick             mb.getBufferIdentifier() + ": failed to parse archive");
220ece8a530Spatrick 
221ece8a530Spatrick   std::vector<MemoryBufferRef> v;
222ece8a530Spatrick   Error err = Error::success();
223ece8a530Spatrick   for (const Archive::Child &c : file->children(err)) {
224ece8a530Spatrick     MemoryBufferRef mbref =
225ece8a530Spatrick         CHECK(c.getMemoryBufferRef(),
226ece8a530Spatrick               mb.getBufferIdentifier() +
227ece8a530Spatrick                   ": could not get the buffer for a child of the archive");
228ece8a530Spatrick     v.push_back(mbref);
229ece8a530Spatrick   }
230ece8a530Spatrick   if (err)
231ece8a530Spatrick     fatal(mb.getBufferIdentifier() +
232ece8a530Spatrick           ": Archive::children failed: " + toString(std::move(err)));
233ece8a530Spatrick 
234ece8a530Spatrick   // Take ownership of memory buffers created for members of thin archives.
235ece8a530Spatrick   for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers())
236ece8a530Spatrick     make<std::unique_ptr<MemoryBuffer>>(std::move(mb));
237ece8a530Spatrick 
238ece8a530Spatrick   return v;
239ece8a530Spatrick }
240ece8a530Spatrick 
addFile(StringRef path)241ece8a530Spatrick void LinkerDriver::addFile(StringRef path) {
242*dfe94b16Srobert   std::optional<MemoryBufferRef> buffer = readFile(path);
243*dfe94b16Srobert   if (!buffer)
244ece8a530Spatrick     return;
245ece8a530Spatrick   MemoryBufferRef mbref = *buffer;
246ece8a530Spatrick 
247ece8a530Spatrick   switch (identify_magic(mbref.getBuffer())) {
248ece8a530Spatrick   case file_magic::archive: {
249ece8a530Spatrick     SmallString<128> importFile = path;
250ece8a530Spatrick     path::replace_extension(importFile, ".imports");
251ece8a530Spatrick     if (fs::exists(importFile))
252ece8a530Spatrick       readImportFile(importFile.str());
253ece8a530Spatrick 
254ece8a530Spatrick     // Handle -whole-archive.
255ece8a530Spatrick     if (inWholeArchive) {
2561cf9926bSpatrick       for (MemoryBufferRef &m : getArchiveMembers(mbref)) {
2571cf9926bSpatrick         auto *object = createObjectFile(m, path);
2581cf9926bSpatrick         // Mark object as live; object members are normally not
2591cf9926bSpatrick         // live by default but -whole-archive is designed to treat
2601cf9926bSpatrick         // them as such.
2611cf9926bSpatrick         object->markLive();
2621cf9926bSpatrick         files.push_back(object);
2631cf9926bSpatrick       }
2641cf9926bSpatrick 
265ece8a530Spatrick       return;
266ece8a530Spatrick     }
267ece8a530Spatrick 
268ece8a530Spatrick     std::unique_ptr<Archive> file =
269ece8a530Spatrick         CHECK(Archive::create(mbref), path + ": failed to parse archive");
270ece8a530Spatrick 
271ece8a530Spatrick     if (!file->isEmpty() && !file->hasSymbolTable()) {
272ece8a530Spatrick       error(mbref.getBufferIdentifier() +
273ece8a530Spatrick             ": archive has no index; run ranlib to add one");
274ece8a530Spatrick     }
275ece8a530Spatrick 
276ece8a530Spatrick     files.push_back(make<ArchiveFile>(mbref));
277ece8a530Spatrick     return;
278ece8a530Spatrick   }
279ece8a530Spatrick   case file_magic::bitcode:
280ece8a530Spatrick   case file_magic::wasm_object:
281ece8a530Spatrick     files.push_back(createObjectFile(mbref));
282ece8a530Spatrick     break;
283*dfe94b16Srobert   case file_magic::unknown:
284*dfe94b16Srobert     if (mbref.getBuffer().starts_with("#STUB")) {
285*dfe94b16Srobert       files.push_back(make<StubFile>(mbref));
286*dfe94b16Srobert       break;
287*dfe94b16Srobert     }
288*dfe94b16Srobert     [[fallthrough]];
289ece8a530Spatrick   default:
290ece8a530Spatrick     error("unknown file type: " + mbref.getBufferIdentifier());
291ece8a530Spatrick   }
292ece8a530Spatrick }
293ece8a530Spatrick 
findFromSearchPaths(StringRef path)294*dfe94b16Srobert static std::optional<std::string> findFromSearchPaths(StringRef path) {
295*dfe94b16Srobert   for (StringRef dir : config->searchPaths)
296*dfe94b16Srobert     if (std::optional<std::string> s = findFile(dir, path))
297*dfe94b16Srobert       return s;
298*dfe94b16Srobert   return std::nullopt;
299ece8a530Spatrick }
300ece8a530Spatrick 
301*dfe94b16Srobert // This is for -l<basename>. We'll look for lib<basename>.a from
302*dfe94b16Srobert // search paths.
searchLibraryBaseName(StringRef name)303*dfe94b16Srobert static std::optional<std::string> searchLibraryBaseName(StringRef name) {
304*dfe94b16Srobert   for (StringRef dir : config->searchPaths) {
305*dfe94b16Srobert     // Currently we don't enable dyanmic linking at all unless -shared or -pie
306*dfe94b16Srobert     // are used, so don't even look for .so files in that case..
307*dfe94b16Srobert     if (config->isPic && !config->isStatic)
308*dfe94b16Srobert       if (std::optional<std::string> s = findFile(dir, "lib" + name + ".so"))
309*dfe94b16Srobert         return s;
310*dfe94b16Srobert     if (std::optional<std::string> s = findFile(dir, "lib" + name + ".a"))
311*dfe94b16Srobert       return s;
312*dfe94b16Srobert   }
313*dfe94b16Srobert   return std::nullopt;
314*dfe94b16Srobert }
315*dfe94b16Srobert 
316*dfe94b16Srobert // This is for -l<namespec>.
searchLibrary(StringRef name)317*dfe94b16Srobert static std::optional<std::string> searchLibrary(StringRef name) {
318*dfe94b16Srobert   if (name.startswith(":"))
319*dfe94b16Srobert     return findFromSearchPaths(name.substr(1));
320*dfe94b16Srobert   return searchLibraryBaseName(name);
321*dfe94b16Srobert }
322*dfe94b16Srobert 
323*dfe94b16Srobert // Add a given library by searching it from input search paths.
addLibrary(StringRef name)324*dfe94b16Srobert void LinkerDriver::addLibrary(StringRef name) {
325*dfe94b16Srobert   if (std::optional<std::string> path = searchLibrary(name))
326*dfe94b16Srobert     addFile(saver().save(*path));
327*dfe94b16Srobert   else
328*dfe94b16Srobert     error("unable to find library -l" + name, ErrorTag::LibNotFound, {name});
329ece8a530Spatrick }
330ece8a530Spatrick 
createFiles(opt::InputArgList & args)331ece8a530Spatrick void LinkerDriver::createFiles(opt::InputArgList &args) {
332ece8a530Spatrick   for (auto *arg : args) {
333ece8a530Spatrick     switch (arg->getOption().getID()) {
334*dfe94b16Srobert     case OPT_library:
335ece8a530Spatrick       addLibrary(arg->getValue());
336ece8a530Spatrick       break;
337ece8a530Spatrick     case OPT_INPUT:
338ece8a530Spatrick       addFile(arg->getValue());
339ece8a530Spatrick       break;
340*dfe94b16Srobert     case OPT_Bstatic:
341*dfe94b16Srobert       config->isStatic = true;
342*dfe94b16Srobert       break;
343*dfe94b16Srobert     case OPT_Bdynamic:
344*dfe94b16Srobert       config->isStatic = false;
345*dfe94b16Srobert       break;
346ece8a530Spatrick     case OPT_whole_archive:
347ece8a530Spatrick       inWholeArchive = true;
348ece8a530Spatrick       break;
349ece8a530Spatrick     case OPT_no_whole_archive:
350ece8a530Spatrick       inWholeArchive = false;
351ece8a530Spatrick       break;
352ece8a530Spatrick     }
353ece8a530Spatrick   }
354bb684c34Spatrick   if (files.empty() && errorCount() == 0)
355bb684c34Spatrick     error("no input files");
356ece8a530Spatrick }
357ece8a530Spatrick 
getEntry(opt::InputArgList & args)358ece8a530Spatrick static StringRef getEntry(opt::InputArgList &args) {
359ece8a530Spatrick   auto *arg = args.getLastArg(OPT_entry, OPT_no_entry);
360ece8a530Spatrick   if (!arg) {
361ece8a530Spatrick     if (args.hasArg(OPT_relocatable))
362ece8a530Spatrick       return "";
363ece8a530Spatrick     if (args.hasArg(OPT_shared))
364ece8a530Spatrick       return "__wasm_call_ctors";
365ece8a530Spatrick     return "_start";
366ece8a530Spatrick   }
367ece8a530Spatrick   if (arg->getOption().getID() == OPT_no_entry)
368ece8a530Spatrick     return "";
369ece8a530Spatrick   return arg->getValue();
370ece8a530Spatrick }
371ece8a530Spatrick 
3721cf9926bSpatrick // Determines what we should do if there are remaining unresolved
3731cf9926bSpatrick // symbols after the name resolution.
getUnresolvedSymbolPolicy(opt::InputArgList & args)3741cf9926bSpatrick static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) {
3751cf9926bSpatrick   UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols,
3761cf9926bSpatrick                                               OPT_warn_unresolved_symbols, true)
3771cf9926bSpatrick                                      ? UnresolvedPolicy::ReportError
3781cf9926bSpatrick                                      : UnresolvedPolicy::Warn;
3791cf9926bSpatrick 
3801cf9926bSpatrick   if (auto *arg = args.getLastArg(OPT_unresolved_symbols)) {
3811cf9926bSpatrick     StringRef s = arg->getValue();
3821cf9926bSpatrick     if (s == "ignore-all")
3831cf9926bSpatrick       return UnresolvedPolicy::Ignore;
384*dfe94b16Srobert     if (s == "import-dynamic")
385*dfe94b16Srobert       return UnresolvedPolicy::ImportDynamic;
3861cf9926bSpatrick     if (s == "report-all")
3871cf9926bSpatrick       return errorOrWarn;
3881cf9926bSpatrick     error("unknown --unresolved-symbols value: " + s);
3891cf9926bSpatrick   }
3901cf9926bSpatrick 
3911cf9926bSpatrick   return errorOrWarn;
3921cf9926bSpatrick }
3931cf9926bSpatrick 
394ece8a530Spatrick // Initializes Config members by the command line options.
readConfigs(opt::InputArgList & args)395ece8a530Spatrick static void readConfigs(opt::InputArgList &args) {
3961cf9926bSpatrick   config->bsymbolic = args.hasArg(OPT_Bsymbolic);
397ece8a530Spatrick   config->checkFeatures =
398ece8a530Spatrick       args.hasFlag(OPT_check_features, OPT_no_check_features, true);
399ece8a530Spatrick   config->compressRelocations = args.hasArg(OPT_compress_relocations);
400ece8a530Spatrick   config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
401ece8a530Spatrick   config->disableVerify = args.hasArg(OPT_disable_verify);
402ece8a530Spatrick   config->emitRelocs = args.hasArg(OPT_emit_relocs);
403bb684c34Spatrick   config->experimentalPic = args.hasArg(OPT_experimental_pic);
404ece8a530Spatrick   config->entry = getEntry(args);
405ece8a530Spatrick   config->exportAll = args.hasArg(OPT_export_all);
406ece8a530Spatrick   config->exportTable = args.hasArg(OPT_export_table);
407ece8a530Spatrick   config->growableTable = args.hasArg(OPT_growable_table);
408*dfe94b16Srobert 
409*dfe94b16Srobert   if (args.hasArg(OPT_import_memory_with_name)) {
410*dfe94b16Srobert     config->memoryImport =
411*dfe94b16Srobert         args.getLastArgValue(OPT_import_memory_with_name).split(",");
412*dfe94b16Srobert   } else if (args.hasArg(OPT_import_memory)) {
413*dfe94b16Srobert     config->memoryImport =
414*dfe94b16Srobert         std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
415*dfe94b16Srobert   } else {
416*dfe94b16Srobert     config->memoryImport =
417*dfe94b16Srobert         std::optional<std::pair<llvm::StringRef, llvm::StringRef>>();
418*dfe94b16Srobert   }
419*dfe94b16Srobert 
420*dfe94b16Srobert   if (args.hasArg(OPT_export_memory_with_name)) {
421*dfe94b16Srobert     config->memoryExport =
422*dfe94b16Srobert         args.getLastArgValue(OPT_export_memory_with_name);
423*dfe94b16Srobert   } else if (args.hasArg(OPT_export_memory)) {
424*dfe94b16Srobert     config->memoryExport = memoryName;
425*dfe94b16Srobert   } else {
426*dfe94b16Srobert     config->memoryExport = std::optional<llvm::StringRef>();
427*dfe94b16Srobert   }
428*dfe94b16Srobert 
429ece8a530Spatrick   config->sharedMemory = args.hasArg(OPT_shared_memory);
430ece8a530Spatrick   config->importTable = args.hasArg(OPT_import_table);
4311cf9926bSpatrick   config->importUndefined = args.hasArg(OPT_import_undefined);
432ece8a530Spatrick   config->ltoo = args::getInteger(args, OPT_lto_O, 2);
433ece8a530Spatrick   config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
4341cf9926bSpatrick   config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
4351cf9926bSpatrick   config->mapFile = args.getLastArgValue(OPT_Map);
4361cf9926bSpatrick   config->optimize = args::getInteger(args, OPT_O, 1);
437ece8a530Spatrick   config->outputFile = args.getLastArgValue(OPT_o);
438ece8a530Spatrick   config->relocatable = args.hasArg(OPT_relocatable);
439ece8a530Spatrick   config->gcSections =
440ece8a530Spatrick       args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable);
441ece8a530Spatrick   config->mergeDataSegments =
442ece8a530Spatrick       args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
443ece8a530Spatrick                    !config->relocatable);
444ece8a530Spatrick   config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
445ece8a530Spatrick   config->printGcSections =
446ece8a530Spatrick       args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
447ece8a530Spatrick   config->saveTemps = args.hasArg(OPT_save_temps);
448*dfe94b16Srobert   config->searchPaths = args::getStrings(args, OPT_library_path);
449ece8a530Spatrick   config->shared = args.hasArg(OPT_shared);
450ece8a530Spatrick   config->stripAll = args.hasArg(OPT_strip_all);
451ece8a530Spatrick   config->stripDebug = args.hasArg(OPT_strip_debug);
452ece8a530Spatrick   config->stackFirst = args.hasArg(OPT_stack_first);
453ece8a530Spatrick   config->trace = args.hasArg(OPT_trace);
454ece8a530Spatrick   config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir);
455ece8a530Spatrick   config->thinLTOCachePolicy = CHECK(
456ece8a530Spatrick       parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),
457ece8a530Spatrick       "--thinlto-cache-policy: invalid cache policy");
4581cf9926bSpatrick   config->unresolvedSymbols = getUnresolvedSymbolPolicy(args);
459*dfe94b16Srobert   config->whyExtract = args.getLastArgValue(OPT_why_extract);
460ece8a530Spatrick   errorHandler().verbose = args.hasArg(OPT_verbose);
461ece8a530Spatrick   LLVM_DEBUG(errorHandler().verbose = true);
462ece8a530Spatrick 
463ece8a530Spatrick   config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
464*dfe94b16Srobert   config->globalBase = args::getInteger(args, OPT_global_base, 0);
465ece8a530Spatrick   config->maxMemory = args::getInteger(args, OPT_max_memory, 0);
466ece8a530Spatrick   config->zStackSize =
467ece8a530Spatrick       args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
468ece8a530Spatrick 
469ece8a530Spatrick   // Default value of exportDynamic depends on `-shared`
470ece8a530Spatrick   config->exportDynamic =
471ece8a530Spatrick       args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, config->shared);
472ece8a530Spatrick 
473bb684c34Spatrick   // Parse wasm32/64.
474bb684c34Spatrick   if (auto *arg = args.getLastArg(OPT_m)) {
475bb684c34Spatrick     StringRef s = arg->getValue();
476bb684c34Spatrick     if (s == "wasm32")
477bb684c34Spatrick       config->is64 = false;
478bb684c34Spatrick     else if (s == "wasm64")
479bb684c34Spatrick       config->is64 = true;
480bb684c34Spatrick     else
481bb684c34Spatrick       error("invalid target architecture: " + s);
482bb684c34Spatrick   }
483bb684c34Spatrick 
484bb684c34Spatrick   // --threads= takes a positive integer and provides the default value for
485bb684c34Spatrick   // --thinlto-jobs=.
486bb684c34Spatrick   if (auto *arg = args.getLastArg(OPT_threads)) {
487bb684c34Spatrick     StringRef v(arg->getValue());
488bb684c34Spatrick     unsigned threads = 0;
489bb684c34Spatrick     if (!llvm::to_integer(v, threads, 0) || threads == 0)
490bb684c34Spatrick       error(arg->getSpelling() + ": expected a positive integer, but got '" +
491bb684c34Spatrick             arg->getValue() + "'");
492bb684c34Spatrick     parallel::strategy = hardware_concurrency(threads);
493bb684c34Spatrick     config->thinLTOJobs = v;
494bb684c34Spatrick   }
495bb684c34Spatrick   if (auto *arg = args.getLastArg(OPT_thinlto_jobs))
496bb684c34Spatrick     config->thinLTOJobs = arg->getValue();
497bb684c34Spatrick 
498ece8a530Spatrick   if (auto *arg = args.getLastArg(OPT_features)) {
499ece8a530Spatrick     config->features =
500*dfe94b16Srobert         std::optional<std::vector<std::string>>(std::vector<std::string>());
501ece8a530Spatrick     for (StringRef s : arg->getValues())
502bb684c34Spatrick       config->features->push_back(std::string(s));
503ece8a530Spatrick   }
5041cf9926bSpatrick 
505*dfe94b16Srobert   if (auto *arg = args.getLastArg(OPT_extra_features)) {
506*dfe94b16Srobert     config->extraFeatures =
507*dfe94b16Srobert         std::optional<std::vector<std::string>>(std::vector<std::string>());
508*dfe94b16Srobert     for (StringRef s : arg->getValues())
509*dfe94b16Srobert       config->extraFeatures->push_back(std::string(s));
510*dfe94b16Srobert   }
511*dfe94b16Srobert 
5121cf9926bSpatrick   // Legacy --allow-undefined flag which is equivalent to
5131cf9926bSpatrick   // --unresolve-symbols=ignore + --import-undefined
5141cf9926bSpatrick   if (args.hasArg(OPT_allow_undefined)) {
5151cf9926bSpatrick     config->importUndefined = true;
5161cf9926bSpatrick     config->unresolvedSymbols = UnresolvedPolicy::Ignore;
5171cf9926bSpatrick   }
5181cf9926bSpatrick 
5191cf9926bSpatrick   if (args.hasArg(OPT_print_map))
5201cf9926bSpatrick     config->mapFile = "-";
521ece8a530Spatrick }
522ece8a530Spatrick 
523ece8a530Spatrick // Some Config members do not directly correspond to any particular
524ece8a530Spatrick // command line options, but computed based on other Config values.
525ece8a530Spatrick // This function initialize such members. See Config.h for the details
526ece8a530Spatrick // of these values.
setConfigs()527ece8a530Spatrick static void setConfigs() {
528ece8a530Spatrick   config->isPic = config->pie || config->shared;
529ece8a530Spatrick 
530ece8a530Spatrick   if (config->isPic) {
531ece8a530Spatrick     if (config->exportTable)
532ece8a530Spatrick       error("-shared/-pie is incompatible with --export-table");
533ece8a530Spatrick     config->importTable = true;
534ece8a530Spatrick   }
535ece8a530Spatrick 
5361cf9926bSpatrick   if (config->relocatable) {
5371cf9926bSpatrick     if (config->exportTable)
5381cf9926bSpatrick       error("--relocatable is incompatible with --export-table");
5391cf9926bSpatrick     if (config->growableTable)
5401cf9926bSpatrick       error("--relocatable is incompatible with --growable-table");
5411cf9926bSpatrick     // Ignore any --import-table, as it's redundant.
5421cf9926bSpatrick     config->importTable = true;
5431cf9926bSpatrick   }
5441cf9926bSpatrick 
545ece8a530Spatrick   if (config->shared) {
546*dfe94b16Srobert     if (config->memoryExport.has_value()) {
547*dfe94b16Srobert       error("--export-memory is incompatible with --shared");
548*dfe94b16Srobert     }
549*dfe94b16Srobert     if (!config->memoryImport.has_value()) {
550*dfe94b16Srobert       config->memoryImport =
551*dfe94b16Srobert           std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
552*dfe94b16Srobert     }
5531cf9926bSpatrick     config->importUndefined = true;
554*dfe94b16Srobert   }
555*dfe94b16Srobert 
556*dfe94b16Srobert   // If neither export-memory nor import-memory is specified, default to
557*dfe94b16Srobert   // exporting memory under its default name.
558*dfe94b16Srobert   if (!config->memoryExport.has_value() && !config->memoryImport.has_value()) {
559*dfe94b16Srobert     config->memoryExport = memoryName;
560ece8a530Spatrick   }
561ece8a530Spatrick }
562ece8a530Spatrick 
563ece8a530Spatrick // Some command line options or some combinations of them are not allowed.
564ece8a530Spatrick // This function checks for such errors.
checkOptions(opt::InputArgList & args)565ece8a530Spatrick static void checkOptions(opt::InputArgList &args) {
566ece8a530Spatrick   if (!config->stripDebug && !config->stripAll && config->compressRelocations)
567ece8a530Spatrick     error("--compress-relocations is incompatible with output debug"
568ece8a530Spatrick           " information. Please pass --strip-debug or --strip-all");
569ece8a530Spatrick 
570ece8a530Spatrick   if (config->ltoo > 3)
571ece8a530Spatrick     error("invalid optimization level for LTO: " + Twine(config->ltoo));
572ece8a530Spatrick   if (config->ltoPartitions == 0)
573ece8a530Spatrick     error("--lto-partitions: number of threads must be > 0");
574bb684c34Spatrick   if (!get_threadpool_strategy(config->thinLTOJobs))
575bb684c34Spatrick     error("--thinlto-jobs: invalid job count: " + config->thinLTOJobs);
576ece8a530Spatrick 
577ece8a530Spatrick   if (config->pie && config->shared)
578ece8a530Spatrick     error("-shared and -pie may not be used together");
579ece8a530Spatrick 
580ece8a530Spatrick   if (config->outputFile.empty())
581ece8a530Spatrick     error("no output file specified");
582ece8a530Spatrick 
583ece8a530Spatrick   if (config->importTable && config->exportTable)
584ece8a530Spatrick     error("--import-table and --export-table may not be used together");
585ece8a530Spatrick 
586ece8a530Spatrick   if (config->relocatable) {
587ece8a530Spatrick     if (!config->entry.empty())
588ece8a530Spatrick       error("entry point specified for relocatable output file");
589ece8a530Spatrick     if (config->gcSections)
590ece8a530Spatrick       error("-r and --gc-sections may not be used together");
591ece8a530Spatrick     if (config->compressRelocations)
592ece8a530Spatrick       error("-r -and --compress-relocations may not be used together");
593ece8a530Spatrick     if (args.hasArg(OPT_undefined))
594ece8a530Spatrick       error("-r -and --undefined may not be used together");
595ece8a530Spatrick     if (config->pie)
596ece8a530Spatrick       error("-r and -pie may not be used together");
597bb684c34Spatrick     if (config->sharedMemory)
598bb684c34Spatrick       error("-r and --shared-memory may not be used together");
599*dfe94b16Srobert     if (config->globalBase)
600*dfe94b16Srobert       error("-r and --global-base may not by used together");
601bb684c34Spatrick   }
602bb684c34Spatrick 
603bb684c34Spatrick   // To begin to prepare for Module Linking-style shared libraries, start
604bb684c34Spatrick   // warning about uses of `-shared` and related flags outside of Experimental
605bb684c34Spatrick   // mode, to give anyone using them a heads-up that they will be changing.
606bb684c34Spatrick   //
607bb684c34Spatrick   // Also, warn about flags which request explicit exports.
608bb684c34Spatrick   if (!config->experimentalPic) {
609bb684c34Spatrick     // -shared will change meaning when Module Linking is implemented.
610bb684c34Spatrick     if (config->shared) {
611bb684c34Spatrick       warn("creating shared libraries, with -shared, is not yet stable");
612bb684c34Spatrick     }
613bb684c34Spatrick 
614bb684c34Spatrick     // -pie will change meaning when Module Linking is implemented.
615bb684c34Spatrick     if (config->pie) {
616bb684c34Spatrick       warn("creating PIEs, with -pie, is not yet stable");
617bb684c34Spatrick     }
618*dfe94b16Srobert 
619*dfe94b16Srobert     if (config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {
620*dfe94b16Srobert       warn("dynamic imports are not yet stable "
621*dfe94b16Srobert            "(--unresolved-symbols=import-dynamic)");
622*dfe94b16Srobert     }
623ece8a530Spatrick   }
6241cf9926bSpatrick 
6251cf9926bSpatrick   if (config->bsymbolic && !config->shared) {
6261cf9926bSpatrick     warn("-Bsymbolic is only meaningful when combined with -shared");
6271cf9926bSpatrick   }
628*dfe94b16Srobert 
629*dfe94b16Srobert   if (config->globalBase && config->isPic) {
630*dfe94b16Srobert     error("--global-base may not be used with -shared/-pie");
631*dfe94b16Srobert   }
632*dfe94b16Srobert }
633*dfe94b16Srobert 
getReproduceOption(opt::InputArgList & args)634*dfe94b16Srobert static const char *getReproduceOption(opt::InputArgList &args) {
635*dfe94b16Srobert   if (auto *arg = args.getLastArg(OPT_reproduce))
636*dfe94b16Srobert     return arg->getValue();
637*dfe94b16Srobert   return getenv("LLD_REPRODUCE");
638ece8a530Spatrick }
639ece8a530Spatrick 
640ece8a530Spatrick // Force Sym to be entered in the output. Used for -u or equivalent.
handleUndefined(StringRef name,const char * option)641*dfe94b16Srobert static Symbol *handleUndefined(StringRef name, const char *option) {
642ece8a530Spatrick   Symbol *sym = symtab->find(name);
643ece8a530Spatrick   if (!sym)
644ece8a530Spatrick     return nullptr;
645ece8a530Spatrick 
646ece8a530Spatrick   // Since symbol S may not be used inside the program, LTO may
647ece8a530Spatrick   // eliminate it. Mark the symbol as "used" to prevent it.
648ece8a530Spatrick   sym->isUsedInRegularObj = true;
649ece8a530Spatrick 
650*dfe94b16Srobert   if (auto *lazySym = dyn_cast<LazySymbol>(sym)) {
651ece8a530Spatrick     lazySym->fetch();
652*dfe94b16Srobert     if (!config->whyExtract.empty())
653*dfe94b16Srobert       config->whyExtractRecords.emplace_back(option, sym->getFile(), *sym);
654*dfe94b16Srobert   }
655ece8a530Spatrick 
656ece8a530Spatrick   return sym;
657ece8a530Spatrick }
658ece8a530Spatrick 
handleLibcall(StringRef name)659ece8a530Spatrick static void handleLibcall(StringRef name) {
660ece8a530Spatrick   Symbol *sym = symtab->find(name);
661ece8a530Spatrick   if (!sym)
662ece8a530Spatrick     return;
663ece8a530Spatrick 
664ece8a530Spatrick   if (auto *lazySym = dyn_cast<LazySymbol>(sym)) {
665ece8a530Spatrick     MemoryBufferRef mb = lazySym->getMemberBuffer();
666*dfe94b16Srobert     if (isBitcode(mb)) {
667*dfe94b16Srobert       if (!config->whyExtract.empty())
668*dfe94b16Srobert         config->whyExtractRecords.emplace_back("<libcall>", sym->getFile(),
669*dfe94b16Srobert                                                *sym);
670ece8a530Spatrick       lazySym->fetch();
671ece8a530Spatrick     }
672ece8a530Spatrick   }
673*dfe94b16Srobert }
674*dfe94b16Srobert 
writeWhyExtract()675*dfe94b16Srobert static void writeWhyExtract() {
676*dfe94b16Srobert   if (config->whyExtract.empty())
677*dfe94b16Srobert     return;
678*dfe94b16Srobert 
679*dfe94b16Srobert   std::error_code ec;
680*dfe94b16Srobert   raw_fd_ostream os(config->whyExtract, ec, sys::fs::OF_None);
681*dfe94b16Srobert   if (ec) {
682*dfe94b16Srobert     error("cannot open --why-extract= file " + config->whyExtract + ": " +
683*dfe94b16Srobert           ec.message());
684*dfe94b16Srobert     return;
685*dfe94b16Srobert   }
686*dfe94b16Srobert 
687*dfe94b16Srobert   os << "reference\textracted\tsymbol\n";
688*dfe94b16Srobert   for (auto &entry : config->whyExtractRecords) {
689*dfe94b16Srobert     os << std::get<0>(entry) << '\t' << toString(std::get<1>(entry)) << '\t'
690*dfe94b16Srobert        << toString(std::get<2>(entry)) << '\n';
691*dfe94b16Srobert   }
692*dfe94b16Srobert }
693*dfe94b16Srobert 
694*dfe94b16Srobert // Equivalent of demote demoteSharedAndLazySymbols() in the ELF linker
demoteLazySymbols()695*dfe94b16Srobert static void demoteLazySymbols() {
696*dfe94b16Srobert   for (Symbol *sym : symtab->symbols()) {
697*dfe94b16Srobert     if (auto* s = dyn_cast<LazySymbol>(sym)) {
698*dfe94b16Srobert       if (s->signature) {
699*dfe94b16Srobert         LLVM_DEBUG(llvm::dbgs()
700*dfe94b16Srobert                    << "demoting lazy func: " << s->getName() << "\n");
701*dfe94b16Srobert         replaceSymbol<UndefinedFunction>(s, s->getName(), std::nullopt,
702*dfe94b16Srobert                                          std::nullopt, WASM_SYMBOL_BINDING_WEAK,
703*dfe94b16Srobert                                          s->getFile(), s->signature);
704*dfe94b16Srobert       }
705*dfe94b16Srobert     }
706*dfe94b16Srobert   }
707*dfe94b16Srobert }
708ece8a530Spatrick 
709ece8a530Spatrick static UndefinedGlobal *
createUndefinedGlobal(StringRef name,llvm::wasm::WasmGlobalType * type)710ece8a530Spatrick createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
711ece8a530Spatrick   auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(
712*dfe94b16Srobert       name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, type));
713ece8a530Spatrick   config->allowUndefinedSymbols.insert(sym->getName());
714ece8a530Spatrick   sym->isUsedInRegularObj = true;
715ece8a530Spatrick   return sym;
716ece8a530Spatrick }
717ece8a530Spatrick 
createGlobal(StringRef name,bool isMutable)7181cf9926bSpatrick static InputGlobal *createGlobal(StringRef name, bool isMutable) {
719ece8a530Spatrick   llvm::wasm::WasmGlobal wasmGlobal;
720*dfe94b16Srobert   bool is64 = config->is64.value_or(false);
7211cf9926bSpatrick   wasmGlobal.Type = {uint8_t(is64 ? WASM_TYPE_I64 : WASM_TYPE_I32), isMutable};
7221cf9926bSpatrick   wasmGlobal.InitExpr = intConst(0, is64);
723ece8a530Spatrick   wasmGlobal.SymbolName = name;
7241cf9926bSpatrick   return make<InputGlobal>(wasmGlobal, nullptr);
7251cf9926bSpatrick }
7261cf9926bSpatrick 
createGlobalVariable(StringRef name,bool isMutable)7271cf9926bSpatrick static GlobalSymbol *createGlobalVariable(StringRef name, bool isMutable) {
7281cf9926bSpatrick   InputGlobal *g = createGlobal(name, isMutable);
7291cf9926bSpatrick   return symtab->addSyntheticGlobal(name, WASM_SYMBOL_VISIBILITY_HIDDEN, g);
7301cf9926bSpatrick }
7311cf9926bSpatrick 
createOptionalGlobal(StringRef name,bool isMutable)7321cf9926bSpatrick static GlobalSymbol *createOptionalGlobal(StringRef name, bool isMutable) {
7331cf9926bSpatrick   InputGlobal *g = createGlobal(name, isMutable);
7341cf9926bSpatrick   return symtab->addOptionalGlobalSymbol(name, g);
735ece8a530Spatrick }
736ece8a530Spatrick 
737ece8a530Spatrick // Create ABI-defined synthetic symbols
createSyntheticSymbols()738ece8a530Spatrick static void createSyntheticSymbols() {
739ece8a530Spatrick   if (config->relocatable)
740ece8a530Spatrick     return;
741ece8a530Spatrick 
742ece8a530Spatrick   static WasmSignature nullSignature = {{}, {}};
743ece8a530Spatrick   static WasmSignature i32ArgSignature = {{}, {ValType::I32}};
744bb684c34Spatrick   static WasmSignature i64ArgSignature = {{}, {ValType::I64}};
745ece8a530Spatrick   static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false};
746bb684c34Spatrick   static llvm::wasm::WasmGlobalType globalTypeI64 = {WASM_TYPE_I64, false};
747ece8a530Spatrick   static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32,
748ece8a530Spatrick                                                             true};
749bb684c34Spatrick   static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,
750bb684c34Spatrick                                                             true};
751ece8a530Spatrick   WasmSym::callCtors = symtab->addSyntheticFunction(
752ece8a530Spatrick       "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
753ece8a530Spatrick       make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
754ece8a530Spatrick 
755*dfe94b16Srobert   bool is64 = config->is64.value_or(false);
756ece8a530Spatrick 
757ece8a530Spatrick   if (config->isPic) {
7581cf9926bSpatrick     WasmSym::stackPointer =
759*dfe94b16Srobert         createUndefinedGlobal("__stack_pointer", config->is64.value_or(false)
7601cf9926bSpatrick                                                      ? &mutableGlobalTypeI64
7611cf9926bSpatrick                                                      : &mutableGlobalTypeI32);
762ece8a530Spatrick     // For PIC code, we import two global variables (__memory_base and
763ece8a530Spatrick     // __table_base) from the environment and use these as the offset at
764ece8a530Spatrick     // which to load our static data and function table.
765ece8a530Spatrick     // See:
766*dfe94b16Srobert     // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
7671cf9926bSpatrick     auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
7681cf9926bSpatrick     WasmSym::memoryBase = createUndefinedGlobal("__memory_base", globalType);
7691cf9926bSpatrick     WasmSym::tableBase = createUndefinedGlobal("__table_base", globalType);
770ece8a530Spatrick     WasmSym::memoryBase->markLive();
771ece8a530Spatrick     WasmSym::tableBase->markLive();
7721cf9926bSpatrick     if (is64) {
7731cf9926bSpatrick       WasmSym::tableBase32 =
7741cf9926bSpatrick           createUndefinedGlobal("__table_base32", &globalTypeI32);
7751cf9926bSpatrick       WasmSym::tableBase32->markLive();
7761cf9926bSpatrick     } else {
7771cf9926bSpatrick       WasmSym::tableBase32 = nullptr;
7781cf9926bSpatrick     }
779ece8a530Spatrick   } else {
780ece8a530Spatrick     // For non-PIC code
7811cf9926bSpatrick     WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true);
782ece8a530Spatrick     WasmSym::stackPointer->markLive();
783ece8a530Spatrick   }
784ece8a530Spatrick 
785*dfe94b16Srobert   if (config->sharedMemory) {
7861cf9926bSpatrick     WasmSym::tlsBase = createGlobalVariable("__tls_base", true);
7871cf9926bSpatrick     WasmSym::tlsSize = createGlobalVariable("__tls_size", false);
7881cf9926bSpatrick     WasmSym::tlsAlign = createGlobalVariable("__tls_align", false);
789ece8a530Spatrick     WasmSym::initTLS = symtab->addSyntheticFunction(
790ece8a530Spatrick         "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
7911cf9926bSpatrick         make<SyntheticFunction>(
7921cf9926bSpatrick             is64 ? i64ArgSignature : i32ArgSignature,
793bb684c34Spatrick             "__wasm_init_tls"));
794ece8a530Spatrick   }
795*dfe94b16Srobert 
796*dfe94b16Srobert   if (config->isPic ||
797*dfe94b16Srobert       config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {
798*dfe94b16Srobert     // For PIC code, or when dynamically importing addresses, we create
799*dfe94b16Srobert     // synthetic functions that apply relocations.  These get called from
800*dfe94b16Srobert     // __wasm_call_ctors before the user-level constructors.
801*dfe94b16Srobert     WasmSym::applyDataRelocs = symtab->addSyntheticFunction(
802*dfe94b16Srobert         "__wasm_apply_data_relocs",
803*dfe94b16Srobert         WASM_SYMBOL_VISIBILITY_DEFAULT | WASM_SYMBOL_EXPORTED,
804*dfe94b16Srobert         make<SyntheticFunction>(nullSignature, "__wasm_apply_data_relocs"));
805*dfe94b16Srobert   }
806ece8a530Spatrick }
807ece8a530Spatrick 
createOptionalSymbols()808ece8a530Spatrick static void createOptionalSymbols() {
809ece8a530Spatrick   if (config->relocatable)
810ece8a530Spatrick     return;
811ece8a530Spatrick 
812ece8a530Spatrick   WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
813ece8a530Spatrick 
814ece8a530Spatrick   if (!config->shared)
815ece8a530Spatrick     WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
816ece8a530Spatrick 
817ece8a530Spatrick   if (!config->isPic) {
818*dfe94b16Srobert     WasmSym::stackLow = symtab->addOptionalDataSymbol("__stack_low");
819*dfe94b16Srobert     WasmSym::stackHigh = symtab->addOptionalDataSymbol("__stack_high");
820ece8a530Spatrick     WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base");
821ece8a530Spatrick     WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
822*dfe94b16Srobert     WasmSym::heapEnd = symtab->addOptionalDataSymbol("__heap_end");
823ece8a530Spatrick     WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
824ece8a530Spatrick     WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base");
825*dfe94b16Srobert     if (config->is64.value_or(false))
8261cf9926bSpatrick       WasmSym::definedTableBase32 =
8271cf9926bSpatrick           symtab->addOptionalDataSymbol("__table_base32");
828ece8a530Spatrick   }
8291cf9926bSpatrick 
8301cf9926bSpatrick   // For non-shared memory programs we still need to define __tls_base since we
8311cf9926bSpatrick   // allow object files built with TLS to be linked into single threaded
832*dfe94b16Srobert   // programs, and such object files can contain references to this symbol.
8331cf9926bSpatrick   //
8341cf9926bSpatrick   // However, in this case __tls_base is immutable and points directly to the
8351cf9926bSpatrick   // start of the `.tdata` static segment.
8361cf9926bSpatrick   //
8371cf9926bSpatrick   // __tls_size and __tls_align are not needed in this case since they are only
8381cf9926bSpatrick   // needed for __wasm_init_tls (which we do not create in this case).
8391cf9926bSpatrick   if (!config->sharedMemory)
8401cf9926bSpatrick     WasmSym::tlsBase = createOptionalGlobal("__tls_base", false);
841ece8a530Spatrick }
842ece8a530Spatrick 
processStubLibraries()843*dfe94b16Srobert static void processStubLibraries() {
844*dfe94b16Srobert   log("-- processStubLibraries");
845*dfe94b16Srobert   for (auto &stub_file : symtab->stubFiles) {
846*dfe94b16Srobert     LLVM_DEBUG(llvm::dbgs()
847*dfe94b16Srobert                << "processing stub file: " << stub_file->getName() << "\n");
848*dfe94b16Srobert     for (auto [name, deps]: stub_file->symbolDependencies) {
849*dfe94b16Srobert       auto* sym = symtab->find(name);
850*dfe94b16Srobert       if (!sym || !sym->isUndefined() || !sym->isUsedInRegularObj ||
851*dfe94b16Srobert           sym->forceImport) {
852*dfe94b16Srobert         LLVM_DEBUG(llvm::dbgs() << "stub not in needed: " << name << "\n");
853*dfe94b16Srobert         continue;
854*dfe94b16Srobert       }
855*dfe94b16Srobert       // The first stub library to define a given symbol sets this and
856*dfe94b16Srobert       // definitions in later stub libraries are ignored.
857*dfe94b16Srobert       sym->forceImport = true;
858*dfe94b16Srobert       if (sym->traced)
859*dfe94b16Srobert         message(toString(stub_file) + ": importing " + name);
860*dfe94b16Srobert       else
861*dfe94b16Srobert         LLVM_DEBUG(llvm::dbgs()
862*dfe94b16Srobert                    << toString(stub_file) << ": importing " << name << "\n");
863*dfe94b16Srobert       for (const auto dep : deps) {
864*dfe94b16Srobert         auto* needed = symtab->find(dep);
865*dfe94b16Srobert         if (!needed) {
866*dfe94b16Srobert           error(toString(stub_file) + ": undefined symbol: " + dep +
867*dfe94b16Srobert                 ". Required by " + toString(*sym));
868*dfe94b16Srobert         } else if (needed->isUndefined()) {
869*dfe94b16Srobert           error(toString(stub_file) +
870*dfe94b16Srobert                 ": undefined symbol: " + toString(*needed) +
871*dfe94b16Srobert                 ". Required by " + toString(*sym));
872*dfe94b16Srobert         } else {
873*dfe94b16Srobert           LLVM_DEBUG(llvm::dbgs()
874*dfe94b16Srobert                      << "force export: " << toString(*needed) << "\n");
875*dfe94b16Srobert           needed->forceExport = true;
876*dfe94b16Srobert           needed->isUsedInRegularObj = true;
877*dfe94b16Srobert           if (auto *lazy = dyn_cast<LazySymbol>(needed)) {
878*dfe94b16Srobert             lazy->fetch();
879*dfe94b16Srobert             if (!config->whyExtract.empty())
880*dfe94b16Srobert               config->whyExtractRecords.emplace_back(stub_file->getName(),
881*dfe94b16Srobert                                                      sym->getFile(), *sym);
882*dfe94b16Srobert           }
883*dfe94b16Srobert         }
884*dfe94b16Srobert       }
885*dfe94b16Srobert     }
886*dfe94b16Srobert   }
887*dfe94b16Srobert   log("-- done processStubLibraries");
888*dfe94b16Srobert }
889*dfe94b16Srobert 
890ece8a530Spatrick // Reconstructs command line arguments so that so that you can re-run
891ece8a530Spatrick // the same command with the same inputs. This is for --reproduce.
createResponseFile(const opt::InputArgList & args)892ece8a530Spatrick static std::string createResponseFile(const opt::InputArgList &args) {
893ece8a530Spatrick   SmallString<0> data;
894ece8a530Spatrick   raw_svector_ostream os(data);
895ece8a530Spatrick 
896ece8a530Spatrick   // Copy the command line to the output while rewriting paths.
897ece8a530Spatrick   for (auto *arg : args) {
898ece8a530Spatrick     switch (arg->getOption().getID()) {
899ece8a530Spatrick     case OPT_reproduce:
900ece8a530Spatrick       break;
901ece8a530Spatrick     case OPT_INPUT:
902ece8a530Spatrick       os << quote(relativeToRoot(arg->getValue())) << "\n";
903ece8a530Spatrick       break;
904ece8a530Spatrick     case OPT_o:
905ece8a530Spatrick       // If -o path contains directories, "lld @response.txt" will likely
906ece8a530Spatrick       // fail because the archive we are creating doesn't contain empty
907ece8a530Spatrick       // directories for the output path (-o doesn't create directories).
908ece8a530Spatrick       // Strip directories to prevent the issue.
909ece8a530Spatrick       os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n";
910ece8a530Spatrick       break;
911ece8a530Spatrick     default:
912ece8a530Spatrick       os << toString(*arg) << "\n";
913ece8a530Spatrick     }
914ece8a530Spatrick   }
915bb684c34Spatrick   return std::string(data.str());
916ece8a530Spatrick }
917ece8a530Spatrick 
918ece8a530Spatrick // The --wrap option is a feature to rename symbols so that you can write
919ece8a530Spatrick // wrappers for existing functions. If you pass `-wrap=foo`, all
920ece8a530Spatrick // occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
921ece8a530Spatrick // expected to write `wrap_foo` function as a wrapper). The original
922ece8a530Spatrick // symbol becomes accessible as `real_foo`, so you can call that from your
923ece8a530Spatrick // wrapper.
924ece8a530Spatrick //
925ece8a530Spatrick // This data structure is instantiated for each -wrap option.
926ece8a530Spatrick struct WrappedSymbol {
927ece8a530Spatrick   Symbol *sym;
928ece8a530Spatrick   Symbol *real;
929ece8a530Spatrick   Symbol *wrap;
930ece8a530Spatrick };
931ece8a530Spatrick 
addUndefined(StringRef name)932ece8a530Spatrick static Symbol *addUndefined(StringRef name) {
933*dfe94b16Srobert   return symtab->addUndefinedFunction(name, std::nullopt, std::nullopt,
934*dfe94b16Srobert                                       WASM_SYMBOL_UNDEFINED, nullptr, nullptr,
935*dfe94b16Srobert                                       false);
936ece8a530Spatrick }
937ece8a530Spatrick 
938ece8a530Spatrick // Handles -wrap option.
939ece8a530Spatrick //
940ece8a530Spatrick // This function instantiates wrapper symbols. At this point, they seem
941ece8a530Spatrick // like they are not being used at all, so we explicitly set some flags so
942ece8a530Spatrick // that LTO won't eliminate them.
addWrappedSymbols(opt::InputArgList & args)943ece8a530Spatrick static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
944ece8a530Spatrick   std::vector<WrappedSymbol> v;
945ece8a530Spatrick   DenseSet<StringRef> seen;
946ece8a530Spatrick 
947ece8a530Spatrick   for (auto *arg : args.filtered(OPT_wrap)) {
948ece8a530Spatrick     StringRef name = arg->getValue();
949ece8a530Spatrick     if (!seen.insert(name).second)
950ece8a530Spatrick       continue;
951ece8a530Spatrick 
952ece8a530Spatrick     Symbol *sym = symtab->find(name);
953ece8a530Spatrick     if (!sym)
954ece8a530Spatrick       continue;
955ece8a530Spatrick 
956*dfe94b16Srobert     Symbol *real = addUndefined(saver().save("__real_" + name));
957*dfe94b16Srobert     Symbol *wrap = addUndefined(saver().save("__wrap_" + name));
958ece8a530Spatrick     v.push_back({sym, real, wrap});
959ece8a530Spatrick 
960ece8a530Spatrick     // We want to tell LTO not to inline symbols to be overwritten
961ece8a530Spatrick     // because LTO doesn't know the final symbol contents after renaming.
962ece8a530Spatrick     real->canInline = false;
963ece8a530Spatrick     sym->canInline = false;
964ece8a530Spatrick 
965ece8a530Spatrick     // Tell LTO not to eliminate these symbols.
966ece8a530Spatrick     sym->isUsedInRegularObj = true;
967ece8a530Spatrick     wrap->isUsedInRegularObj = true;
968ece8a530Spatrick     real->isUsedInRegularObj = false;
969ece8a530Spatrick   }
970ece8a530Spatrick   return v;
971ece8a530Spatrick }
972ece8a530Spatrick 
973ece8a530Spatrick // Do renaming for -wrap by updating pointers to symbols.
974ece8a530Spatrick //
975ece8a530Spatrick // When this function is executed, only InputFiles and symbol table
976ece8a530Spatrick // contain pointers to symbol objects. We visit them to replace pointers,
977ece8a530Spatrick // so that wrapped symbols are swapped as instructed by the command line.
wrapSymbols(ArrayRef<WrappedSymbol> wrapped)978ece8a530Spatrick static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
979ece8a530Spatrick   DenseMap<Symbol *, Symbol *> map;
980ece8a530Spatrick   for (const WrappedSymbol &w : wrapped) {
981ece8a530Spatrick     map[w.sym] = w.wrap;
982ece8a530Spatrick     map[w.real] = w.sym;
983ece8a530Spatrick   }
984ece8a530Spatrick 
985ece8a530Spatrick   // Update pointers in input files.
986ece8a530Spatrick   parallelForEach(symtab->objectFiles, [&](InputFile *file) {
987ece8a530Spatrick     MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
988ece8a530Spatrick     for (size_t i = 0, e = syms.size(); i != e; ++i)
989ece8a530Spatrick       if (Symbol *s = map.lookup(syms[i]))
990ece8a530Spatrick         syms[i] = s;
991ece8a530Spatrick   });
992ece8a530Spatrick 
993ece8a530Spatrick   // Update pointers in the symbol table.
994ece8a530Spatrick   for (const WrappedSymbol &w : wrapped)
995ece8a530Spatrick     symtab->wrap(w.sym, w.real, w.wrap);
996ece8a530Spatrick }
997ece8a530Spatrick 
splitSections()9981cf9926bSpatrick static void splitSections() {
9991cf9926bSpatrick   // splitIntoPieces needs to be called on each MergeInputChunk
10001cf9926bSpatrick   // before calling finalizeContents().
10011cf9926bSpatrick   LLVM_DEBUG(llvm::dbgs() << "splitSections\n");
10021cf9926bSpatrick   parallelForEach(symtab->objectFiles, [](ObjFile *file) {
10031cf9926bSpatrick     for (InputChunk *seg : file->segments) {
10041cf9926bSpatrick       if (auto *s = dyn_cast<MergeInputChunk>(seg))
10051cf9926bSpatrick         s->splitIntoPieces();
10061cf9926bSpatrick     }
10071cf9926bSpatrick     for (InputChunk *sec : file->customSections) {
10081cf9926bSpatrick       if (auto *s = dyn_cast<MergeInputChunk>(sec))
10091cf9926bSpatrick         s->splitIntoPieces();
10101cf9926bSpatrick     }
10111cf9926bSpatrick   });
10121cf9926bSpatrick }
10131cf9926bSpatrick 
isKnownZFlag(StringRef s)1014*dfe94b16Srobert static bool isKnownZFlag(StringRef s) {
1015*dfe94b16Srobert   // For now, we only support a very limited set of -z flags
1016*dfe94b16Srobert   return s.startswith("stack-size=");
1017*dfe94b16Srobert }
1018*dfe94b16Srobert 
1019*dfe94b16Srobert // Report a warning for an unknown -z option.
checkZOptions(opt::InputArgList & args)1020*dfe94b16Srobert static void checkZOptions(opt::InputArgList &args) {
1021*dfe94b16Srobert   for (auto *arg : args.filtered(OPT_z))
1022*dfe94b16Srobert     if (!isKnownZFlag(arg->getValue()))
1023*dfe94b16Srobert       warn("unknown -z value: " + StringRef(arg->getValue()));
1024*dfe94b16Srobert }
1025*dfe94b16Srobert 
linkerMain(ArrayRef<const char * > argsArr)10261cf9926bSpatrick void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
1027ece8a530Spatrick   WasmOptTable parser;
1028ece8a530Spatrick   opt::InputArgList args = parser.parse(argsArr.slice(1));
1029ece8a530Spatrick 
1030*dfe94b16Srobert   // Interpret these flags early because error()/warn() depend on them.
1031*dfe94b16Srobert   errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20);
1032*dfe94b16Srobert   errorHandler().fatalWarnings =
1033*dfe94b16Srobert       args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
1034*dfe94b16Srobert   checkZOptions(args);
1035*dfe94b16Srobert 
1036ece8a530Spatrick   // Handle --help
1037ece8a530Spatrick   if (args.hasArg(OPT_help)) {
10381cf9926bSpatrick     parser.printHelp(lld::outs(),
1039ece8a530Spatrick                      (std::string(argsArr[0]) + " [options] file...").c_str(),
1040ece8a530Spatrick                      "LLVM Linker", false);
1041ece8a530Spatrick     return;
1042ece8a530Spatrick   }
1043ece8a530Spatrick 
1044ece8a530Spatrick   // Handle --version
1045ece8a530Spatrick   if (args.hasArg(OPT_version) || args.hasArg(OPT_v)) {
1046ece8a530Spatrick     lld::outs() << getLLDVersion() << "\n";
1047ece8a530Spatrick     return;
1048ece8a530Spatrick   }
1049ece8a530Spatrick 
1050ece8a530Spatrick   // Handle --reproduce
1051*dfe94b16Srobert   if (const char *path = getReproduceOption(args)) {
1052ece8a530Spatrick     Expected<std::unique_ptr<TarWriter>> errOrWriter =
1053ece8a530Spatrick         TarWriter::create(path, path::stem(path));
1054ece8a530Spatrick     if (errOrWriter) {
1055ece8a530Spatrick       tar = std::move(*errOrWriter);
1056ece8a530Spatrick       tar->append("response.txt", createResponseFile(args));
1057ece8a530Spatrick       tar->append("version.txt", getLLDVersion() + "\n");
1058ece8a530Spatrick     } else {
1059ece8a530Spatrick       error("--reproduce: " + toString(errOrWriter.takeError()));
1060ece8a530Spatrick     }
1061ece8a530Spatrick   }
1062ece8a530Spatrick 
1063ece8a530Spatrick   // Parse and evaluate -mllvm options.
1064ece8a530Spatrick   std::vector<const char *> v;
1065ece8a530Spatrick   v.push_back("wasm-ld (LLVM option parsing)");
1066ece8a530Spatrick   for (auto *arg : args.filtered(OPT_mllvm))
1067ece8a530Spatrick     v.push_back(arg->getValue());
10681cf9926bSpatrick   cl::ResetAllOptionOccurrences();
1069ece8a530Spatrick   cl::ParseCommandLineOptions(v.size(), v.data());
1070ece8a530Spatrick 
1071ece8a530Spatrick   readConfigs(args);
1072*dfe94b16Srobert   setConfigs();
1073bb684c34Spatrick 
1074bb684c34Spatrick   createFiles(args);
1075bb684c34Spatrick   if (errorCount())
1076bb684c34Spatrick     return;
1077bb684c34Spatrick 
1078ece8a530Spatrick   checkOptions(args);
1079bb684c34Spatrick   if (errorCount())
1080bb684c34Spatrick     return;
1081ece8a530Spatrick 
1082ece8a530Spatrick   if (auto *arg = args.getLastArg(OPT_allow_undefined_file))
1083ece8a530Spatrick     readImportFile(arg->getValue());
1084ece8a530Spatrick 
1085bb684c34Spatrick   // Fail early if the output file or map file is not writable. If a user has a
1086bb684c34Spatrick   // long link, e.g. due to a large LTO link, they do not wish to run it and
1087bb684c34Spatrick   // find that it failed because there was a mistake in their command-line.
1088bb684c34Spatrick   if (auto e = tryCreateFile(config->outputFile))
1089bb684c34Spatrick     error("cannot open output file " + config->outputFile + ": " + e.message());
10901cf9926bSpatrick   if (auto e = tryCreateFile(config->mapFile))
10911cf9926bSpatrick     error("cannot open map file " + config->mapFile + ": " + e.message());
1092bb684c34Spatrick   if (errorCount())
1093ece8a530Spatrick     return;
1094ece8a530Spatrick 
1095ece8a530Spatrick   // Handle --trace-symbol.
1096ece8a530Spatrick   for (auto *arg : args.filtered(OPT_trace_symbol))
1097ece8a530Spatrick     symtab->trace(arg->getValue());
1098ece8a530Spatrick 
10991cf9926bSpatrick   for (auto *arg : args.filtered(OPT_export_if_defined))
1100ece8a530Spatrick     config->exportedSymbols.insert(arg->getValue());
1101ece8a530Spatrick 
11021cf9926bSpatrick   for (auto *arg : args.filtered(OPT_export)) {
11031cf9926bSpatrick     config->exportedSymbols.insert(arg->getValue());
11041cf9926bSpatrick     config->requiredExports.push_back(arg->getValue());
11051cf9926bSpatrick   }
11061cf9926bSpatrick 
1107ece8a530Spatrick   createSyntheticSymbols();
1108ece8a530Spatrick 
1109ece8a530Spatrick   // Add all files to the symbol table. This will add almost all
1110ece8a530Spatrick   // symbols that we need to the symbol table.
1111ece8a530Spatrick   for (InputFile *f : files)
1112ece8a530Spatrick     symtab->addFile(f);
1113ece8a530Spatrick   if (errorCount())
1114ece8a530Spatrick     return;
1115ece8a530Spatrick 
1116ece8a530Spatrick   // Handle the `--undefined <sym>` options.
1117ece8a530Spatrick   for (auto *arg : args.filtered(OPT_undefined))
1118*dfe94b16Srobert     handleUndefined(arg->getValue(), "<internal>");
1119ece8a530Spatrick 
1120ece8a530Spatrick   // Handle the `--export <sym>` options
1121ece8a530Spatrick   // This works like --undefined but also exports the symbol if its found
11221cf9926bSpatrick   for (auto &iter : config->exportedSymbols)
1123*dfe94b16Srobert     handleUndefined(iter.first(), "--export");
1124ece8a530Spatrick 
1125ece8a530Spatrick   Symbol *entrySym = nullptr;
1126ece8a530Spatrick   if (!config->relocatable && !config->entry.empty()) {
1127*dfe94b16Srobert     entrySym = handleUndefined(config->entry, "--entry");
1128ece8a530Spatrick     if (entrySym && entrySym->isDefined())
1129ece8a530Spatrick       entrySym->forceExport = true;
1130ece8a530Spatrick     else
1131bb684c34Spatrick       error("entry symbol not defined (pass --no-entry to suppress): " +
1132ece8a530Spatrick             config->entry);
1133ece8a530Spatrick   }
1134ece8a530Spatrick 
11351cf9926bSpatrick   // If the user code defines a `__wasm_call_dtors` function, remember it so
11361cf9926bSpatrick   // that we can call it from the command export wrappers. Unlike
11371cf9926bSpatrick   // `__wasm_call_ctors` which we synthesize, `__wasm_call_dtors` is defined
11381cf9926bSpatrick   // by libc/etc., because destructors are registered dynamically with
11391cf9926bSpatrick   // `__cxa_atexit` and friends.
11401cf9926bSpatrick   if (!config->relocatable && !config->shared &&
11411cf9926bSpatrick       !WasmSym::callCtors->isUsedInRegularObj &&
11421cf9926bSpatrick       WasmSym::callCtors->getName() != config->entry &&
11431cf9926bSpatrick       !config->exportedSymbols.count(WasmSym::callCtors->getName())) {
1144*dfe94b16Srobert     if (Symbol *callDtors =
1145*dfe94b16Srobert             handleUndefined("__wasm_call_dtors", "<internal>")) {
11461cf9926bSpatrick       if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {
11471cf9926bSpatrick         if (callDtorsFunc->signature &&
11481cf9926bSpatrick             (!callDtorsFunc->signature->Params.empty() ||
11491cf9926bSpatrick              !callDtorsFunc->signature->Returns.empty())) {
11501cf9926bSpatrick           error("__wasm_call_dtors must have no argument or return values");
11511cf9926bSpatrick         }
11521cf9926bSpatrick         WasmSym::callDtors = callDtorsFunc;
11531cf9926bSpatrick       } else {
11541cf9926bSpatrick         error("__wasm_call_dtors must be a function");
11551cf9926bSpatrick       }
11561cf9926bSpatrick     }
11571cf9926bSpatrick   }
11581cf9926bSpatrick 
1159ece8a530Spatrick   if (errorCount())
1160ece8a530Spatrick     return;
1161ece8a530Spatrick 
1162ece8a530Spatrick   // Create wrapped symbols for -wrap option.
1163ece8a530Spatrick   std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
1164ece8a530Spatrick 
1165ece8a530Spatrick   // If any of our inputs are bitcode files, the LTO code generator may create
1166ece8a530Spatrick   // references to certain library functions that might not be explicit in the
1167ece8a530Spatrick   // bitcode file's symbol table. If any of those library functions are defined
1168ece8a530Spatrick   // in a bitcode file in an archive member, we need to arrange to use LTO to
1169ece8a530Spatrick   // compile those archive members by adding them to the link beforehand.
1170ece8a530Spatrick   //
1171ece8a530Spatrick   // We only need to add libcall symbols to the link before LTO if the symbol's
1172ece8a530Spatrick   // definition is in bitcode. Any other required libcall symbols will be added
1173ece8a530Spatrick   // to the link after LTO when we add the LTO object file to the link.
1174ece8a530Spatrick   if (!symtab->bitcodeFiles.empty())
1175ece8a530Spatrick     for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
1176ece8a530Spatrick       handleLibcall(s);
1177ece8a530Spatrick   if (errorCount())
1178ece8a530Spatrick     return;
1179ece8a530Spatrick 
1180*dfe94b16Srobert   writeWhyExtract();
1181*dfe94b16Srobert 
1182ece8a530Spatrick   // Do link-time optimization if given files are LLVM bitcode files.
1183ece8a530Spatrick   // This compiles bitcode files into real object files.
1184*dfe94b16Srobert   symtab->compileBitcodeFiles();
1185ece8a530Spatrick   if (errorCount())
1186ece8a530Spatrick     return;
1187ece8a530Spatrick 
1188*dfe94b16Srobert   processStubLibraries();
1189*dfe94b16Srobert 
1190*dfe94b16Srobert   createOptionalSymbols();
1191*dfe94b16Srobert 
1192ece8a530Spatrick   // Resolve any variant symbols that were created due to signature
1193ece8a530Spatrick   // mismatchs.
1194ece8a530Spatrick   symtab->handleSymbolVariants();
1195ece8a530Spatrick   if (errorCount())
1196ece8a530Spatrick     return;
1197ece8a530Spatrick 
1198ece8a530Spatrick   // Apply symbol renames for -wrap.
1199ece8a530Spatrick   if (!wrapped.empty())
1200ece8a530Spatrick     wrapSymbols(wrapped);
1201ece8a530Spatrick 
12021cf9926bSpatrick   for (auto &iter : config->exportedSymbols) {
12031cf9926bSpatrick     Symbol *sym = symtab->find(iter.first());
1204ece8a530Spatrick     if (sym && sym->isDefined())
1205ece8a530Spatrick       sym->forceExport = true;
1206ece8a530Spatrick   }
1207ece8a530Spatrick 
12081cf9926bSpatrick   if (!config->relocatable && !config->isPic) {
1209ece8a530Spatrick     // Add synthetic dummies for weak undefined functions.  Must happen
1210ece8a530Spatrick     // after LTO otherwise functions may not yet have signatures.
1211ece8a530Spatrick     symtab->handleWeakUndefines();
1212ece8a530Spatrick   }
1213ece8a530Spatrick 
1214ece8a530Spatrick   if (entrySym)
1215ece8a530Spatrick     entrySym->setHidden(false);
1216ece8a530Spatrick 
1217ece8a530Spatrick   if (errorCount())
1218ece8a530Spatrick     return;
1219ece8a530Spatrick 
12201cf9926bSpatrick   // Split WASM_SEG_FLAG_STRINGS sections into pieces in preparation for garbage
12211cf9926bSpatrick   // collection.
12221cf9926bSpatrick   splitSections();
12231cf9926bSpatrick 
1224*dfe94b16Srobert   // Any remaining lazy symbols should be demoted to Undefined
1225*dfe94b16Srobert   demoteLazySymbols();
1226*dfe94b16Srobert 
1227ece8a530Spatrick   // Do size optimizations: garbage collection
1228ece8a530Spatrick   markLive();
1229ece8a530Spatrick 
12301cf9926bSpatrick   // Provide the indirect function table if needed.
12311cf9926bSpatrick   WasmSym::indirectFunctionTable =
12321cf9926bSpatrick       symtab->resolveIndirectFunctionTable(/*required =*/false);
12331cf9926bSpatrick 
12341cf9926bSpatrick   if (errorCount())
12351cf9926bSpatrick     return;
12361cf9926bSpatrick 
1237ece8a530Spatrick   // Write the result to the file.
1238ece8a530Spatrick   writeResult();
1239ece8a530Spatrick }
1240ece8a530Spatrick 
1241ece8a530Spatrick } // namespace wasm
1242ece8a530Spatrick } // namespace lld
1243