xref: /llvm-project/lld/wasm/Driver.cpp (revision 3792b36234b6c87d728f0a905543e284bf961460)
1c94d393aSSam Clegg //===- Driver.cpp ---------------------------------------------------------===//
2c94d393aSSam Clegg //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c94d393aSSam Clegg //
7c94d393aSSam Clegg //===----------------------------------------------------------------------===//
8c94d393aSSam Clegg 
9c94d393aSSam Clegg #include "lld/Common/Driver.h"
1078f766a9SSam Clegg #include "Config.h"
11ebda41f8SNicholas Wilson #include "InputChunks.h"
12a56e5749SAndy Wingo #include "InputElement.h"
130362633fSSam Clegg #include "MarkLive.h"
14c94d393aSSam Clegg #include "SymbolTable.h"
15c94d393aSSam Clegg #include "Writer.h"
163e03944fSRui Ueyama #include "lld/Common/Args.h"
176b9a80deSFangrui Song #include "lld/Common/CommonLinkerContext.h"
18c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h"
19b5767010SSam Clegg #include "lld/Common/Filesystem.h"
202017d52bSRui Ueyama #include "lld/Common/Memory.h"
2135150bb5SRui Ueyama #include "lld/Common/Reproduce.h"
22531769b9SNicholas Wilson #include "lld/Common/Strings.h"
23c94d393aSSam Clegg #include "lld/Common/Version.h"
24c94d393aSSam Clegg #include "llvm/ADT/Twine.h"
25e8140139SArthur Eubanks #include "llvm/Config/llvm-config.h"
26c94d393aSSam Clegg #include "llvm/Object/Wasm.h"
2782de51a3SThomas Lively #include "llvm/Option/Arg.h"
28c94d393aSSam Clegg #include "llvm/Option/ArgList.h"
29c94d393aSSam Clegg #include "llvm/Support/CommandLine.h"
30932f0276SReid Kleckner #include "llvm/Support/Parallel.h"
31c94d393aSSam Clegg #include "llvm/Support/Path.h"
32c94d393aSSam Clegg #include "llvm/Support/Process.h"
3335150bb5SRui Ueyama #include "llvm/Support/TarWriter.h"
34c729c1b4SSam Clegg #include "llvm/Support/TargetSelect.h"
35d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h"
36b9ef5648SKazu Hirata #include <optional>
37c94d393aSSam Clegg 
380362633fSSam Clegg #define DEBUG_TYPE "lld"
390362633fSSam Clegg 
40c94d393aSSam Clegg using namespace llvm;
4145218f4aSSam Clegg using namespace llvm::object;
42dcb6d212SJustin Bogner using namespace llvm::opt;
43c94d393aSSam Clegg using namespace llvm::sys;
44c94d393aSSam Clegg using namespace llvm::wasm;
45c94d393aSSam Clegg 
46d32f71a9SSam Clegg namespace lld::wasm {
47184c22ddSSam Clegg Ctx ctx;
48c94d393aSSam Clegg 
490367305aSmzukovec void errorOrWarn(const llvm::Twine &msg) {
50*3792b362SFangrui Song   if (ctx.arg.noinhibitExec)
510367305aSmzukovec     warn(msg);
520367305aSmzukovec   else
530367305aSmzukovec     error(msg);
540367305aSmzukovec }
550367305aSmzukovec 
56*3792b362SFangrui Song Ctx::Ctx() {}
57a222d00cSFangrui Song 
582bfa5ca9SSam Clegg void Ctx::reset() {
59a222d00cSFangrui Song   arg.~Config();
60a222d00cSFangrui Song   new (&arg) Config();
612bfa5ca9SSam Clegg   objectFiles.clear();
622bfa5ca9SSam Clegg   stubFiles.clear();
632bfa5ca9SSam Clegg   sharedFiles.clear();
642bfa5ca9SSam Clegg   bitcodeFiles.clear();
6552aff97fSAnutosh Bhat   lazyBitcodeFiles.clear();
662bfa5ca9SSam Clegg   syntheticFunctions.clear();
672bfa5ca9SSam Clegg   syntheticGlobals.clear();
682bfa5ca9SSam Clegg   syntheticTables.clear();
692bfa5ca9SSam Clegg   whyExtractRecords.clear();
702bfa5ca9SSam Clegg   isPic = false;
712bfa5ca9SSam Clegg   legacyFunctionTable = false;
722bfa5ca9SSam Clegg   emitBssSegments = false;
732bfa5ca9SSam Clegg }
742bfa5ca9SSam Clegg 
7539049c05SRui Ueyama namespace {
76c94d393aSSam Clegg 
77c94d393aSSam Clegg // Create enum with OPT_xxx values for each option in Options.td
78c94d393aSSam Clegg enum {
79c94d393aSSam Clegg   OPT_INVALID = 0,
803f092f37SJan Svoboda #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
81c94d393aSSam Clegg #include "Options.inc"
82c94d393aSSam Clegg #undef OPTION
83c94d393aSSam Clegg };
84c94d393aSSam Clegg 
85c729c1b4SSam Clegg // This function is called on startup. We need this for LTO since
86c729c1b4SSam Clegg // LTO calls LLVM functions to compile bitcode files to native code.
87c729c1b4SSam Clegg // Technically this can be delayed until we read bitcode files, but
88c729c1b4SSam Clegg // we don't bother to do lazily because the initialization is fast.
89c729c1b4SSam Clegg static void initLLVM() {
90c729c1b4SSam Clegg   InitializeAllTargets();
91c729c1b4SSam Clegg   InitializeAllTargetMCs();
92c729c1b4SSam Clegg   InitializeAllAsmPrinters();
93c729c1b4SSam Clegg   InitializeAllAsmParsers();
94c729c1b4SSam Clegg }
95c729c1b4SSam Clegg 
96c94d393aSSam Clegg class LinkerDriver {
97c94d393aSSam Clegg public:
98a222d00cSFangrui Song   LinkerDriver(Ctx &);
99fdd6ed8eSReshabh Sharma   void linkerMain(ArrayRef<const char *> argsArr);
100c94d393aSSam Clegg 
101c94d393aSSam Clegg private:
102136d27abSRui Ueyama   void createFiles(opt::InputArgList &args);
103136d27abSRui Ueyama   void addFile(StringRef path);
104136d27abSRui Ueyama   void addLibrary(StringRef name);
1058adf7ac5SSam Clegg 
106a222d00cSFangrui Song   Ctx &ctx;
107a222d00cSFangrui Song 
1088adf7ac5SSam Clegg   // True if we are in --whole-archive and --no-whole-archive.
109136d27abSRui Ueyama   bool inWholeArchive = false;
1108adf7ac5SSam Clegg 
11119261390SSam Clegg   // True if we are in --start-lib and --end-lib.
11219261390SSam Clegg   bool inLib = false;
11319261390SSam Clegg 
114136d27abSRui Ueyama   std::vector<InputFile *> files;
115c94d393aSSam Clegg };
1160367305aSmzukovec 
1170367305aSmzukovec static bool hasZOption(opt::InputArgList &args, StringRef key) {
1180367305aSmzukovec   bool ret = false;
1190367305aSmzukovec   for (const auto *arg : args.filtered(OPT_z))
1200367305aSmzukovec     if (key == arg->getValue()) {
1210367305aSmzukovec       ret = true;
1220367305aSmzukovec       arg->claim();
1230367305aSmzukovec     }
1240367305aSmzukovec   return ret;
1250367305aSmzukovec }
126c94d393aSSam Clegg } // anonymous namespace
127c94d393aSSam Clegg 
12883d59e05SAlexandre Ganea bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
12983d59e05SAlexandre Ganea           llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
1306f2e92c1SAlexandre Ganea   // This driver-specific context will be freed later by unsafeLldMain().
131a222d00cSFangrui Song   auto *context = new CommonLinkerContext;
132d3fec7fbSJames Y Knight 
133a222d00cSFangrui Song   context->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
134a222d00cSFangrui Song   context->e.cleanupCallback = []() { ctx.reset(); };
135a222d00cSFangrui Song   context->e.logName = args::getFilenameWithoutExe(args[0]);
136a222d00cSFangrui Song   context->e.errorLimitExceededMsg =
137a222d00cSFangrui Song       "too many errors emitted, stopping now (use "
138c94d393aSSam Clegg       "-error-limit=0 to see all errors)";
139c94d393aSSam Clegg 
140136d27abSRui Ueyama   symtab = make<SymbolTable>();
141c94d393aSSam Clegg 
142c729c1b4SSam Clegg   initLLVM();
143a222d00cSFangrui Song   LinkerDriver(ctx).linkerMain(args);
144c94d393aSSam Clegg 
14583d59e05SAlexandre Ganea   return errorCount() == 0;
146c94d393aSSam Clegg }
147c94d393aSSam Clegg 
148dd647e3eSChandler Carruth #define OPTTABLE_STR_TABLE_CODE
149c94d393aSSam Clegg #include "Options.inc"
150dd647e3eSChandler Carruth #undef OPTTABLE_STR_TABLE_CODE
151dd647e3eSChandler Carruth 
152dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_TABLE_CODE
153dd647e3eSChandler Carruth #include "Options.inc"
154dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_TABLE_CODE
155c94d393aSSam Clegg 
156c94d393aSSam Clegg // Create table mapping all options defined in Options.td
15707d9ab9aSserge-sans-paille static constexpr opt::OptTable::Info optInfo[] = {
158dcb6d212SJustin Bogner #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,         \
159aff197ffSDavid Spickett                VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR,     \
160aff197ffSDavid Spickett                VALUES)                                                         \
161aff197ffSDavid Spickett   {PREFIX,                                                                     \
162aff197ffSDavid Spickett    NAME,                                                                       \
163aff197ffSDavid Spickett    HELPTEXT,                                                                   \
164aff197ffSDavid Spickett    HELPTEXTSFORVARIANTS,                                                       \
165aff197ffSDavid Spickett    METAVAR,                                                                    \
166aff197ffSDavid Spickett    OPT_##ID,                                                                   \
167aff197ffSDavid Spickett    opt::Option::KIND##Class,                                                   \
168aff197ffSDavid Spickett    PARAM,                                                                      \
169aff197ffSDavid Spickett    FLAGS,                                                                      \
170aff197ffSDavid Spickett    VISIBILITY,                                                                 \
171aff197ffSDavid Spickett    OPT_##GROUP,                                                                \
172aff197ffSDavid Spickett    OPT_##ALIAS,                                                                \
173aff197ffSDavid Spickett    ALIASARGS,                                                                  \
174dcb6d212SJustin Bogner    VALUES},
175c94d393aSSam Clegg #include "Options.inc"
176c94d393aSSam Clegg #undef OPTION
177c94d393aSSam Clegg };
178c94d393aSSam Clegg 
1795455038dSBenjamin Kramer namespace {
18007bb29d8Sserge-sans-paille class WasmOptTable : public opt::GenericOptTable {
18139049c05SRui Ueyama public:
182dd647e3eSChandler Carruth   WasmOptTable()
183dd647e3eSChandler Carruth       : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}
184136d27abSRui Ueyama   opt::InputArgList parse(ArrayRef<const char *> argv);
18539049c05SRui Ueyama };
1865455038dSBenjamin Kramer } // namespace
18739049c05SRui Ueyama 
188c94d393aSSam Clegg // Set color diagnostics according to -color-diagnostics={auto,always,never}
189c94d393aSSam Clegg // or -no-color-diagnostics flags.
190136d27abSRui Ueyama static void handleColorDiagnostics(opt::InputArgList &args) {
191136d27abSRui Ueyama   auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
192c94d393aSSam Clegg                               OPT_no_color_diagnostics);
193136d27abSRui Ueyama   if (!arg)
194c94d393aSSam Clegg     return;
195fcb6b132SFangrui Song   auto &errs = errorHandler().errs();
196136d27abSRui Ueyama   if (arg->getOption().getID() == OPT_color_diagnostics) {
197fcb6b132SFangrui Song     errs.enable_colors(true);
198136d27abSRui Ueyama   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
199fcb6b132SFangrui Song     errs.enable_colors(false);
200cac2b334SNico Weber   } else {
201136d27abSRui Ueyama     StringRef s = arg->getValue();
202136d27abSRui Ueyama     if (s == "always")
203fcb6b132SFangrui Song       errs.enable_colors(true);
204136d27abSRui Ueyama     else if (s == "never")
205fcb6b132SFangrui Song       errs.enable_colors(false);
206136d27abSRui Ueyama     else if (s != "auto")
207136d27abSRui Ueyama       error("unknown option: --color-diagnostics=" + s);
208c94d393aSSam Clegg   }
209c94d393aSSam Clegg }
210c94d393aSSam Clegg 
211928e9e17SSam Clegg static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
212928e9e17SSam Clegg   if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
213928e9e17SSam Clegg     StringRef s = arg->getValue();
214928e9e17SSam Clegg     if (s != "windows" && s != "posix")
215928e9e17SSam Clegg       error("invalid response file quoting: " + s);
216928e9e17SSam Clegg     if (s == "windows")
217928e9e17SSam Clegg       return cl::TokenizeWindowsCommandLine;
218928e9e17SSam Clegg     return cl::TokenizeGNUCommandLine;
219928e9e17SSam Clegg   }
220928e9e17SSam Clegg   if (Triple(sys::getProcessTriple()).isOSWindows())
221928e9e17SSam Clegg     return cl::TokenizeWindowsCommandLine;
222928e9e17SSam Clegg   return cl::TokenizeGNUCommandLine;
223928e9e17SSam Clegg }
224928e9e17SSam Clegg 
225c94d393aSSam Clegg // Find a file by concatenating given paths.
226b9ef5648SKazu Hirata static std::optional<std::string> findFile(StringRef path1,
227b9ef5648SKazu Hirata                                            const Twine &path2) {
228136d27abSRui Ueyama   SmallString<128> s;
229136d27abSRui Ueyama   path::append(s, path1, path2);
230136d27abSRui Ueyama   if (fs::exists(s))
2313e24242aSJonas Devlieghere     return std::string(s);
232c68af42fSKazu Hirata   return std::nullopt;
233c94d393aSSam Clegg }
234c94d393aSSam Clegg 
235136d27abSRui Ueyama opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) {
236136d27abSRui Ueyama   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
237c94d393aSSam Clegg 
238136d27abSRui Ueyama   unsigned missingIndex;
239136d27abSRui Ueyama   unsigned missingCount;
240e9ce661eSSam Clegg 
241928e9e17SSam Clegg   // We need to get the quoting style for response files before parsing all
242928e9e17SSam Clegg   // options so we parse here before and ignore all the options but
243928e9e17SSam Clegg   // --rsp-quoting.
244136d27abSRui Ueyama   opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
245c94d393aSSam Clegg 
246928e9e17SSam Clegg   // Expand response files (arguments in the form of @<filename>)
247928e9e17SSam Clegg   // and then parse the argument again.
24883d59e05SAlexandre Ganea   cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec);
249928e9e17SSam Clegg   args = this->ParseArgs(vec, missingIndex, missingCount);
250928e9e17SSam Clegg 
251136d27abSRui Ueyama   handleColorDiagnostics(args);
252966427b8SSam Clegg   if (missingCount)
253966427b8SSam Clegg     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
254966427b8SSam Clegg 
255136d27abSRui Ueyama   for (auto *arg : args.filtered(OPT_UNKNOWN))
256136d27abSRui Ueyama     error("unknown argument: " + arg->getAsString(args));
257136d27abSRui Ueyama   return args;
258c94d393aSSam Clegg }
259c94d393aSSam Clegg 
26031efdcd7SSam Clegg // Currently we allow a ".imports" to live alongside a library. This can
26131efdcd7SSam Clegg // be used to specify a list of symbols which can be undefined at link
26231efdcd7SSam Clegg // time (imported from the environment.  For example libc.a include an
26331efdcd7SSam Clegg // import file that lists the syscall functions it relies on at runtime.
26431efdcd7SSam Clegg // In the long run this information would be better stored as a symbol
26531efdcd7SSam Clegg // attribute/flag in the object file itself.
26631efdcd7SSam Clegg // See: https://github.com/WebAssembly/tool-conventions/issues/35
267136d27abSRui Ueyama static void readImportFile(StringRef filename) {
268b9ef5648SKazu Hirata   if (std::optional<MemoryBufferRef> buf = readFile(filename))
269136d27abSRui Ueyama     for (StringRef sym : args::getLines(*buf))
270*3792b362SFangrui Song       ctx.arg.allowUndefinedSymbols.insert(sym);
27131efdcd7SSam Clegg }
27231efdcd7SSam Clegg 
2738adf7ac5SSam Clegg // Returns slices of MB by parsing MB as an archive file.
2748adf7ac5SSam Clegg // Each slice consists of a member file in the archive.
27539e024d9SSam Clegg std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
27639e024d9SSam Clegg     MemoryBufferRef mb) {
277136d27abSRui Ueyama   std::unique_ptr<Archive> file =
278136d27abSRui Ueyama       CHECK(Archive::create(mb),
279136d27abSRui Ueyama             mb.getBufferIdentifier() + ": failed to parse archive");
2808adf7ac5SSam Clegg 
28139e024d9SSam Clegg   std::vector<std::pair<MemoryBufferRef, uint64_t>> v;
282136d27abSRui Ueyama   Error err = Error::success();
283681b1be7SFangrui Song   for (const Archive::Child &c : file->children(err)) {
284136d27abSRui Ueyama     MemoryBufferRef mbref =
285136d27abSRui Ueyama         CHECK(c.getMemoryBufferRef(),
286136d27abSRui Ueyama               mb.getBufferIdentifier() +
2878adf7ac5SSam Clegg                   ": could not get the buffer for a child of the archive");
28839e024d9SSam Clegg     v.push_back(std::make_pair(mbref, c.getChildOffset()));
2898adf7ac5SSam Clegg   }
290136d27abSRui Ueyama   if (err)
291136d27abSRui Ueyama     fatal(mb.getBufferIdentifier() +
292136d27abSRui Ueyama           ": Archive::children failed: " + toString(std::move(err)));
2938adf7ac5SSam Clegg 
2948adf7ac5SSam Clegg   // Take ownership of memory buffers created for members of thin archives.
295136d27abSRui Ueyama   for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers())
296136d27abSRui Ueyama     make<std::unique_ptr<MemoryBuffer>>(std::move(mb));
2978adf7ac5SSam Clegg 
298136d27abSRui Ueyama   return v;
2998adf7ac5SSam Clegg }
3008adf7ac5SSam Clegg 
301136d27abSRui Ueyama void LinkerDriver::addFile(StringRef path) {
302b9ef5648SKazu Hirata   std::optional<MemoryBufferRef> buffer = readFile(path);
3035413bf1bSKazu Hirata   if (!buffer)
304c94d393aSSam Clegg     return;
305136d27abSRui Ueyama   MemoryBufferRef mbref = *buffer;
306c94d393aSSam Clegg 
307136d27abSRui Ueyama   switch (identify_magic(mbref.getBuffer())) {
308c729c1b4SSam Clegg   case file_magic::archive: {
309136d27abSRui Ueyama     SmallString<128> importFile = path;
310136d27abSRui Ueyama     path::replace_extension(importFile, ".imports");
311136d27abSRui Ueyama     if (fs::exists(importFile))
312136d27abSRui Ueyama       readImportFile(importFile.str());
31361d70e4aSSam Clegg 
314bcc9b9d8SSam Clegg     auto members = getArchiveMembers(mbref);
315bcc9b9d8SSam Clegg 
3168adf7ac5SSam Clegg     // Handle -whole-archive.
317136d27abSRui Ueyama     if (inWholeArchive) {
318bcc9b9d8SSam Clegg       for (const auto &[m, offset] : members) {
31939e024d9SSam Clegg         auto *object = createObjectFile(m, path, offset);
320b3b4cda1SSam Clegg         // Mark object as live; object members are normally not
321b3b4cda1SSam Clegg         // live by default but -whole-archive is designed to treat
322b3b4cda1SSam Clegg         // them as such.
323b3b4cda1SSam Clegg         object->markLive();
324b3b4cda1SSam Clegg         files.push_back(object);
325b3b4cda1SSam Clegg       }
326b3b4cda1SSam Clegg 
3278adf7ac5SSam Clegg       return;
3288adf7ac5SSam Clegg     }
3298adf7ac5SSam Clegg 
330136d27abSRui Ueyama     std::unique_ptr<Archive> file =
331136d27abSRui Ueyama         CHECK(Archive::create(mbref), path + ": failed to parse archive");
33261d70e4aSSam Clegg 
333bcc9b9d8SSam Clegg     for (const auto &[m, offset] : members) {
334bcc9b9d8SSam Clegg       auto magic = identify_magic(m.getBuffer());
335bcc9b9d8SSam Clegg       if (magic == file_magic::wasm_object || magic == file_magic::bitcode)
336bcc9b9d8SSam Clegg         files.push_back(createObjectFile(m, path, offset, true));
337bcc9b9d8SSam Clegg       else
338bcc9b9d8SSam Clegg         warn(path + ": archive member '" + m.getBufferIdentifier() +
339bcc9b9d8SSam Clegg              "' is neither Wasm object file nor LLVM bitcode");
34061d70e4aSSam Clegg     }
34131efdcd7SSam Clegg 
34231efdcd7SSam Clegg     return;
34331efdcd7SSam Clegg   }
344c729c1b4SSam Clegg   case file_magic::bitcode:
345be770edeSSam Clegg   case file_magic::wasm_object: {
346be770edeSSam Clegg     auto obj = createObjectFile(mbref, "", 0, inLib);
347*3792b362SFangrui Song     if (ctx.arg.isStatic && isa<SharedFile>(obj)) {
348be770edeSSam Clegg       error("attempted static link of dynamic object " + path);
349c729c1b4SSam Clegg       break;
350be770edeSSam Clegg     }
351be770edeSSam Clegg     files.push_back(obj);
352be770edeSSam Clegg     break;
353be770edeSSam Clegg   }
3543111784fSSam Clegg   case file_magic::unknown:
355d9d840cdSSam Clegg     if (mbref.getBuffer().starts_with("#STUB")) {
3563111784fSSam Clegg       files.push_back(make<StubFile>(mbref));
3573111784fSSam Clegg       break;
3583111784fSSam Clegg     }
3593111784fSSam Clegg     [[fallthrough]];
360c729c1b4SSam Clegg   default:
361136d27abSRui Ueyama     error("unknown file type: " + mbref.getBufferIdentifier());
362c94d393aSSam Clegg   }
363c729c1b4SSam Clegg }
364c94d393aSSam Clegg 
365b9ef5648SKazu Hirata static std::optional<std::string> findFromSearchPaths(StringRef path) {
366*3792b362SFangrui Song   for (StringRef dir : ctx.arg.searchPaths)
367b9ef5648SKazu Hirata     if (std::optional<std::string> s = findFile(dir, path))
3680a9756fcSSam Clegg       return s;
369c68af42fSKazu Hirata   return std::nullopt;
370c94d393aSSam Clegg }
371c94d393aSSam Clegg 
3720a9756fcSSam Clegg // This is for -l<basename>. We'll look for lib<basename>.a from
3730a9756fcSSam Clegg // search paths.
374b9ef5648SKazu Hirata static std::optional<std::string> searchLibraryBaseName(StringRef name) {
375*3792b362SFangrui Song   for (StringRef dir : ctx.arg.searchPaths) {
376*3792b362SFangrui Song     if (!ctx.arg.isStatic)
377b9ef5648SKazu Hirata       if (std::optional<std::string> s = findFile(dir, "lib" + name + ".so"))
3780a9756fcSSam Clegg         return s;
379b9ef5648SKazu Hirata     if (std::optional<std::string> s = findFile(dir, "lib" + name + ".a"))
3800a9756fcSSam Clegg       return s;
3810a9756fcSSam Clegg   }
382c68af42fSKazu Hirata   return std::nullopt;
3830a9756fcSSam Clegg }
3840a9756fcSSam Clegg 
3850a9756fcSSam Clegg // This is for -l<namespec>.
386b9ef5648SKazu Hirata static std::optional<std::string> searchLibrary(StringRef name) {
3878d85c96eSFangrui Song   if (name.starts_with(":"))
3880a9756fcSSam Clegg     return findFromSearchPaths(name.substr(1));
3890a9756fcSSam Clegg   return searchLibraryBaseName(name);
3900a9756fcSSam Clegg }
3910a9756fcSSam Clegg 
3920a9756fcSSam Clegg // Add a given library by searching it from input search paths.
3930a9756fcSSam Clegg void LinkerDriver::addLibrary(StringRef name) {
394b9ef5648SKazu Hirata   if (std::optional<std::string> path = searchLibrary(name))
3950a9756fcSSam Clegg     addFile(saver().save(*path));
3960a9756fcSSam Clegg   else
3970a9756fcSSam Clegg     error("unable to find library -l" + name, ErrorTag::LibNotFound, {name});
398c94d393aSSam Clegg }
399c94d393aSSam Clegg 
400136d27abSRui Ueyama void LinkerDriver::createFiles(opt::InputArgList &args) {
401136d27abSRui Ueyama   for (auto *arg : args) {
402136d27abSRui Ueyama     switch (arg->getOption().getID()) {
4030a9756fcSSam Clegg     case OPT_library:
404136d27abSRui Ueyama       addLibrary(arg->getValue());
405c94d393aSSam Clegg       break;
406c94d393aSSam Clegg     case OPT_INPUT:
407136d27abSRui Ueyama       addFile(arg->getValue());
408c94d393aSSam Clegg       break;
4090a9756fcSSam Clegg     case OPT_Bstatic:
410*3792b362SFangrui Song       ctx.arg.isStatic = true;
4110a9756fcSSam Clegg       break;
4120a9756fcSSam Clegg     case OPT_Bdynamic:
413*3792b362SFangrui Song       ctx.arg.isStatic = false;
4140a9756fcSSam Clegg       break;
4158adf7ac5SSam Clegg     case OPT_whole_archive:
416136d27abSRui Ueyama       inWholeArchive = true;
4178adf7ac5SSam Clegg       break;
4188adf7ac5SSam Clegg     case OPT_no_whole_archive:
419136d27abSRui Ueyama       inWholeArchive = false;
4208adf7ac5SSam Clegg       break;
42119261390SSam Clegg     case OPT_start_lib:
42219261390SSam Clegg       if (inLib)
42319261390SSam Clegg         error("nested --start-lib");
42419261390SSam Clegg       inLib = true;
42519261390SSam Clegg       break;
42619261390SSam Clegg     case OPT_end_lib:
42719261390SSam Clegg       if (!inLib)
42819261390SSam Clegg         error("stray --end-lib");
42919261390SSam Clegg       inLib = false;
43019261390SSam Clegg       break;
431c94d393aSSam Clegg     }
432c94d393aSSam Clegg   }
433b5767010SSam Clegg   if (files.empty() && errorCount() == 0)
434b5767010SSam Clegg     error("no input files");
435c94d393aSSam Clegg }
436c94d393aSSam Clegg 
437b70eb863SSam Clegg static StringRef getAliasSpelling(opt::Arg *arg) {
438b70eb863SSam Clegg   if (const opt::Arg *alias = arg->getAlias())
439b70eb863SSam Clegg     return alias->getSpelling();
440b70eb863SSam Clegg   return arg->getSpelling();
441b70eb863SSam Clegg }
442b70eb863SSam Clegg 
443b70eb863SSam Clegg static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
444b70eb863SSam Clegg                                                         unsigned id) {
445b70eb863SSam Clegg   auto *arg = args.getLastArg(id);
446b70eb863SSam Clegg   if (!arg)
447b70eb863SSam Clegg     return {"", ""};
448b70eb863SSam Clegg 
449b70eb863SSam Clegg   StringRef s = arg->getValue();
450b70eb863SSam Clegg   std::pair<StringRef, StringRef> ret = s.split(';');
451b70eb863SSam Clegg   if (ret.second.empty())
452b70eb863SSam Clegg     error(getAliasSpelling(arg) + " expects 'old;new' format, but got " + s);
453b70eb863SSam Clegg   return ret;
454b70eb863SSam Clegg }
455b70eb863SSam Clegg 
456b70eb863SSam Clegg // Parse options of the form "old;new[;extra]".
457b70eb863SSam Clegg static std::tuple<StringRef, StringRef, StringRef>
458b70eb863SSam Clegg getOldNewOptionsExtra(opt::InputArgList &args, unsigned id) {
459b70eb863SSam Clegg   auto [oldDir, second] = getOldNewOptions(args, id);
460b70eb863SSam Clegg   auto [newDir, extraDir] = second.split(';');
461b70eb863SSam Clegg   return {oldDir, newDir, extraDir};
462b70eb863SSam Clegg }
463b70eb863SSam Clegg 
464136d27abSRui Ueyama static StringRef getEntry(opt::InputArgList &args) {
465136d27abSRui Ueyama   auto *arg = args.getLastArg(OPT_entry, OPT_no_entry);
466136d27abSRui Ueyama   if (!arg) {
467136d27abSRui Ueyama     if (args.hasArg(OPT_relocatable))
46809137be7SSam Clegg       return "";
469136d27abSRui Ueyama     if (args.hasArg(OPT_shared))
47009137be7SSam Clegg       return "__wasm_call_ctors";
47109137be7SSam Clegg     return "_start";
47209137be7SSam Clegg   }
473136d27abSRui Ueyama   if (arg->getOption().getID() == OPT_no_entry)
4742c096bacSSam Clegg     return "";
475136d27abSRui Ueyama   return arg->getValue();
4762c096bacSSam Clegg }
4772c096bacSSam Clegg 
478206884bfSSam Clegg // Determines what we should do if there are remaining unresolved
479206884bfSSam Clegg // symbols after the name resolution.
480206884bfSSam Clegg static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) {
481206884bfSSam Clegg   UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols,
482206884bfSSam Clegg                                               OPT_warn_unresolved_symbols, true)
483206884bfSSam Clegg                                      ? UnresolvedPolicy::ReportError
484206884bfSSam Clegg                                      : UnresolvedPolicy::Warn;
485206884bfSSam Clegg 
486206884bfSSam Clegg   if (auto *arg = args.getLastArg(OPT_unresolved_symbols)) {
487206884bfSSam Clegg     StringRef s = arg->getValue();
488206884bfSSam Clegg     if (s == "ignore-all")
489206884bfSSam Clegg       return UnresolvedPolicy::Ignore;
49086c90f9bSSam Clegg     if (s == "import-dynamic")
49186c90f9bSSam Clegg       return UnresolvedPolicy::ImportDynamic;
492206884bfSSam Clegg     if (s == "report-all")
493206884bfSSam Clegg       return errorOrWarn;
494206884bfSSam Clegg     error("unknown --unresolved-symbols value: " + s);
495206884bfSSam Clegg   }
496206884bfSSam Clegg 
497206884bfSSam Clegg   return errorOrWarn;
498206884bfSSam Clegg }
499206884bfSSam Clegg 
500c7af9ae5SDerek Schuff // Parse --build-id or --build-id=<style>. We handle "tree" as a
501c7af9ae5SDerek Schuff // synonym for "sha1" because all our hash functions including
502c7af9ae5SDerek Schuff // -build-id=sha1 are actually tree hashes for performance reasons.
503c7af9ae5SDerek Schuff static std::pair<BuildIdKind, SmallVector<uint8_t, 0>>
504c7af9ae5SDerek Schuff getBuildId(opt::InputArgList &args) {
505c7af9ae5SDerek Schuff   auto *arg = args.getLastArg(OPT_build_id, OPT_build_id_eq);
506c7af9ae5SDerek Schuff   if (!arg)
507c7af9ae5SDerek Schuff     return {BuildIdKind::None, {}};
508c7af9ae5SDerek Schuff 
509c7af9ae5SDerek Schuff   if (arg->getOption().getID() == OPT_build_id)
510c7af9ae5SDerek Schuff     return {BuildIdKind::Fast, {}};
511c7af9ae5SDerek Schuff 
512c7af9ae5SDerek Schuff   StringRef s = arg->getValue();
513c7af9ae5SDerek Schuff   if (s == "fast")
514c7af9ae5SDerek Schuff     return {BuildIdKind::Fast, {}};
515c7af9ae5SDerek Schuff   if (s == "sha1" || s == "tree")
516c7af9ae5SDerek Schuff     return {BuildIdKind::Sha1, {}};
517c7af9ae5SDerek Schuff   if (s == "uuid")
518c7af9ae5SDerek Schuff     return {BuildIdKind::Uuid, {}};
5198d85c96eSFangrui Song   if (s.starts_with("0x"))
520c7af9ae5SDerek Schuff     return {BuildIdKind::Hexstring, parseHex(s.substr(2))};
521c7af9ae5SDerek Schuff 
522c7af9ae5SDerek Schuff   if (s != "none")
523c7af9ae5SDerek Schuff     error("unknown --build-id style: " + s);
524c7af9ae5SDerek Schuff   return {BuildIdKind::None, {}};
525c7af9ae5SDerek Schuff }
526c7af9ae5SDerek Schuff 
527a1282a39SSam Clegg // Initializes Config members by the command line options.
528136d27abSRui Ueyama static void readConfigs(opt::InputArgList &args) {
529*3792b362SFangrui Song   ctx.arg.allowMultipleDefinition =
5300367305aSmzukovec       hasZOption(args, "muldefs") ||
5310367305aSmzukovec       args.hasFlag(OPT_allow_multiple_definition,
5320367305aSmzukovec                    OPT_no_allow_multiple_definition, false);
533*3792b362SFangrui Song   ctx.arg.bsymbolic = args.hasArg(OPT_Bsymbolic);
534*3792b362SFangrui Song   ctx.arg.checkFeatures =
535136d27abSRui Ueyama       args.hasFlag(OPT_check_features, OPT_no_check_features, true);
536*3792b362SFangrui Song   ctx.arg.compressRelocations = args.hasArg(OPT_compress_relocations);
537*3792b362SFangrui Song   ctx.arg.demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
538*3792b362SFangrui Song   ctx.arg.disableVerify = args.hasArg(OPT_disable_verify);
539*3792b362SFangrui Song   ctx.arg.emitRelocs = args.hasArg(OPT_emit_relocs);
540*3792b362SFangrui Song   ctx.arg.experimentalPic = args.hasArg(OPT_experimental_pic);
541*3792b362SFangrui Song   ctx.arg.entry = getEntry(args);
542*3792b362SFangrui Song   ctx.arg.exportAll = args.hasArg(OPT_export_all);
543*3792b362SFangrui Song   ctx.arg.exportTable = args.hasArg(OPT_export_table);
544*3792b362SFangrui Song   ctx.arg.growableTable = args.hasArg(OPT_growable_table);
545*3792b362SFangrui Song   ctx.arg.noinhibitExec = args.hasArg(OPT_noinhibit_exec);
546d4c8a0edSDan Gohman 
547d4c8a0edSDan Gohman   if (args.hasArg(OPT_import_memory_with_name)) {
548*3792b362SFangrui Song     ctx.arg.memoryImport =
549d4c8a0edSDan Gohman         args.getLastArgValue(OPT_import_memory_with_name).split(",");
550d4c8a0edSDan Gohman   } else if (args.hasArg(OPT_import_memory)) {
551*3792b362SFangrui Song     ctx.arg.memoryImport =
552d4c8a0edSDan Gohman         std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
553d4c8a0edSDan Gohman   } else {
554*3792b362SFangrui Song     ctx.arg.memoryImport =
555b9ef5648SKazu Hirata         std::optional<std::pair<llvm::StringRef, llvm::StringRef>>();
556d4c8a0edSDan Gohman   }
557d4c8a0edSDan Gohman 
558d4c8a0edSDan Gohman   if (args.hasArg(OPT_export_memory_with_name)) {
559*3792b362SFangrui Song     ctx.arg.memoryExport = args.getLastArgValue(OPT_export_memory_with_name);
560d4c8a0edSDan Gohman   } else if (args.hasArg(OPT_export_memory)) {
561*3792b362SFangrui Song     ctx.arg.memoryExport = memoryName;
562d4c8a0edSDan Gohman   } else {
563*3792b362SFangrui Song     ctx.arg.memoryExport = std::optional<llvm::StringRef>();
564d4c8a0edSDan Gohman   }
565d4c8a0edSDan Gohman 
566*3792b362SFangrui Song   ctx.arg.sharedMemory = args.hasArg(OPT_shared_memory);
567*3792b362SFangrui Song   ctx.arg.soName = args.getLastArgValue(OPT_soname);
568*3792b362SFangrui Song   ctx.arg.importTable = args.hasArg(OPT_import_table);
569*3792b362SFangrui Song   ctx.arg.importUndefined = args.hasArg(OPT_import_undefined);
570*3792b362SFangrui Song   ctx.arg.ltoo = args::getInteger(args, OPT_lto_O, 2);
571*3792b362SFangrui Song   if (ctx.arg.ltoo > 3)
572*3792b362SFangrui Song     error("invalid optimization level for LTO: " + Twine(ctx.arg.ltoo));
57345ee0a9aSScott Linder   unsigned ltoCgo =
574*3792b362SFangrui Song       args::getInteger(args, OPT_lto_CGO, args::getCGOptLevel(ctx.arg.ltoo));
57545ee0a9aSScott Linder   if (auto level = CodeGenOpt::getLevel(ltoCgo))
576*3792b362SFangrui Song     ctx.arg.ltoCgo = *level;
57745ee0a9aSScott Linder   else
57845ee0a9aSScott Linder     error("invalid codegen optimization level for LTO: " + Twine(ltoCgo));
579*3792b362SFangrui Song   ctx.arg.ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
580*3792b362SFangrui Song   ctx.arg.ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
581*3792b362SFangrui Song   ctx.arg.ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
582*3792b362SFangrui Song   ctx.arg.mapFile = args.getLastArgValue(OPT_Map);
583*3792b362SFangrui Song   ctx.arg.optimize = args::getInteger(args, OPT_O, 1);
584*3792b362SFangrui Song   ctx.arg.outputFile = args.getLastArgValue(OPT_o);
585*3792b362SFangrui Song   ctx.arg.relocatable = args.hasArg(OPT_relocatable);
586*3792b362SFangrui Song   ctx.arg.gcSections =
587*3792b362SFangrui Song       args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !ctx.arg.relocatable);
58889d5635fSSam Clegg   for (auto *arg : args.filtered(OPT_keep_section))
589*3792b362SFangrui Song     ctx.arg.keepSections.insert(arg->getValue());
590*3792b362SFangrui Song   ctx.arg.mergeDataSegments =
591136d27abSRui Ueyama       args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
592*3792b362SFangrui Song                    !ctx.arg.relocatable);
593*3792b362SFangrui Song   ctx.arg.pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
594*3792b362SFangrui Song   ctx.arg.printGcSections =
595136d27abSRui Ueyama       args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
596*3792b362SFangrui Song   ctx.arg.saveTemps = args.hasArg(OPT_save_temps);
597*3792b362SFangrui Song   ctx.arg.searchPaths = args::getStrings(args, OPT_library_path);
598*3792b362SFangrui Song   ctx.arg.shared = args.hasArg(OPT_shared);
599*3792b362SFangrui Song   ctx.arg.shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck);
600*3792b362SFangrui Song   ctx.arg.stripAll = args.hasArg(OPT_strip_all);
601*3792b362SFangrui Song   ctx.arg.stripDebug = args.hasArg(OPT_strip_debug);
602*3792b362SFangrui Song   ctx.arg.stackFirst = args.hasArg(OPT_stack_first);
603*3792b362SFangrui Song   ctx.arg.trace = args.hasArg(OPT_trace);
604*3792b362SFangrui Song   ctx.arg.thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir);
605*3792b362SFangrui Song   ctx.arg.thinLTOCachePolicy = CHECK(
606136d27abSRui Ueyama       parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),
607c729c1b4SSam Clegg       "--thinlto-cache-policy: invalid cache policy");
608*3792b362SFangrui Song   ctx.arg.thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);
609*3792b362SFangrui Song   ctx.arg.thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) ||
6109a450a00SSam Clegg                                   args.hasArg(OPT_thinlto_index_only) ||
6119a450a00SSam Clegg                                   args.hasArg(OPT_thinlto_index_only_eq);
612*3792b362SFangrui Song   ctx.arg.thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||
6139a450a00SSam Clegg                              args.hasArg(OPT_thinlto_index_only_eq);
614*3792b362SFangrui Song   ctx.arg.thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq);
615*3792b362SFangrui Song   ctx.arg.thinLTOObjectSuffixReplace =
616b70eb863SSam Clegg       getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq);
617*3792b362SFangrui Song   std::tie(ctx.arg.thinLTOPrefixReplaceOld, ctx.arg.thinLTOPrefixReplaceNew,
618*3792b362SFangrui Song            ctx.arg.thinLTOPrefixReplaceNativeObject) =
619b70eb863SSam Clegg       getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace_eq);
620*3792b362SFangrui Song   if (ctx.arg.thinLTOEmitIndexFiles && !ctx.arg.thinLTOIndexOnly) {
621b70eb863SSam Clegg     if (args.hasArg(OPT_thinlto_object_suffix_replace_eq))
622b70eb863SSam Clegg       error("--thinlto-object-suffix-replace is not supported with "
623b70eb863SSam Clegg             "--thinlto-emit-index-files");
624b70eb863SSam Clegg     else if (args.hasArg(OPT_thinlto_prefix_replace_eq))
625b70eb863SSam Clegg       error("--thinlto-prefix-replace is not supported with "
626b70eb863SSam Clegg             "--thinlto-emit-index-files");
627b70eb863SSam Clegg   }
628*3792b362SFangrui Song   if (!ctx.arg.thinLTOPrefixReplaceNativeObject.empty() &&
629*3792b362SFangrui Song       ctx.arg.thinLTOIndexOnlyArg.empty()) {
630b70eb863SSam Clegg     error("--thinlto-prefix-replace=old_dir;new_dir;obj_dir must be used with "
631b70eb863SSam Clegg           "--thinlto-index-only=");
632b70eb863SSam Clegg   }
633*3792b362SFangrui Song   ctx.arg.unresolvedSymbols = getUnresolvedSymbolPolicy(args);
634*3792b362SFangrui Song   ctx.arg.whyExtract = args.getLastArgValue(OPT_why_extract);
635136d27abSRui Ueyama   errorHandler().verbose = args.hasArg(OPT_verbose);
636136d27abSRui Ueyama   LLVM_DEBUG(errorHandler().verbose = true);
637c94d393aSSam Clegg 
638*3792b362SFangrui Song   ctx.arg.tableBase = args::getInteger(args, OPT_table_base, 0);
639*3792b362SFangrui Song   ctx.arg.globalBase = args::getInteger(args, OPT_global_base, 0);
640*3792b362SFangrui Song   ctx.arg.initialHeap = args::getInteger(args, OPT_initial_heap, 0);
641*3792b362SFangrui Song   ctx.arg.initialMemory = args::getInteger(args, OPT_initial_memory, 0);
642*3792b362SFangrui Song   ctx.arg.maxMemory = args::getInteger(args, OPT_max_memory, 0);
643*3792b362SFangrui Song   ctx.arg.noGrowableMemory = args.hasArg(OPT_no_growable_memory);
644*3792b362SFangrui Song   ctx.arg.zStackSize =
645136d27abSRui Ueyama       args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
64682de51a3SThomas Lively 
6472b6c6bb4SYAMAMOTO Takashi   // -Bdynamic by default if -pie or -shared is specified.
648*3792b362SFangrui Song   if (ctx.arg.pie || ctx.arg.shared)
649*3792b362SFangrui Song     ctx.arg.isStatic = false;
6502b6c6bb4SYAMAMOTO Takashi 
651*3792b362SFangrui Song   if (ctx.arg.maxMemory != 0 && ctx.arg.noGrowableMemory) {
652cb4f94dbSSingleAccretion     // Erroring out here is simpler than defining precedence rules.
653cb4f94dbSSingleAccretion     error("--max-memory is incompatible with --no-growable-memory");
654cb4f94dbSSingleAccretion   }
655cb4f94dbSSingleAccretion 
656e8e914e6SSam Clegg   // Default value of exportDynamic depends on `-shared`
657*3792b362SFangrui Song   ctx.arg.exportDynamic =
658*3792b362SFangrui Song       args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, ctx.arg.shared);
659e8e914e6SSam Clegg 
660b9a539c0SWouter van Oortmerssen   // Parse wasm32/64.
661b9a539c0SWouter van Oortmerssen   if (auto *arg = args.getLastArg(OPT_m)) {
662b9a539c0SWouter van Oortmerssen     StringRef s = arg->getValue();
663b9a539c0SWouter van Oortmerssen     if (s == "wasm32")
664*3792b362SFangrui Song       ctx.arg.is64 = false;
665b9a539c0SWouter van Oortmerssen     else if (s == "wasm64")
666*3792b362SFangrui Song       ctx.arg.is64 = true;
667b9a539c0SWouter van Oortmerssen     else
668b9a539c0SWouter van Oortmerssen       error("invalid target architecture: " + s);
669b9a539c0SWouter van Oortmerssen   }
670b9a539c0SWouter van Oortmerssen 
671eb4663d8SFangrui Song   // --threads= takes a positive integer and provides the default value for
672eb4663d8SFangrui Song   // --thinlto-jobs=.
673eb4663d8SFangrui Song   if (auto *arg = args.getLastArg(OPT_threads)) {
674eb4663d8SFangrui Song     StringRef v(arg->getValue());
675eb4663d8SFangrui Song     unsigned threads = 0;
676eb4663d8SFangrui Song     if (!llvm::to_integer(v, threads, 0) || threads == 0)
677eb4663d8SFangrui Song       error(arg->getSpelling() + ": expected a positive integer, but got '" +
678eb4663d8SFangrui Song             arg->getValue() + "'");
679eb4663d8SFangrui Song     parallel::strategy = hardware_concurrency(threads);
680*3792b362SFangrui Song     ctx.arg.thinLTOJobs = v;
681eb4663d8SFangrui Song   }
682eb4663d8SFangrui Song   if (auto *arg = args.getLastArg(OPT_thinlto_jobs))
683*3792b362SFangrui Song     ctx.arg.thinLTOJobs = arg->getValue();
684eb4663d8SFangrui Song 
685136d27abSRui Ueyama   if (auto *arg = args.getLastArg(OPT_features)) {
686*3792b362SFangrui Song     ctx.arg.features =
687b9ef5648SKazu Hirata         std::optional<std::vector<std::string>>(std::vector<std::string>());
688136d27abSRui Ueyama     for (StringRef s : arg->getValues())
689*3792b362SFangrui Song       ctx.arg.features->push_back(std::string(s));
69082de51a3SThomas Lively   }
691cc2da555SSam Clegg 
692c07e8381SSam Clegg   if (auto *arg = args.getLastArg(OPT_extra_features)) {
693*3792b362SFangrui Song     ctx.arg.extraFeatures =
694b9ef5648SKazu Hirata         std::optional<std::vector<std::string>>(std::vector<std::string>());
695c07e8381SSam Clegg     for (StringRef s : arg->getValues())
696*3792b362SFangrui Song       ctx.arg.extraFeatures->push_back(std::string(s));
697c07e8381SSam Clegg   }
698c07e8381SSam Clegg 
699758633f9SSam Clegg   // Legacy --allow-undefined flag which is equivalent to
700758633f9SSam Clegg   // --unresolve-symbols=ignore + --import-undefined
701758633f9SSam Clegg   if (args.hasArg(OPT_allow_undefined)) {
702*3792b362SFangrui Song     ctx.arg.importUndefined = true;
703*3792b362SFangrui Song     ctx.arg.unresolvedSymbols = UnresolvedPolicy::Ignore;
704758633f9SSam Clegg   }
705758633f9SSam Clegg 
706cc2da555SSam Clegg   if (args.hasArg(OPT_print_map))
707*3792b362SFangrui Song     ctx.arg.mapFile = "-";
708c7af9ae5SDerek Schuff 
709*3792b362SFangrui Song   std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(args);
710d5f65063SSam Clegg }
711c94d393aSSam Clegg 
712a1282a39SSam Clegg // Some Config members do not directly correspond to any particular
713a1282a39SSam Clegg // command line options, but computed based on other Config values.
714a1282a39SSam Clegg // This function initialize such members. See Config.h for the details
715a1282a39SSam Clegg // of these values.
716a1282a39SSam Clegg static void setConfigs() {
717*3792b362SFangrui Song   ctx.isPic = ctx.arg.pie || ctx.arg.shared;
718a1282a39SSam Clegg 
719184c22ddSSam Clegg   if (ctx.isPic) {
720*3792b362SFangrui Song     if (ctx.arg.exportTable)
721a1282a39SSam Clegg       error("-shared/-pie is incompatible with --export-table");
722*3792b362SFangrui Song     ctx.arg.importTable = true;
72393adcb77SSam Clegg   } else {
72493adcb77SSam Clegg     // Default table base.  Defaults to 1, reserving 0 for the NULL function
72593adcb77SSam Clegg     // pointer.
726*3792b362SFangrui Song     if (!ctx.arg.tableBase)
727*3792b362SFangrui Song       ctx.arg.tableBase = 1;
72893adcb77SSam Clegg     // The default offset for static/global data, for when --global-base is
72993adcb77SSam Clegg     // not specified on the command line.  The precise value of 1024 is
73093adcb77SSam Clegg     // somewhat arbitrary, and pre-dates wasm-ld (Its the value that
73193adcb77SSam Clegg     // emscripten used prior to wasm-ld).
732*3792b362SFangrui Song     if (!ctx.arg.globalBase && !ctx.arg.relocatable && !ctx.arg.stackFirst)
733*3792b362SFangrui Song       ctx.arg.globalBase = 1024;
734a1282a39SSam Clegg   }
735a1282a39SSam Clegg 
736*3792b362SFangrui Song   if (ctx.arg.relocatable) {
737*3792b362SFangrui Song     if (ctx.arg.exportTable)
73848219d06SAndy Wingo       error("--relocatable is incompatible with --export-table");
739*3792b362SFangrui Song     if (ctx.arg.growableTable)
74048219d06SAndy Wingo       error("--relocatable is incompatible with --growable-table");
74148219d06SAndy Wingo     // Ignore any --import-table, as it's redundant.
742*3792b362SFangrui Song     ctx.arg.importTable = true;
74348219d06SAndy Wingo   }
74448219d06SAndy Wingo 
745*3792b362SFangrui Song   if (ctx.arg.shared) {
746*3792b362SFangrui Song     if (ctx.arg.memoryExport.has_value()) {
747d4c8a0edSDan Gohman       error("--export-memory is incompatible with --shared");
748d4c8a0edSDan Gohman     }
749*3792b362SFangrui Song     if (!ctx.arg.memoryImport.has_value()) {
750*3792b362SFangrui Song       ctx.arg.memoryImport = std::pair<llvm::StringRef, llvm::StringRef>(
751*3792b362SFangrui Song           defaultModule, memoryName);
752d4c8a0edSDan Gohman     }
753a1282a39SSam Clegg   }
754d4c8a0edSDan Gohman 
755d4c8a0edSDan Gohman   // If neither export-memory nor import-memory is specified, default to
756d4c8a0edSDan Gohman   // exporting memory under its default name.
757*3792b362SFangrui Song   if (!ctx.arg.memoryExport.has_value() && !ctx.arg.memoryImport.has_value()) {
758*3792b362SFangrui Song     ctx.arg.memoryExport = memoryName;
759d4c8a0edSDan Gohman   }
760a1282a39SSam Clegg }
761a1282a39SSam Clegg 
762d5f65063SSam Clegg // Some command line options or some combinations of them are not allowed.
763d5f65063SSam Clegg // This function checks for such errors.
764136d27abSRui Ueyama static void checkOptions(opt::InputArgList &args) {
765*3792b362SFangrui Song   if (!ctx.arg.stripDebug && !ctx.arg.stripAll && ctx.arg.compressRelocations)
76630161dc2SSam Clegg     error("--compress-relocations is incompatible with output debug"
76730161dc2SSam Clegg           " information. Please pass --strip-debug or --strip-all");
768fb983cdaSSam Clegg 
769*3792b362SFangrui Song   if (ctx.arg.ltoPartitions == 0)
770c729c1b4SSam Clegg     error("--lto-partitions: number of threads must be > 0");
771*3792b362SFangrui Song   if (!get_threadpool_strategy(ctx.arg.thinLTOJobs))
772*3792b362SFangrui Song     error("--thinlto-jobs: invalid job count: " + ctx.arg.thinLTOJobs);
773c729c1b4SSam Clegg 
774*3792b362SFangrui Song   if (ctx.arg.pie && ctx.arg.shared)
775bfb75348SSam Clegg     error("-shared and -pie may not be used together");
776bfb75348SSam Clegg 
777*3792b362SFangrui Song   if (ctx.arg.outputFile.empty() && !ctx.arg.thinLTOIndexOnly)
778c94d393aSSam Clegg     error("no output file specified");
779c94d393aSSam Clegg 
780*3792b362SFangrui Song   if (ctx.arg.importTable && ctx.arg.exportTable)
7810961218cSRui Ueyama     error("--import-table and --export-table may not be used together");
7820961218cSRui Ueyama 
783*3792b362SFangrui Song   if (ctx.arg.relocatable) {
784*3792b362SFangrui Song     if (!ctx.arg.entry.empty())
785c94d393aSSam Clegg       error("entry point specified for relocatable output file");
786*3792b362SFangrui Song     if (ctx.arg.gcSections)
7870362633fSSam Clegg       error("-r and --gc-sections may not be used together");
788*3792b362SFangrui Song     if (ctx.arg.compressRelocations)
78930161dc2SSam Clegg       error("-r -and --compress-relocations may not be used together");
790136d27abSRui Ueyama     if (args.hasArg(OPT_undefined))
7910362633fSSam Clegg       error("-r -and --undefined may not be used together");
792*3792b362SFangrui Song     if (ctx.arg.pie)
793bfb75348SSam Clegg       error("-r and -pie may not be used together");
794*3792b362SFangrui Song     if (ctx.arg.sharedMemory)
7956474d1b2SThomas Lively       error("-r and --shared-memory may not be used together");
796*3792b362SFangrui Song     if (ctx.arg.globalBase)
7976912ed7bSSam Clegg       error("-r and --global-base may not by used together");
7980362633fSSam Clegg   }
79946a32683SDan Gohman 
80046a32683SDan Gohman   // To begin to prepare for Module Linking-style shared libraries, start
80146a32683SDan Gohman   // warning about uses of `-shared` and related flags outside of Experimental
80246a32683SDan Gohman   // mode, to give anyone using them a heads-up that they will be changing.
80346a32683SDan Gohman   //
80446a32683SDan Gohman   // Also, warn about flags which request explicit exports.
805*3792b362SFangrui Song   if (!ctx.arg.experimentalPic) {
80646a32683SDan Gohman     // -shared will change meaning when Module Linking is implemented.
807*3792b362SFangrui Song     if (ctx.arg.shared) {
80846a32683SDan Gohman       warn("creating shared libraries, with -shared, is not yet stable");
80946a32683SDan Gohman     }
81046a32683SDan Gohman 
81146a32683SDan Gohman     // -pie will change meaning when Module Linking is implemented.
812*3792b362SFangrui Song     if (ctx.arg.pie) {
81346a32683SDan Gohman       warn("creating PIEs, with -pie, is not yet stable");
81446a32683SDan Gohman     }
81586c90f9bSSam Clegg 
816*3792b362SFangrui Song     if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {
81786c90f9bSSam Clegg       warn("dynamic imports are not yet stable "
81886c90f9bSSam Clegg            "(--unresolved-symbols=import-dynamic)");
81986c90f9bSSam Clegg     }
82046a32683SDan Gohman   }
8212513407dSSam Clegg 
822*3792b362SFangrui Song   if (ctx.arg.bsymbolic && !ctx.arg.shared) {
8232513407dSSam Clegg     warn("-Bsymbolic is only meaningful when combined with -shared");
8242513407dSSam Clegg   }
8256912ed7bSSam Clegg 
826184c22ddSSam Clegg   if (ctx.isPic) {
827*3792b362SFangrui Song     if (ctx.arg.globalBase)
8286912ed7bSSam Clegg       error("--global-base may not be used with -shared/-pie");
829*3792b362SFangrui Song     if (ctx.arg.tableBase)
83093adcb77SSam Clegg       error("--table-base may not be used with -shared/-pie");
8316912ed7bSSam Clegg   }
832d5f65063SSam Clegg }
833d5f65063SSam Clegg 
8343c28a6d2SSam Clegg static const char *getReproduceOption(opt::InputArgList &args) {
8353c28a6d2SSam Clegg   if (auto *arg = args.getLastArg(OPT_reproduce))
8363c28a6d2SSam Clegg     return arg->getValue();
8373c28a6d2SSam Clegg   return getenv("LLD_REPRODUCE");
8383c28a6d2SSam Clegg }
8393c28a6d2SSam Clegg 
840d5f65063SSam Clegg // Force Sym to be entered in the output. Used for -u or equivalent.
8418aef04faSSam Clegg static Symbol *handleUndefined(StringRef name, const char *option) {
842136d27abSRui Ueyama   Symbol *sym = symtab->find(name);
843136d27abSRui Ueyama   if (!sym)
844d5f65063SSam Clegg     return nullptr;
845d5f65063SSam Clegg 
846d5f65063SSam Clegg   // Since symbol S may not be used inside the program, LTO may
847d5f65063SSam Clegg   // eliminate it. Mark the symbol as "used" to prevent it.
848136d27abSRui Ueyama   sym->isUsedInRegularObj = true;
849d5f65063SSam Clegg 
8508aef04faSSam Clegg   if (auto *lazySym = dyn_cast<LazySymbol>(sym)) {
851f2684959SSam Clegg     lazySym->extract();
852*3792b362SFangrui Song     if (!ctx.arg.whyExtract.empty())
853184c22ddSSam Clegg       ctx.whyExtractRecords.emplace_back(option, sym->getFile(), *sym);
8548aef04faSSam Clegg   }
855d5f65063SSam Clegg 
856136d27abSRui Ueyama   return sym;
857d5f65063SSam Clegg }
858d5f65063SSam Clegg 
8599cd98581SSam Clegg static void handleLibcall(StringRef name) {
8609cd98581SSam Clegg   Symbol *sym = symtab->find(name);
861bcc9b9d8SSam Clegg   if (sym && sym->isLazy() && isa<BitcodeFile>(sym->getFile())) {
862*3792b362SFangrui Song     if (!ctx.arg.whyExtract.empty())
863184c22ddSSam Clegg       ctx.whyExtractRecords.emplace_back("<libcall>", sym->getFile(), *sym);
864bcc9b9d8SSam Clegg     cast<LazySymbol>(sym)->extract();
8659cd98581SSam Clegg   }
8668aef04faSSam Clegg }
8678aef04faSSam Clegg 
8688aef04faSSam Clegg static void writeWhyExtract() {
869*3792b362SFangrui Song   if (ctx.arg.whyExtract.empty())
8708aef04faSSam Clegg     return;
8718aef04faSSam Clegg 
8728aef04faSSam Clegg   std::error_code ec;
873*3792b362SFangrui Song   raw_fd_ostream os(ctx.arg.whyExtract, ec, sys::fs::OF_None);
8748aef04faSSam Clegg   if (ec) {
875*3792b362SFangrui Song     error("cannot open --why-extract= file " + ctx.arg.whyExtract + ": " +
8768aef04faSSam Clegg           ec.message());
8778aef04faSSam Clegg     return;
8788aef04faSSam Clegg   }
8798aef04faSSam Clegg 
8808aef04faSSam Clegg   os << "reference\textracted\tsymbol\n";
881184c22ddSSam Clegg   for (auto &entry : ctx.whyExtractRecords) {
8828aef04faSSam Clegg     os << std::get<0>(entry) << '\t' << toString(std::get<1>(entry)) << '\t'
8838aef04faSSam Clegg        << toString(std::get<2>(entry)) << '\n';
8848aef04faSSam Clegg   }
8858aef04faSSam Clegg }
8869cd98581SSam Clegg 
887b0f18af3SSam Clegg // Equivalent of demote demoteSharedAndLazySymbols() in the ELF linker
888b0f18af3SSam Clegg static void demoteLazySymbols() {
889113b5688SSam Clegg   for (Symbol *sym : symtab->symbols()) {
890b0f18af3SSam Clegg     if (auto* s = dyn_cast<LazySymbol>(sym)) {
891b0f18af3SSam Clegg       if (s->signature) {
892b0f18af3SSam Clegg         LLVM_DEBUG(llvm::dbgs()
893b0f18af3SSam Clegg                    << "demoting lazy func: " << s->getName() << "\n");
894c68af42fSKazu Hirata         replaceSymbol<UndefinedFunction>(s, s->getName(), std::nullopt,
895c68af42fSKazu Hirata                                          std::nullopt, WASM_SYMBOL_BINDING_WEAK,
896c68af42fSKazu Hirata                                          s->getFile(), s->signature);
897b0f18af3SSam Clegg       }
898b0f18af3SSam Clegg     }
899b0f18af3SSam Clegg   }
900b0f18af3SSam Clegg }
901b0f18af3SSam Clegg 
9022dad4e2cSSam Clegg static UndefinedGlobal *
903136d27abSRui Ueyama createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
904f6f4b98fSSam Clegg   auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(
905c68af42fSKazu Hirata       name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, type));
906*3792b362SFangrui Song   ctx.arg.allowUndefinedSymbols.insert(sym->getName());
907136d27abSRui Ueyama   sym->isUsedInRegularObj = true;
908136d27abSRui Ueyama   return sym;
9092dad4e2cSSam Clegg }
9102dad4e2cSSam Clegg 
91129a3056bSSam Clegg static InputGlobal *createGlobal(StringRef name, bool isMutable) {
9125204f761SGuanzhong Chen   llvm::wasm::WasmGlobal wasmGlobal;
913*3792b362SFangrui Song   bool is64 = ctx.arg.is64.value_or(false);
9143a293cbfSWouter van Oortmerssen   wasmGlobal.Type = {uint8_t(is64 ? WASM_TYPE_I64 : WASM_TYPE_I32), isMutable};
9153a293cbfSWouter van Oortmerssen   wasmGlobal.InitExpr = intConst(0, is64);
9165204f761SGuanzhong Chen   wasmGlobal.SymbolName = name;
91729a3056bSSam Clegg   return make<InputGlobal>(wasmGlobal, nullptr);
91829a3056bSSam Clegg }
91929a3056bSSam Clegg 
92029a3056bSSam Clegg static GlobalSymbol *createGlobalVariable(StringRef name, bool isMutable) {
92129a3056bSSam Clegg   InputGlobal *g = createGlobal(name, isMutable);
92229a3056bSSam Clegg   return symtab->addSyntheticGlobal(name, WASM_SYMBOL_VISIBILITY_HIDDEN, g);
92329a3056bSSam Clegg }
92429a3056bSSam Clegg 
92529a3056bSSam Clegg static GlobalSymbol *createOptionalGlobal(StringRef name, bool isMutable) {
92629a3056bSSam Clegg   InputGlobal *g = createGlobal(name, isMutable);
92788e4056bSSam Clegg   return symtab->addOptionalGlobalSymbol(name, g);
9285204f761SGuanzhong Chen }
9295204f761SGuanzhong Chen 
9302dad4e2cSSam Clegg // Create ABI-defined synthetic symbols
9312dad4e2cSSam Clegg static void createSyntheticSymbols() {
932*3792b362SFangrui Song   if (ctx.arg.relocatable)
933dbfea282SSam Clegg     return;
934dbfea282SSam Clegg 
935136d27abSRui Ueyama   static WasmSignature nullSignature = {{}, {}};
93642bba4b8SGuanzhong Chen   static WasmSignature i32ArgSignature = {{}, {ValType::I32}};
937b9a539c0SWouter van Oortmerssen   static WasmSignature i64ArgSignature = {{}, {ValType::I64}};
938136d27abSRui Ueyama   static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false};
939b9a539c0SWouter van Oortmerssen   static llvm::wasm::WasmGlobalType globalTypeI64 = {WASM_TYPE_I64, false};
940136d27abSRui Ueyama   static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32,
9412dad4e2cSSam Clegg                                                             true};
942b9a539c0SWouter van Oortmerssen   static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,
943b9a539c0SWouter van Oortmerssen                                                             true};
944136d27abSRui Ueyama   WasmSym::callCtors = symtab->addSyntheticFunction(
9452dad4e2cSSam Clegg       "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
946136d27abSRui Ueyama       make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
9472dad4e2cSSam Clegg 
948*3792b362SFangrui Song   bool is64 = ctx.arg.is64.value_or(false);
9494157b603SWouter van Oortmerssen 
950184c22ddSSam Clegg   if (ctx.isPic) {
95129f8c9f6SWouter van Oortmerssen     WasmSym::stackPointer =
952*3792b362SFangrui Song         createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)
95329f8c9f6SWouter van Oortmerssen                                                      ? &mutableGlobalTypeI64
95429f8c9f6SWouter van Oortmerssen                                                      : &mutableGlobalTypeI32);
955fd11ce32SSam Clegg     // For PIC code, we import two global variables (__memory_base and
956fd11ce32SSam Clegg     // __table_base) from the environment and use these as the offset at
957fd11ce32SSam Clegg     // which to load our static data and function table.
958fd11ce32SSam Clegg     // See:
959c71fbdd8SQuinn Pham     // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
9603a293cbfSWouter van Oortmerssen     auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
9613a293cbfSWouter van Oortmerssen     WasmSym::memoryBase = createUndefinedGlobal("__memory_base", globalType);
9623a293cbfSWouter van Oortmerssen     WasmSym::tableBase = createUndefinedGlobal("__table_base", globalType);
963fd11ce32SSam Clegg     WasmSym::memoryBase->markLive();
964fd11ce32SSam Clegg     WasmSym::tableBase->markLive();
9652dad4e2cSSam Clegg   } else {
9662dad4e2cSSam Clegg     // For non-PIC code
96729a3056bSSam Clegg     WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true);
968ad1cc145SSam Clegg     WasmSym::stackPointer->markLive();
9692dad4e2cSSam Clegg   }
9702dad4e2cSSam Clegg 
971*3792b362SFangrui Song   if (ctx.arg.sharedMemory) {
97229a3056bSSam Clegg     WasmSym::tlsBase = createGlobalVariable("__tls_base", true);
97329a3056bSSam Clegg     WasmSym::tlsSize = createGlobalVariable("__tls_size", false);
97429a3056bSSam Clegg     WasmSym::tlsAlign = createGlobalVariable("__tls_align", false);
97542bba4b8SGuanzhong Chen     WasmSym::initTLS = symtab->addSyntheticFunction(
97642bba4b8SGuanzhong Chen         "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,
97729f8c9f6SWouter van Oortmerssen         make<SyntheticFunction>(
9784157b603SWouter van Oortmerssen             is64 ? i64ArgSignature : i32ArgSignature,
979b9a539c0SWouter van Oortmerssen             "__wasm_init_tls"));
98042bba4b8SGuanzhong Chen   }
981caa0db13SSam Clegg }
98242bba4b8SGuanzhong Chen 
983caa0db13SSam Clegg static void createOptionalSymbols() {
984*3792b362SFangrui Song   if (ctx.arg.relocatable)
985dbfea282SSam Clegg     return;
986dbfea282SSam Clegg 
987caa0db13SSam Clegg   WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
988caa0db13SSam Clegg 
989*3792b362SFangrui Song   if (!ctx.arg.shared)
990caa0db13SSam Clegg     WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
991c5ccbf52SGuanzhong Chen 
992184c22ddSSam Clegg   if (!ctx.isPic) {
9931532be98SSam Clegg     WasmSym::stackLow = symtab->addOptionalDataSymbol("__stack_low");
9941532be98SSam Clegg     WasmSym::stackHigh = symtab->addOptionalDataSymbol("__stack_high");
995caa0db13SSam Clegg     WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base");
996caa0db13SSam Clegg     WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
9974b24e9beSDan Gohman     WasmSym::heapEnd = symtab->addOptionalDataSymbol("__heap_end");
9987185a730SSam Clegg     WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
9997185a730SSam Clegg     WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base");
1000caa0db13SSam Clegg   }
100129a3056bSSam Clegg 
100229a3056bSSam Clegg   // For non-shared memory programs we still need to define __tls_base since we
100329a3056bSSam Clegg   // allow object files built with TLS to be linked into single threaded
10049f903475SNico Weber   // programs, and such object files can contain references to this symbol.
100529a3056bSSam Clegg   //
100629a3056bSSam Clegg   // However, in this case __tls_base is immutable and points directly to the
100729a3056bSSam Clegg   // start of the `.tdata` static segment.
100829a3056bSSam Clegg   //
100929a3056bSSam Clegg   // __tls_size and __tls_align are not needed in this case since they are only
101029a3056bSSam Clegg   // needed for __wasm_init_tls (which we do not create in this case).
1011*3792b362SFangrui Song   if (!ctx.arg.sharedMemory)
101229a3056bSSam Clegg     WasmSym::tlsBase = createOptionalGlobal("__tls_base", false);
10132dad4e2cSSam Clegg }
10142dad4e2cSSam Clegg 
1015d43f0889SSam Clegg static void processStubLibrariesPreLTO() {
1016d43f0889SSam Clegg   log("-- processStubLibrariesPreLTO");
10173c584570SSam Clegg   for (auto &stub_file : ctx.stubFiles) {
1018d43f0889SSam Clegg     LLVM_DEBUG(llvm::dbgs()
1019d43f0889SSam Clegg                << "processing stub file: " << stub_file->getName() << "\n");
1020d43f0889SSam Clegg     for (auto [name, deps]: stub_file->symbolDependencies) {
1021d43f0889SSam Clegg       auto* sym = symtab->find(name);
1022d43f0889SSam Clegg       // If the symbol is not present at all (yet), or if it is present but
1023d43f0889SSam Clegg       // undefined, then mark the dependent symbols as used by a regular
1024d43f0889SSam Clegg       // object so they will be preserved and exported by the LTO process.
1025d43f0889SSam Clegg       if (!sym || sym->isUndefined()) {
1026d43f0889SSam Clegg         for (const auto dep : deps) {
1027d43f0889SSam Clegg           auto* needed = symtab->find(dep);
1028d43f0889SSam Clegg           if (needed ) {
1029d43f0889SSam Clegg             needed->isUsedInRegularObj = true;
1030e7efa323SSam Clegg             // Like with handleLibcall we have to extract any LTO archive
1031e7efa323SSam Clegg             // members that might need to be exported due to stub library
1032e7efa323SSam Clegg             // symbols being referenced.  Without this the LTO object could be
1033e7efa323SSam Clegg             // extracted during processStubLibraries, which is too late since
1034e7efa323SSam Clegg             // LTO has already being performed at that point.
1035e7efa323SSam Clegg             if (needed->isLazy() && isa<BitcodeFile>(needed->getFile())) {
1036*3792b362SFangrui Song               if (!ctx.arg.whyExtract.empty())
1037e7efa323SSam Clegg                 ctx.whyExtractRecords.emplace_back(toString(stub_file),
1038e7efa323SSam Clegg                                                    needed->getFile(), *needed);
1039e7efa323SSam Clegg               cast<LazySymbol>(needed)->extract();
1040e7efa323SSam Clegg             }
1041d43f0889SSam Clegg           }
1042d43f0889SSam Clegg         }
1043d43f0889SSam Clegg       }
1044d43f0889SSam Clegg     }
1045d43f0889SSam Clegg   }
1046d43f0889SSam Clegg }
1047d43f0889SSam Clegg 
1048afb3f7e0SSam Clegg static bool addStubSymbolDeps(const StubFile *stub_file, Symbol *sym,
1049afb3f7e0SSam Clegg                               ArrayRef<StringRef> deps) {
10503111784fSSam Clegg   // The first stub library to define a given symbol sets this and
10513111784fSSam Clegg   // definitions in later stub libraries are ignored.
1052d43f0889SSam Clegg   if (sym->forceImport)
1053afb3f7e0SSam Clegg     return false; // Already handled
10543111784fSSam Clegg   sym->forceImport = true;
10553111784fSSam Clegg   if (sym->traced)
1056afb3f7e0SSam Clegg     message(toString(stub_file) + ": importing " + sym->getName());
10573111784fSSam Clegg   else
1058afb3f7e0SSam Clegg     LLVM_DEBUG(llvm::dbgs() << toString(stub_file) << ": importing "
1059afb3f7e0SSam Clegg                             << sym->getName() << "\n");
1060afb3f7e0SSam Clegg   bool depsAdded = false;
10613111784fSSam Clegg   for (const auto dep : deps) {
10623111784fSSam Clegg     auto *needed = symtab->find(dep);
10633111784fSSam Clegg     if (!needed) {
10643111784fSSam Clegg       error(toString(stub_file) + ": undefined symbol: " + dep +
10653111784fSSam Clegg             ". Required by " + toString(*sym));
10663111784fSSam Clegg     } else if (needed->isUndefined()) {
1067afb3f7e0SSam Clegg       error(toString(stub_file) + ": undefined symbol: " + toString(*needed) +
10683111784fSSam Clegg             ". Required by " + toString(*sym));
10693111784fSSam Clegg     } else {
1070aca110f9SSam Clegg       if (needed->traced)
1071aca110f9SSam Clegg         message(toString(stub_file) + ": exported " + toString(*needed) +
1072afb3f7e0SSam Clegg                 " due to import of " + sym->getName());
1073aca110f9SSam Clegg       else
10743111784fSSam Clegg         LLVM_DEBUG(llvm::dbgs()
10753111784fSSam Clegg                    << "force export: " << toString(*needed) << "\n");
10763111784fSSam Clegg       needed->forceExport = true;
10773111784fSSam Clegg       if (auto *lazy = dyn_cast<LazySymbol>(needed)) {
10787a8ee92fSSam Clegg         depsAdded = true;
1079f2684959SSam Clegg         lazy->extract();
1080*3792b362SFangrui Song         if (!ctx.arg.whyExtract.empty())
1081afb3f7e0SSam Clegg           ctx.whyExtractRecords.emplace_back(toString(stub_file),
10823111784fSSam Clegg                                              sym->getFile(), *sym);
10833111784fSSam Clegg       }
10843111784fSSam Clegg     }
10853111784fSSam Clegg   }
1086afb3f7e0SSam Clegg   return depsAdded;
1087afb3f7e0SSam Clegg }
1088afb3f7e0SSam Clegg 
1089afb3f7e0SSam Clegg static void processStubLibraries() {
1090afb3f7e0SSam Clegg   log("-- processStubLibraries");
1091afb3f7e0SSam Clegg   bool depsAdded = false;
1092afb3f7e0SSam Clegg   do {
1093afb3f7e0SSam Clegg     depsAdded = false;
1094afb3f7e0SSam Clegg     for (auto &stub_file : ctx.stubFiles) {
1095afb3f7e0SSam Clegg       LLVM_DEBUG(llvm::dbgs()
1096afb3f7e0SSam Clegg                  << "processing stub file: " << stub_file->getName() << "\n");
1097afb3f7e0SSam Clegg 
1098afb3f7e0SSam Clegg       // First look for any imported symbols that directly match
1099afb3f7e0SSam Clegg       // the names of the stub imports
1100afb3f7e0SSam Clegg       for (auto [name, deps]: stub_file->symbolDependencies) {
1101afb3f7e0SSam Clegg         auto* sym = symtab->find(name);
1102afb3f7e0SSam Clegg         if (sym && sym->isUndefined()) {
1103afb3f7e0SSam Clegg           depsAdded |= addStubSymbolDeps(stub_file, sym, deps);
1104afb3f7e0SSam Clegg         } else {
1105afb3f7e0SSam Clegg           if (sym && sym->traced)
1106afb3f7e0SSam Clegg             message(toString(stub_file) + ": stub symbol not needed: " + name);
1107afb3f7e0SSam Clegg           else
1108afb3f7e0SSam Clegg             LLVM_DEBUG(llvm::dbgs()
1109afb3f7e0SSam Clegg                        << "stub symbol not needed: `" << name << "`\n");
1110afb3f7e0SSam Clegg         }
1111afb3f7e0SSam Clegg       }
1112afb3f7e0SSam Clegg 
1113afb3f7e0SSam Clegg       // Secondly looks for any symbols with an `importName` that matches
1114afb3f7e0SSam Clegg       for (Symbol *sym : symtab->symbols()) {
1115afb3f7e0SSam Clegg         if (sym->isUndefined() && sym->importName.has_value()) {
1116afb3f7e0SSam Clegg           auto it = stub_file->symbolDependencies.find(sym->importName.value());
1117afb3f7e0SSam Clegg           if (it != stub_file->symbolDependencies.end()) {
1118afb3f7e0SSam Clegg             depsAdded |= addStubSymbolDeps(stub_file, sym, it->second);
1119afb3f7e0SSam Clegg           }
1120afb3f7e0SSam Clegg         }
11213111784fSSam Clegg       }
11223111784fSSam Clegg     }
11237a8ee92fSSam Clegg   } while (depsAdded);
11247a8ee92fSSam Clegg 
11253111784fSSam Clegg   log("-- done processStubLibraries");
11263111784fSSam Clegg }
11273111784fSSam Clegg 
112835150bb5SRui Ueyama // Reconstructs command line arguments so that so that you can re-run
112935150bb5SRui Ueyama // the same command with the same inputs. This is for --reproduce.
1130136d27abSRui Ueyama static std::string createResponseFile(const opt::InputArgList &args) {
1131136d27abSRui Ueyama   SmallString<0> data;
1132136d27abSRui Ueyama   raw_svector_ostream os(data);
113335150bb5SRui Ueyama 
113435150bb5SRui Ueyama   // Copy the command line to the output while rewriting paths.
1135136d27abSRui Ueyama   for (auto *arg : args) {
1136136d27abSRui Ueyama     switch (arg->getOption().getID()) {
113735150bb5SRui Ueyama     case OPT_reproduce:
113835150bb5SRui Ueyama       break;
113935150bb5SRui Ueyama     case OPT_INPUT:
1140136d27abSRui Ueyama       os << quote(relativeToRoot(arg->getValue())) << "\n";
114135150bb5SRui Ueyama       break;
114235150bb5SRui Ueyama     case OPT_o:
114335150bb5SRui Ueyama       // If -o path contains directories, "lld @response.txt" will likely
114435150bb5SRui Ueyama       // fail because the archive we are creating doesn't contain empty
114535150bb5SRui Ueyama       // directories for the output path (-o doesn't create directories).
114635150bb5SRui Ueyama       // Strip directories to prevent the issue.
1147136d27abSRui Ueyama       os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n";
114835150bb5SRui Ueyama       break;
114935150bb5SRui Ueyama     default:
1150136d27abSRui Ueyama       os << toString(*arg) << "\n";
115135150bb5SRui Ueyama     }
115235150bb5SRui Ueyama   }
115321730eb4SKazu Hirata   return std::string(data);
115435150bb5SRui Ueyama }
115535150bb5SRui Ueyama 
1156a5ca34e6SSam Clegg // The --wrap option is a feature to rename symbols so that you can write
1157a5ca34e6SSam Clegg // wrappers for existing functions. If you pass `-wrap=foo`, all
1158a5ca34e6SSam Clegg // occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
1159a5ca34e6SSam Clegg // expected to write `wrap_foo` function as a wrapper). The original
1160a5ca34e6SSam Clegg // symbol becomes accessible as `real_foo`, so you can call that from your
1161a5ca34e6SSam Clegg // wrapper.
1162a5ca34e6SSam Clegg //
1163a5ca34e6SSam Clegg // This data structure is instantiated for each -wrap option.
1164a5ca34e6SSam Clegg struct WrappedSymbol {
1165136d27abSRui Ueyama   Symbol *sym;
1166136d27abSRui Ueyama   Symbol *real;
1167136d27abSRui Ueyama   Symbol *wrap;
1168a5ca34e6SSam Clegg };
1169a5ca34e6SSam Clegg 
1170136d27abSRui Ueyama static Symbol *addUndefined(StringRef name) {
1171c68af42fSKazu Hirata   return symtab->addUndefinedFunction(name, std::nullopt, std::nullopt,
1172c68af42fSKazu Hirata                                       WASM_SYMBOL_UNDEFINED, nullptr, nullptr,
1173c68af42fSKazu Hirata                                       false);
1174a5ca34e6SSam Clegg }
1175a5ca34e6SSam Clegg 
1176a5ca34e6SSam Clegg // Handles -wrap option.
1177a5ca34e6SSam Clegg //
1178a5ca34e6SSam Clegg // This function instantiates wrapper symbols. At this point, they seem
1179a5ca34e6SSam Clegg // like they are not being used at all, so we explicitly set some flags so
1180a5ca34e6SSam Clegg // that LTO won't eliminate them.
1181136d27abSRui Ueyama static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
1182136d27abSRui Ueyama   std::vector<WrappedSymbol> v;
1183136d27abSRui Ueyama   DenseSet<StringRef> seen;
1184a5ca34e6SSam Clegg 
1185136d27abSRui Ueyama   for (auto *arg : args.filtered(OPT_wrap)) {
1186136d27abSRui Ueyama     StringRef name = arg->getValue();
1187136d27abSRui Ueyama     if (!seen.insert(name).second)
1188a5ca34e6SSam Clegg       continue;
1189a5ca34e6SSam Clegg 
1190136d27abSRui Ueyama     Symbol *sym = symtab->find(name);
1191136d27abSRui Ueyama     if (!sym)
1192a5ca34e6SSam Clegg       continue;
1193a5ca34e6SSam Clegg 
119483d59e05SAlexandre Ganea     Symbol *real = addUndefined(saver().save("__real_" + name));
119583d59e05SAlexandre Ganea     Symbol *wrap = addUndefined(saver().save("__wrap_" + name));
1196136d27abSRui Ueyama     v.push_back({sym, real, wrap});
1197a5ca34e6SSam Clegg 
1198a5ca34e6SSam Clegg     // We want to tell LTO not to inline symbols to be overwritten
1199a5ca34e6SSam Clegg     // because LTO doesn't know the final symbol contents after renaming.
1200136d27abSRui Ueyama     real->canInline = false;
1201136d27abSRui Ueyama     sym->canInline = false;
1202a5ca34e6SSam Clegg 
1203a5ca34e6SSam Clegg     // Tell LTO not to eliminate these symbols.
1204136d27abSRui Ueyama     sym->isUsedInRegularObj = true;
1205136d27abSRui Ueyama     wrap->isUsedInRegularObj = true;
1206136d27abSRui Ueyama     real->isUsedInRegularObj = false;
1207a5ca34e6SSam Clegg   }
1208136d27abSRui Ueyama   return v;
1209a5ca34e6SSam Clegg }
1210a5ca34e6SSam Clegg 
1211a5ca34e6SSam Clegg // Do renaming for -wrap by updating pointers to symbols.
1212a5ca34e6SSam Clegg //
1213a5ca34e6SSam Clegg // When this function is executed, only InputFiles and symbol table
1214a5ca34e6SSam Clegg // contain pointers to symbol objects. We visit them to replace pointers,
1215a5ca34e6SSam Clegg // so that wrapped symbols are swapped as instructed by the command line.
1216136d27abSRui Ueyama static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
1217136d27abSRui Ueyama   DenseMap<Symbol *, Symbol *> map;
1218136d27abSRui Ueyama   for (const WrappedSymbol &w : wrapped) {
1219136d27abSRui Ueyama     map[w.sym] = w.wrap;
1220136d27abSRui Ueyama     map[w.real] = w.sym;
1221a5ca34e6SSam Clegg   }
1222a5ca34e6SSam Clegg 
1223a5ca34e6SSam Clegg   // Update pointers in input files.
12243c584570SSam Clegg   parallelForEach(ctx.objectFiles, [&](InputFile *file) {
1225136d27abSRui Ueyama     MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
1226136d27abSRui Ueyama     for (size_t i = 0, e = syms.size(); i != e; ++i)
1227136d27abSRui Ueyama       if (Symbol *s = map.lookup(syms[i]))
1228136d27abSRui Ueyama         syms[i] = s;
1229a5ca34e6SSam Clegg   });
1230a5ca34e6SSam Clegg 
1231a5ca34e6SSam Clegg   // Update pointers in the symbol table.
1232136d27abSRui Ueyama   for (const WrappedSymbol &w : wrapped)
1233136d27abSRui Ueyama     symtab->wrap(w.sym, w.real, w.wrap);
1234a5ca34e6SSam Clegg }
1235a5ca34e6SSam Clegg 
12363b8d2be5SSam Clegg static void splitSections() {
123745b7cf99SSam Clegg   // splitIntoPieces needs to be called on each MergeInputChunk
12383b8d2be5SSam Clegg   // before calling finalizeContents().
12393b8d2be5SSam Clegg   LLVM_DEBUG(llvm::dbgs() << "splitSections\n");
12403c584570SSam Clegg   parallelForEach(ctx.objectFiles, [](ObjFile *file) {
12415a9b25e1SSam Clegg     for (InputChunk *seg : file->segments) {
12425a9b25e1SSam Clegg       if (auto *s = dyn_cast<MergeInputChunk>(seg))
12433b8d2be5SSam Clegg         s->splitIntoPieces();
12443b8d2be5SSam Clegg     }
124545b7cf99SSam Clegg     for (InputChunk *sec : file->customSections) {
124645b7cf99SSam Clegg       if (auto *s = dyn_cast<MergeInputChunk>(sec))
124745b7cf99SSam Clegg         s->splitIntoPieces();
124845b7cf99SSam Clegg     }
12493b8d2be5SSam Clegg   });
12503b8d2be5SSam Clegg }
12513b8d2be5SSam Clegg 
1252faab70b7SSam Clegg static bool isKnownZFlag(StringRef s) {
1253faab70b7SSam Clegg   // For now, we only support a very limited set of -z flags
12540367305aSmzukovec   return s.starts_with("stack-size=") || s.starts_with("muldefs");
1255faab70b7SSam Clegg }
1256faab70b7SSam Clegg 
1257faab70b7SSam Clegg // Report a warning for an unknown -z option.
1258faab70b7SSam Clegg static void checkZOptions(opt::InputArgList &args) {
1259faab70b7SSam Clegg   for (auto *arg : args.filtered(OPT_z))
1260faab70b7SSam Clegg     if (!isKnownZFlag(arg->getValue()))
1261faab70b7SSam Clegg       warn("unknown -z value: " + StringRef(arg->getValue()));
1262faab70b7SSam Clegg }
1263faab70b7SSam Clegg 
1264a222d00cSFangrui Song LinkerDriver::LinkerDriver(Ctx &ctx) : ctx(ctx) {}
1265a222d00cSFangrui Song 
1266fdd6ed8eSReshabh Sharma void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
1267136d27abSRui Ueyama   WasmOptTable parser;
1268136d27abSRui Ueyama   opt::InputArgList args = parser.parse(argsArr.slice(1));
1269d5f65063SSam Clegg 
1270faab70b7SSam Clegg   // Interpret these flags early because error()/warn() depend on them.
1271fcb6b132SFangrui Song   auto &errHandler = errorHandler();
1272fcb6b132SFangrui Song   errHandler.errorLimit = args::getInteger(args, OPT_error_limit, 20);
1273fcb6b132SFangrui Song   errHandler.fatalWarnings =
1274faab70b7SSam Clegg       args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
1275faab70b7SSam Clegg   checkZOptions(args);
1276faab70b7SSam Clegg 
1277d5f65063SSam Clegg   // Handle --help
1278136d27abSRui Ueyama   if (args.hasArg(OPT_help)) {
1279fcb6b132SFangrui Song     parser.printHelp(errHandler.outs(),
1280136d27abSRui Ueyama                      (std::string(argsArr[0]) + " [options] file...").c_str(),
1281d5f65063SSam Clegg                      "LLVM Linker", false);
1282d5f65063SSam Clegg     return;
1283d5f65063SSam Clegg   }
1284d5f65063SSam Clegg 
12850764e55cSSam Clegg   // Handle -v or -version.
12860764e55cSSam Clegg   if (args.hasArg(OPT_v) || args.hasArg(OPT_version))
1287fcb6b132SFangrui Song     errHandler.outs() << getLLDVersion() << "\n";
1288d5f65063SSam Clegg 
128935150bb5SRui Ueyama   // Handle --reproduce
12903c28a6d2SSam Clegg   if (const char *path = getReproduceOption(args)) {
1291136d27abSRui Ueyama     Expected<std::unique_ptr<TarWriter>> errOrWriter =
1292136d27abSRui Ueyama         TarWriter::create(path, path::stem(path));
1293136d27abSRui Ueyama     if (errOrWriter) {
1294136d27abSRui Ueyama       tar = std::move(*errOrWriter);
1295136d27abSRui Ueyama       tar->append("response.txt", createResponseFile(args));
1296136d27abSRui Ueyama       tar->append("version.txt", getLLDVersion() + "\n");
129735150bb5SRui Ueyama     } else {
1298136d27abSRui Ueyama       error("--reproduce: " + toString(errOrWriter.takeError()));
129935150bb5SRui Ueyama     }
130035150bb5SRui Ueyama   }
130135150bb5SRui Ueyama 
1302d5f65063SSam Clegg   // Parse and evaluate -mllvm options.
1303136d27abSRui Ueyama   std::vector<const char *> v;
1304136d27abSRui Ueyama   v.push_back("wasm-ld (LLVM option parsing)");
1305136d27abSRui Ueyama   for (auto *arg : args.filtered(OPT_mllvm))
1306136d27abSRui Ueyama     v.push_back(arg->getValue());
1307f2efb574SAlexandre Ganea   cl::ResetAllOptionOccurrences();
1308136d27abSRui Ueyama   cl::ParseCommandLineOptions(v.size(), v.data());
1309d5f65063SSam Clegg 
1310136d27abSRui Ueyama   readConfigs(args);
13110a9756fcSSam Clegg   setConfigs();
1312b5767010SSam Clegg 
13130764e55cSSam Clegg   // The behavior of -v or --version is a bit strange, but this is
13140764e55cSSam Clegg   // needed for compatibility with GNU linkers.
13150764e55cSSam Clegg   if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT))
13160764e55cSSam Clegg     return;
13170764e55cSSam Clegg   if (args.hasArg(OPT_version))
13180764e55cSSam Clegg     return;
13190764e55cSSam Clegg 
1320b5767010SSam Clegg   createFiles(args);
1321b5767010SSam Clegg   if (errorCount())
1322b5767010SSam Clegg     return;
1323b5767010SSam Clegg 
1324136d27abSRui Ueyama   checkOptions(args);
1325b5767010SSam Clegg   if (errorCount())
1326b5767010SSam Clegg     return;
1327d5f65063SSam Clegg 
1328136d27abSRui Ueyama   if (auto *arg = args.getLastArg(OPT_allow_undefined_file))
1329136d27abSRui Ueyama     readImportFile(arg->getValue());
1330d5f65063SSam Clegg 
1331b5767010SSam Clegg   // Fail early if the output file or map file is not writable. If a user has a
1332b5767010SSam Clegg   // long link, e.g. due to a large LTO link, they do not wish to run it and
1333b5767010SSam Clegg   // find that it failed because there was a mistake in their command-line.
1334a222d00cSFangrui Song   if (auto e = tryCreateFile(ctx.arg.outputFile))
1335a222d00cSFangrui Song     error("cannot open output file " + ctx.arg.outputFile + ": " + e.message());
1336a222d00cSFangrui Song   if (auto e = tryCreateFile(ctx.arg.mapFile))
1337a222d00cSFangrui Song     error("cannot open map file " + ctx.arg.mapFile + ": " + e.message());
1338b5767010SSam Clegg   if (errorCount())
1339d5f65063SSam Clegg     return;
1340c94d393aSSam Clegg 
13411f3f774fSSam Clegg   // Handle --trace-symbol.
1342136d27abSRui Ueyama   for (auto *arg : args.filtered(OPT_trace_symbol))
1343136d27abSRui Ueyama     symtab->trace(arg->getValue());
13441f3f774fSSam Clegg 
1345a6f40648SSam Clegg   for (auto *arg : args.filtered(OPT_export_if_defined))
1346a222d00cSFangrui Song     ctx.arg.exportedSymbols.insert(arg->getValue());
13477d4ec5afSSam Clegg 
1348a6f40648SSam Clegg   for (auto *arg : args.filtered(OPT_export)) {
1349a222d00cSFangrui Song     ctx.arg.exportedSymbols.insert(arg->getValue());
1350a222d00cSFangrui Song     ctx.arg.requiredExports.push_back(arg->getValue());
1351a6f40648SSam Clegg   }
1352a6f40648SSam Clegg 
13532dad4e2cSSam Clegg   createSyntheticSymbols();
1354c94d393aSSam Clegg 
1355c94d393aSSam Clegg   // Add all files to the symbol table. This will add almost all
1356c94d393aSSam Clegg   // symbols that we need to the symbol table.
1357136d27abSRui Ueyama   for (InputFile *f : files)
1358136d27abSRui Ueyama     symtab->addFile(f);
1359c729c1b4SSam Clegg   if (errorCount())
1360c729c1b4SSam Clegg     return;
1361c94d393aSSam Clegg 
136247e2b6b2SSam Clegg   // Handle the `--undefined <sym>` options.
1363136d27abSRui Ueyama   for (auto *arg : args.filtered(OPT_undefined))
13648aef04faSSam Clegg     handleUndefined(arg->getValue(), "<internal>");
136547e2b6b2SSam Clegg 
13667d4ec5afSSam Clegg   // Handle the `--export <sym>` options
13677d4ec5afSSam Clegg   // This works like --undefined but also exports the symbol if its found
1368a222d00cSFangrui Song   for (auto &iter : ctx.arg.exportedSymbols)
13698aef04faSSam Clegg     handleUndefined(iter.first(), "--export");
13707d4ec5afSSam Clegg 
1371136d27abSRui Ueyama   Symbol *entrySym = nullptr;
1372a222d00cSFangrui Song   if (!ctx.arg.relocatable && !ctx.arg.entry.empty()) {
1373a222d00cSFangrui Song     entrySym = handleUndefined(ctx.arg.entry, "--entry");
1374136d27abSRui Ueyama     if (entrySym && entrySym->isDefined())
1375136d27abSRui Ueyama       entrySym->forceExport = true;
1376305b0343SSam Clegg     else
13777c5fcb35SKazuaki Ishizaki       error("entry symbol not defined (pass --no-entry to suppress): " +
1378a222d00cSFangrui Song             ctx.arg.entry);
137947e2b6b2SSam Clegg   }
138047e2b6b2SSam Clegg 
13816cd8511eSDan Gohman   // If the user code defines a `__wasm_call_dtors` function, remember it so
13826cd8511eSDan Gohman   // that we can call it from the command export wrappers. Unlike
13836cd8511eSDan Gohman   // `__wasm_call_ctors` which we synthesize, `__wasm_call_dtors` is defined
13846cd8511eSDan Gohman   // by libc/etc., because destructors are registered dynamically with
13856cd8511eSDan Gohman   // `__cxa_atexit` and friends.
1386a222d00cSFangrui Song   if (!ctx.arg.relocatable && !ctx.arg.shared &&
13876cd8511eSDan Gohman       !WasmSym::callCtors->isUsedInRegularObj &&
1388a222d00cSFangrui Song       WasmSym::callCtors->getName() != ctx.arg.entry &&
1389a222d00cSFangrui Song       !ctx.arg.exportedSymbols.count(WasmSym::callCtors->getName())) {
13908aef04faSSam Clegg     if (Symbol *callDtors =
13918aef04faSSam Clegg             handleUndefined("__wasm_call_dtors", "<internal>")) {
13926cd8511eSDan Gohman       if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {
13936cd8511eSDan Gohman         if (callDtorsFunc->signature &&
13946cd8511eSDan Gohman             (!callDtorsFunc->signature->Params.empty() ||
13956cd8511eSDan Gohman              !callDtorsFunc->signature->Returns.empty())) {
13966cd8511eSDan Gohman           error("__wasm_call_dtors must have no argument or return values");
13976cd8511eSDan Gohman         }
13986cd8511eSDan Gohman         WasmSym::callDtors = callDtorsFunc;
13996cd8511eSDan Gohman       } else {
14006cd8511eSDan Gohman         error("__wasm_call_dtors must be a function");
14016cd8511eSDan Gohman       }
14026cd8511eSDan Gohman     }
14036cd8511eSDan Gohman   }
14046cd8511eSDan Gohman 
140547e2b6b2SSam Clegg   if (errorCount())
140647e2b6b2SSam Clegg     return;
140747e2b6b2SSam Clegg 
1408a5ca34e6SSam Clegg   // Create wrapped symbols for -wrap option.
1409136d27abSRui Ueyama   std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
1410a5ca34e6SSam Clegg 
14119cd98581SSam Clegg   // If any of our inputs are bitcode files, the LTO code generator may create
14129cd98581SSam Clegg   // references to certain library functions that might not be explicit in the
14139cd98581SSam Clegg   // bitcode file's symbol table. If any of those library functions are defined
14149cd98581SSam Clegg   // in a bitcode file in an archive member, we need to arrange to use LTO to
14159cd98581SSam Clegg   // compile those archive members by adding them to the link beforehand.
14169cd98581SSam Clegg   //
14179cd98581SSam Clegg   // We only need to add libcall symbols to the link before LTO if the symbol's
14189cd98581SSam Clegg   // definition is in bitcode. Any other required libcall symbols will be added
14199cd98581SSam Clegg   // to the link after LTO when we add the LTO object file to the link.
1420615b7eeaSJoseph Huber   if (!ctx.bitcodeFiles.empty()) {
1421615b7eeaSJoseph Huber     llvm::Triple TT(ctx.bitcodeFiles.front()->obj->getTargetTriple());
1422615b7eeaSJoseph Huber     for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))
14239cd98581SSam Clegg       handleLibcall(s);
1424615b7eeaSJoseph Huber   }
14259cd98581SSam Clegg   if (errorCount())
14269cd98581SSam Clegg     return;
14279cd98581SSam Clegg 
1428d43f0889SSam Clegg   // We process the stub libraries once beofore LTO to ensure that any possible
1429d43f0889SSam Clegg   // required exports are preserved by the LTO process.
1430d43f0889SSam Clegg   processStubLibrariesPreLTO();
14318aef04faSSam Clegg 
1432c729c1b4SSam Clegg   // Do link-time optimization if given files are LLVM bitcode files.
1433c729c1b4SSam Clegg   // This compiles bitcode files into real object files.
14344da38c14SSam Clegg   symtab->compileBitcodeFiles();
1435c729c1b4SSam Clegg   if (errorCount())
1436c729c1b4SSam Clegg     return;
1437c729c1b4SSam Clegg 
14382ea8a3a5SSam Clegg   // The LTO process can generate new undefined symbols, specifically libcall
14392ea8a3a5SSam Clegg   // functions.  Because those symbols might be declared in a stub library we
1440d43f0889SSam Clegg   // need the process the stub libraries once again after LTO to handle all
1441d43f0889SSam Clegg   // undefined symbols, including ones that didn't exist prior to LTO.
14423111784fSSam Clegg   processStubLibraries();
14433111784fSSam Clegg 
14442ea8a3a5SSam Clegg   writeWhyExtract();
14452ea8a3a5SSam Clegg 
14469a450a00SSam Clegg   // Bail out if normal linked output is skipped due to LTO.
1447a222d00cSFangrui Song   if (ctx.arg.thinLTOIndexOnly)
14489a450a00SSam Clegg     return;
14499a450a00SSam Clegg 
14508fe12847SSam Clegg   createOptionalSymbols();
14518fe12847SSam Clegg 
14526540e570SSam Clegg   // Resolve any variant symbols that were created due to signature
14536540e570SSam Clegg   // mismatchs.
1454136d27abSRui Ueyama   symtab->handleSymbolVariants();
14556540e570SSam Clegg   if (errorCount())
14566540e570SSam Clegg     return;
14576540e570SSam Clegg 
1458a5ca34e6SSam Clegg   // Apply symbol renames for -wrap.
1459136d27abSRui Ueyama   if (!wrapped.empty())
1460136d27abSRui Ueyama     wrapSymbols(wrapped);
1461a5ca34e6SSam Clegg 
1462a222d00cSFangrui Song   for (auto &iter : ctx.arg.exportedSymbols) {
1463a6f40648SSam Clegg     Symbol *sym = symtab->find(iter.first());
1464136d27abSRui Ueyama     if (sym && sym->isDefined())
1465136d27abSRui Ueyama       sym->forceExport = true;
14666540e570SSam Clegg   }
14676540e570SSam Clegg 
1468a222d00cSFangrui Song   if (!ctx.arg.relocatable && !ctx.isPic) {
1469e320cea5SSam Clegg     // Add synthetic dummies for weak undefined functions.  Must happen
1470e320cea5SSam Clegg     // after LTO otherwise functions may not yet have signatures.
1471136d27abSRui Ueyama     symtab->handleWeakUndefines();
14726540e570SSam Clegg   }
14736540e570SSam Clegg 
1474136d27abSRui Ueyama   if (entrySym)
1475136d27abSRui Ueyama     entrySym->setHidden(false);
14760f0a4287SSam Clegg 
14772c096bacSSam Clegg   if (errorCount())
14782c096bacSSam Clegg     return;
1479c94d393aSSam Clegg 
14803b8d2be5SSam Clegg   // Split WASM_SEG_FLAG_STRINGS sections into pieces in preparation for garbage
14813b8d2be5SSam Clegg   // collection.
14823b8d2be5SSam Clegg   splitSections();
14833b8d2be5SSam Clegg 
1484b0f18af3SSam Clegg   // Any remaining lazy symbols should be demoted to Undefined
1485b0f18af3SSam Clegg   demoteLazySymbols();
1486b0f18af3SSam Clegg 
14870362633fSSam Clegg   // Do size optimizations: garbage collection
14880362633fSSam Clegg   markLive();
14890362633fSSam Clegg 
1490e638d8b2SAndy Wingo   // Provide the indirect function table if needed.
1491e638d8b2SAndy Wingo   WasmSym::indirectFunctionTable =
1492e638d8b2SAndy Wingo       symtab->resolveIndirectFunctionTable(/*required =*/false);
149363393828SAndy Wingo 
149463393828SAndy Wingo   if (errorCount())
149563393828SAndy Wingo     return;
149663393828SAndy Wingo 
1497c94d393aSSam Clegg   // Write the result to the file.
1498c94d393aSSam Clegg   writeResult();
1499c94d393aSSam Clegg }
150033c59abfSFangrui Song 
1501467cf154SCongcong Cai } // namespace lld::wasm
1502