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