1735 lines · cpp
1//===- Driver.cpp ---------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lld/Common/Driver.h"10#include "Config.h"11#include "InputChunks.h"12#include "InputElement.h"13#include "MarkLive.h"14#include "SymbolTable.h"15#include "Writer.h"16#include "lld/Common/Args.h"17#include "lld/Common/CommonLinkerContext.h"18#include "lld/Common/ErrorHandler.h"19#include "lld/Common/Filesystem.h"20#include "lld/Common/Memory.h"21#include "lld/Common/Reproduce.h"22#include "lld/Common/Strings.h"23#include "lld/Common/Version.h"24#include "llvm/ADT/Twine.h"25#include "llvm/Config/llvm-config.h"26#include "llvm/Option/Arg.h"27#include "llvm/Option/ArgList.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/Error.h"30#include "llvm/Support/GlobPattern.h"31#include "llvm/Support/Parallel.h"32#include "llvm/Support/Path.h"33#include "llvm/Support/Process.h"34#include "llvm/Support/TarWriter.h"35#include "llvm/Support/TargetSelect.h"36#include "llvm/TargetParser/Host.h"37#include <cctype>38#include <optional>39 40#define DEBUG_TYPE "lld"41 42using namespace llvm;43using namespace llvm::object;44using namespace llvm::opt;45using namespace llvm::sys;46using namespace llvm::wasm;47 48namespace lld::wasm {49Ctx ctx;50 51void errorOrWarn(const llvm::Twine &msg) {52 if (ctx.arg.noinhibitExec)53 warn(msg);54 else55 error(msg);56}57 58Ctx::Ctx() {}59 60void Ctx::reset() {61 arg.~Config();62 new (&arg) Config();63 objectFiles.clear();64 stubFiles.clear();65 sharedFiles.clear();66 bitcodeFiles.clear();67 lazyBitcodeFiles.clear();68 syntheticFunctions.clear();69 syntheticGlobals.clear();70 syntheticTables.clear();71 whyExtractRecords.clear();72 isPic = false;73 legacyFunctionTable = false;74 emitBssSegments = false;75 sym = WasmSym{};76}77 78namespace {79 80// Create enum with OPT_xxx values for each option in Options.td81enum {82 OPT_INVALID = 0,83#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),84#include "Options.inc"85#undef OPTION86};87 88// This function is called on startup. We need this for LTO since89// LTO calls LLVM functions to compile bitcode files to native code.90// Technically this can be delayed until we read bitcode files, but91// we don't bother to do lazily because the initialization is fast.92static void initLLVM() {93 InitializeAllTargets();94 InitializeAllTargetMCs();95 InitializeAllAsmPrinters();96 InitializeAllAsmParsers();97}98 99class LinkerDriver {100public:101 LinkerDriver(Ctx &);102 void linkerMain(ArrayRef<const char *> argsArr);103 104private:105 void createFiles(opt::InputArgList &args);106 void addFile(StringRef path);107 void addLibrary(StringRef name);108 109 Ctx &ctx;110 111 // True if we are in --whole-archive and --no-whole-archive.112 bool inWholeArchive = false;113 114 // True if we are in --start-lib and --end-lib.115 bool inLib = false;116 117 std::vector<InputFile *> files;118};119 120static bool hasZOption(opt::InputArgList &args, StringRef key) {121 bool ret = false;122 for (const auto *arg : args.filtered(OPT_z))123 if (key == arg->getValue()) {124 ret = true;125 arg->claim();126 }127 return ret;128}129} // anonymous namespace130 131bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,132 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {133 // This driver-specific context will be freed later by unsafeLldMain().134 auto *context = new CommonLinkerContext;135 136 context->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);137 context->e.cleanupCallback = []() { ctx.reset(); };138 context->e.logName = args::getFilenameWithoutExe(args[0]);139 context->e.errorLimitExceededMsg =140 "too many errors emitted, stopping now (use "141 "-error-limit=0 to see all errors)";142 143 symtab = make<SymbolTable>();144 145 initLLVM();146 LinkerDriver(ctx).linkerMain(args);147 148 return errorCount() == 0;149}150 151#define OPTTABLE_STR_TABLE_CODE152#include "Options.inc"153#undef OPTTABLE_STR_TABLE_CODE154 155#define OPTTABLE_PREFIXES_TABLE_CODE156#include "Options.inc"157#undef OPTTABLE_PREFIXES_TABLE_CODE158 159// Create table mapping all options defined in Options.td160static constexpr opt::OptTable::Info optInfo[] = {161#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \162 VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \163 VALUES, SUBCOMMANDIDS_OFFSET) \164 {PREFIX, \165 NAME, \166 HELPTEXT, \167 HELPTEXTSFORVARIANTS, \168 METAVAR, \169 OPT_##ID, \170 opt::Option::KIND##Class, \171 PARAM, \172 FLAGS, \173 VISIBILITY, \174 OPT_##GROUP, \175 OPT_##ALIAS, \176 ALIASARGS, \177 VALUES, \178 SUBCOMMANDIDS_OFFSET},179#include "Options.inc"180#undef OPTION181};182 183namespace {184class WasmOptTable : public opt::GenericOptTable {185public:186 WasmOptTable()187 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}188 opt::InputArgList parse(ArrayRef<const char *> argv);189};190} // namespace191 192// Set color diagnostics according to -color-diagnostics={auto,always,never}193// or -no-color-diagnostics flags.194static void handleColorDiagnostics(opt::InputArgList &args) {195 auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,196 OPT_no_color_diagnostics);197 if (!arg)198 return;199 auto &errs = errorHandler().errs();200 if (arg->getOption().getID() == OPT_color_diagnostics) {201 errs.enable_colors(true);202 } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {203 errs.enable_colors(false);204 } else {205 StringRef s = arg->getValue();206 if (s == "always")207 errs.enable_colors(true);208 else if (s == "never")209 errs.enable_colors(false);210 else if (s != "auto")211 error("unknown option: --color-diagnostics=" + s);212 }213}214 215static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {216 if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {217 StringRef s = arg->getValue();218 if (s != "windows" && s != "posix")219 error("invalid response file quoting: " + s);220 if (s == "windows")221 return cl::TokenizeWindowsCommandLine;222 return cl::TokenizeGNUCommandLine;223 }224 if (Triple(sys::getProcessTriple()).isOSWindows())225 return cl::TokenizeWindowsCommandLine;226 return cl::TokenizeGNUCommandLine;227}228 229// Find a file by concatenating given paths.230static std::optional<std::string> findFile(StringRef path1,231 const Twine &path2) {232 SmallString<128> s;233 path::append(s, path1, path2);234 if (fs::exists(s))235 return std::string(s);236 return std::nullopt;237}238 239opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) {240 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());241 242 unsigned missingIndex;243 unsigned missingCount;244 245 // We need to get the quoting style for response files before parsing all246 // options so we parse here before and ignore all the options but247 // --rsp-quoting.248 opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);249 250 // Expand response files (arguments in the form of @<filename>)251 // and then parse the argument again.252 cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec);253 args = this->ParseArgs(vec, missingIndex, missingCount);254 255 handleColorDiagnostics(args);256 if (missingCount)257 error(Twine(args.getArgString(missingIndex)) + ": missing argument");258 259 for (auto *arg : args.filtered(OPT_UNKNOWN))260 error("unknown argument: " + arg->getAsString(args));261 return args;262}263 264// Currently we allow a ".imports" to live alongside a library. This can265// be used to specify a list of symbols which can be undefined at link266// time (imported from the environment. For example libc.a include an267// import file that lists the syscall functions it relies on at runtime.268// In the long run this information would be better stored as a symbol269// attribute/flag in the object file itself.270// See: https://github.com/WebAssembly/tool-conventions/issues/35271static void readImportFile(StringRef filename) {272 if (std::optional<MemoryBufferRef> buf = readFile(filename))273 for (StringRef sym : args::getLines(*buf))274 ctx.arg.allowUndefinedSymbols.insert(sym);275}276 277static bool hasWildcard(StringRef s) {278 return s.find_first_of("?*[") != StringRef::npos;279}280 281// Strip surrounding double quotes, if present.282static StringRef unquoteVersion(StringRef s) {283 if (s.size() >= 2 && s.front() == '"' && s.back() == '"')284 return s.substr(1, s.size() - 2);285 return s;286}287 288// Record one symbol pattern from a version script into the right bucket.289// `*` is tracked specially as a fast all-match flag; other wildcards are290// compiled into GlobPatterns; everything else is an exact-name match.291static void addVersionPattern(StringRef tok, bool global) {292 StringRef name = unquoteVersion(tok);293 bool &all = global ? ctx.arg.versionGlobalAll : ctx.arg.versionLocalAll;294 auto &exact = global ? ctx.arg.versionGlobalExact : ctx.arg.versionLocalExact;295 auto &pats =296 global ? ctx.arg.versionGlobalPatterns : ctx.arg.versionLocalPatterns;297 298 if (name == "*") {299 all = true;300 return;301 }302 if (hasWildcard(name)) {303 Expected<GlobPattern> pat = GlobPattern::create(name);304 if (pat)305 pats.push_back(std::move(*pat));306 else {307 // Never silently drop a pattern; fall back to an exact match (so a308 // malformed glob can only over-export, never wrongly hide a symbol).309 handleAllErrors(pat.takeError(), [&](const ErrorInfoBase &e) {310 warn("version script: invalid pattern '" + name + "': " + e.message() +311 " (treated as a literal name)");312 });313 exact.insert(name);314 }315 return;316 }317 exact.insert(name);318}319 320// Parse a GNU version script for its export-visibility semantics only. We do321// not honor the version *tags* (wasm collapses symbol versioning); we only322// collect the global:/local: symbol sets. The grammar handled is the usual323// [TAG] { [global:] s; ... [local:] s; ... [extern "C[++]" { ... };] } [parent];324// including anonymous (tag-less) nodes. Tokens are whitespace/`{}`/`;`325// separated; `:` is kept as part of `global:`/`local:` keywords.326static void readVersionScript(MemoryBufferRef mb) {327 StringRef s = mb.getBuffer();328 size_t i = 0;329 const size_t n = s.size();330 331 // Tokenizer: returns the next token, or empty StringRef at EOF. `{`, `}`,332 // and `;` are single-character tokens; everything else is a maximal run of333 // non-delimiter, non-whitespace characters (quotes are absorbed into the334 // run). C-style /* */ comments and `#` line comments are skipped.335 auto next = [&]() -> StringRef {336 for (;;) {337 while (i < n && isspace((unsigned char)s[i]))338 ++i;339 if (i + 1 < n && s[i] == '/' && s[i + 1] == '*') {340 size_t e = s.find("*/", i + 2);341 i = (e == StringRef::npos) ? n : e + 2;342 continue;343 }344 if (i < n && s[i] == '#') {345 size_t e = s.find('\n', i + 1);346 i = (e == StringRef::npos) ? n : e + 1;347 continue;348 }349 break;350 }351 if (i >= n)352 return StringRef();353 char c = s[i];354 if (c == '{' || c == '}' || c == ';') {355 ++i;356 return s.substr(i - 1, 1);357 }358 size_t start = i;359 bool inQuote = false;360 while (i < n) {361 char d = s[i];362 if (d == '"')363 inQuote = !inQuote;364 if (!inQuote && (isspace((unsigned char)d) || d == '{' || d == '}' ||365 d == ';'))366 break;367 ++i;368 }369 return s.substr(start, i - start);370 };371 372 // Parse the body of a `{ ... }` node, dispatching symbols into global/local.373 auto parseBody = [&]() {374 bool global = true; // default scope before any `global:`/`local:`375 for (;;) {376 StringRef tok = next();377 if (tok.empty() || tok == "}")378 return;379 if (tok == ";")380 continue;381 if (tok == "global:" || tok == "global") {382 global = true;383 continue;384 }385 if (tok == "local:" || tok == "local") {386 global = false;387 continue;388 }389 if (tok == ":")390 continue;391 if (tok == "extern") {392 // extern "C" / "C++" { names }; -- record the names in the current393 // scope. C++ name patterns are not demangled on wasm (over-export at394 // worst); this is a documented limitation.395 StringRef lang = next();396 (void)lang;397 StringRef brace = next();398 if (brace != "{")399 continue;400 for (;;) {401 StringRef e = next();402 if (e.empty() || e == "}")403 break;404 if (e == ";")405 continue;406 addVersionPattern(e, global);407 }408 continue;409 }410 addVersionPattern(tok, global);411 }412 };413 414 for (;;) {415 StringRef tok = next();416 if (tok.empty())417 break;418 if (tok == ";")419 continue;420 if (tok != "{") {421 // A version tag name (ignored on wasm). The `{` follows.422 StringRef brace = next();423 if (brace.empty())424 break;425 if (brace != "{") {426 error("version script: expected '{' after version tag '" + tok + "'");427 return;428 }429 }430 parseBody();431 // Consume an optional parent-tag list up to the terminating `;`.432 for (;;) {433 StringRef t = next();434 if (t.empty() || t == ";")435 break;436 }437 }438 ctx.arg.hasVersionScript = true;439}440 441// Returns slices of MB by parsing MB as an archive file.442// Each slice consists of a member file in the archive.443std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(444 MemoryBufferRef mb) {445 std::unique_ptr<Archive> file =446 CHECK(Archive::create(mb),447 mb.getBufferIdentifier() + ": failed to parse archive");448 449 std::vector<std::pair<MemoryBufferRef, uint64_t>> v;450 Error err = Error::success();451 for (const Archive::Child &c : file->children(err)) {452 MemoryBufferRef mbref =453 CHECK(c.getMemoryBufferRef(),454 mb.getBufferIdentifier() +455 ": could not get the buffer for a child of the archive");456 v.push_back(std::make_pair(mbref, c.getChildOffset()));457 }458 if (err)459 fatal(mb.getBufferIdentifier() +460 ": Archive::children failed: " + toString(std::move(err)));461 462 // Take ownership of memory buffers created for members of thin archives.463 for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers())464 make<std::unique_ptr<MemoryBuffer>>(std::move(mb));465 466 return v;467}468 469void LinkerDriver::addFile(StringRef path) {470 std::optional<MemoryBufferRef> buffer = readFile(path);471 if (!buffer)472 return;473 MemoryBufferRef mbref = *buffer;474 475 switch (identify_magic(mbref.getBuffer())) {476 case file_magic::archive: {477 SmallString<128> importFile = path;478 path::replace_extension(importFile, ".imports");479 if (fs::exists(importFile))480 readImportFile(importFile.str());481 482 auto members = getArchiveMembers(mbref);483 484 // Handle -whole-archive.485 if (inWholeArchive) {486 for (const auto &[m, offset] : members) {487 auto *object = createObjectFile(m, path, offset);488 files.push_back(object);489 }490 491 return;492 }493 494 std::unique_ptr<Archive> file =495 CHECK(Archive::create(mbref), path + ": failed to parse archive");496 497 for (const auto &[m, offset] : members) {498 auto magic = identify_magic(m.getBuffer());499 if (magic == file_magic::wasm_object || magic == file_magic::bitcode)500 files.push_back(createObjectFile(m, path, offset, true));501 else502 warn(path + ": archive member '" + m.getBufferIdentifier() +503 "' is neither Wasm object file nor LLVM bitcode");504 }505 506 return;507 }508 case file_magic::bitcode:509 case file_magic::wasm_object: {510 auto obj = createObjectFile(mbref, "", 0, inLib);511 if (ctx.arg.isStatic && isa<SharedFile>(obj)) {512 error("attempted static link of dynamic object " + path);513 break;514 }515 files.push_back(obj);516 break;517 }518 case file_magic::unknown:519 if (mbref.getBuffer().starts_with("#STUB")) {520 files.push_back(make<StubFile>(mbref));521 break;522 }523 [[fallthrough]];524 default:525 error("unknown file type: " + mbref.getBufferIdentifier());526 }527}528 529static std::optional<std::string> findFromSearchPaths(StringRef path) {530 for (StringRef dir : ctx.arg.searchPaths)531 if (std::optional<std::string> s = findFile(dir, path))532 return s;533 return std::nullopt;534}535 536// This is for -l<basename>. We'll look for lib<basename>.a from537// search paths.538static std::optional<std::string> searchLibraryBaseName(StringRef name) {539 for (StringRef dir : ctx.arg.searchPaths) {540 if (!ctx.arg.isStatic)541 if (std::optional<std::string> s = findFile(dir, "lib" + name + ".so"))542 return s;543 if (std::optional<std::string> s = findFile(dir, "lib" + name + ".a"))544 return s;545 }546 return std::nullopt;547}548 549// This is for -l<namespec>.550static std::optional<std::string> searchLibrary(StringRef name) {551 if (name.starts_with(":"))552 return findFromSearchPaths(name.substr(1));553 return searchLibraryBaseName(name);554}555 556// Add a given library by searching it from input search paths.557void LinkerDriver::addLibrary(StringRef name) {558 if (std::optional<std::string> path = searchLibrary(name))559 addFile(saver().save(*path));560 else561 error("unable to find library -l" + name, ErrorTag::LibNotFound, {name});562}563 564void LinkerDriver::createFiles(opt::InputArgList &args) {565 for (auto *arg : args) {566 switch (arg->getOption().getID()) {567 case OPT_library:568 addLibrary(arg->getValue());569 break;570 case OPT_INPUT:571 addFile(arg->getValue());572 break;573 case OPT_Bstatic:574 ctx.arg.isStatic = true;575 break;576 case OPT_Bdynamic:577 if (!ctx.arg.relocatable)578 ctx.arg.isStatic = false;579 break;580 case OPT_whole_archive:581 inWholeArchive = true;582 break;583 case OPT_no_whole_archive:584 inWholeArchive = false;585 break;586 case OPT_start_lib:587 if (inLib)588 error("nested --start-lib");589 inLib = true;590 break;591 case OPT_end_lib:592 if (!inLib)593 error("stray --end-lib");594 inLib = false;595 break;596 }597 }598 if (files.empty() && errorCount() == 0)599 error("no input files");600}601 602static StringRef getAliasSpelling(opt::Arg *arg) {603 if (const opt::Arg *alias = arg->getAlias())604 return alias->getSpelling();605 return arg->getSpelling();606}607 608static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,609 unsigned id) {610 auto *arg = args.getLastArg(id);611 if (!arg)612 return {"", ""};613 614 StringRef s = arg->getValue();615 std::pair<StringRef, StringRef> ret = s.split(';');616 if (ret.second.empty())617 error(getAliasSpelling(arg) + " expects 'old;new' format, but got " + s);618 return ret;619}620 621// Parse options of the form "old;new[;extra]".622static std::tuple<StringRef, StringRef, StringRef>623getOldNewOptionsExtra(opt::InputArgList &args, unsigned id) {624 auto [oldDir, second] = getOldNewOptions(args, id);625 auto [newDir, extraDir] = second.split(';');626 return {oldDir, newDir, extraDir};627}628 629static StringRef getEntry(opt::InputArgList &args) {630 auto *arg = args.getLastArg(OPT_entry, OPT_no_entry);631 if (!arg) {632 if (args.hasArg(OPT_relocatable))633 return "";634 if (args.hasArg(OPT_shared))635 return "__wasm_call_ctors";636 return "_start";637 }638 if (arg->getOption().getID() == OPT_no_entry)639 return "";640 return arg->getValue();641}642 643// Determines what we should do if there are remaining unresolved644// symbols after the name resolution.645static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) {646 UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols,647 OPT_warn_unresolved_symbols, true)648 ? UnresolvedPolicy::ReportError649 : UnresolvedPolicy::Warn;650 651 if (auto *arg = args.getLastArg(OPT_unresolved_symbols)) {652 StringRef s = arg->getValue();653 if (s == "ignore-all")654 return UnresolvedPolicy::Ignore;655 if (s == "import-dynamic")656 return UnresolvedPolicy::ImportDynamic;657 if (s == "report-all")658 return errorOrWarn;659 error("unknown --unresolved-symbols value: " + s);660 }661 662 return errorOrWarn;663}664 665// Parse --build-id or --build-id=<style>. We handle "tree" as a666// synonym for "sha1" because all our hash functions including667// -build-id=sha1 are actually tree hashes for performance reasons.668static std::pair<BuildIdKind, SmallVector<uint8_t, 0>>669getBuildId(opt::InputArgList &args) {670 auto *arg = args.getLastArg(OPT_build_id, OPT_build_id_eq);671 if (!arg)672 return {BuildIdKind::None, {}};673 674 if (arg->getOption().getID() == OPT_build_id)675 return {BuildIdKind::Fast, {}};676 677 StringRef s = arg->getValue();678 if (s == "fast")679 return {BuildIdKind::Fast, {}};680 if (s == "sha1" || s == "tree")681 return {BuildIdKind::Sha1, {}};682 if (s == "uuid")683 return {BuildIdKind::Uuid, {}};684 if (s.starts_with("0x"))685 return {BuildIdKind::Hexstring, parseHex(s.substr(2))};686 687 if (s != "none")688 error("unknown --build-id style: " + s);689 return {BuildIdKind::None, {}};690}691 692// Initializes Config members by the command line options.693static void readConfigs(opt::InputArgList &args) {694 ctx.arg.allowMultipleDefinition =695 hasZOption(args, "muldefs") ||696 args.hasFlag(OPT_allow_multiple_definition,697 OPT_no_allow_multiple_definition, false);698 ctx.arg.bsymbolic = args.hasArg(OPT_Bsymbolic);699 ctx.arg.checkFeatures =700 args.hasFlag(OPT_check_features, OPT_no_check_features, true);701 ctx.arg.compressRelocations = args.hasArg(OPT_compress_relocations);702 ctx.arg.demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);703 ctx.arg.disableVerify = args.hasArg(OPT_disable_verify);704 ctx.arg.emitRelocs = args.hasArg(OPT_emit_relocs);705 ctx.arg.experimentalPic = args.hasArg(OPT_experimental_pic);706 ctx.arg.entry = getEntry(args);707 ctx.arg.exportAll = args.hasArg(OPT_export_all);708 ctx.arg.exportTable = args.hasArg(OPT_export_table);709 ctx.arg.growableTable = args.hasArg(OPT_growable_table);710 ctx.arg.noinhibitExec = args.hasArg(OPT_noinhibit_exec);711 712 if (args.hasArg(OPT_import_memory_with_name)) {713 auto argValue = args.getLastArgValue(OPT_import_memory_with_name);714 if (argValue.contains(','))715 ctx.arg.memoryImport = argValue.split(",");716 else717 ctx.arg.memoryImport = {defaultModule, argValue};718 } else if (args.hasArg(OPT_import_memory)) {719 ctx.arg.memoryImport = {defaultModule, memoryName};720 }721 722 if (args.hasArg(OPT_export_memory_with_name)) {723 ctx.arg.memoryExport = args.getLastArgValue(OPT_export_memory_with_name);724 } else if (args.hasArg(OPT_export_memory)) {725 ctx.arg.memoryExport = memoryName;726 }727 728 ctx.arg.sharedMemory = args.hasArg(OPT_shared_memory);729 ctx.arg.soName = args.getLastArgValue(OPT_soname);730 ctx.arg.importTable = args.hasArg(OPT_import_table);731 ctx.arg.importUndefined = args.hasArg(OPT_import_undefined);732 ctx.arg.ltoo = args::getInteger(args, OPT_lto_O, 2);733 if (ctx.arg.ltoo > 3)734 error("invalid optimization level for LTO: " + Twine(ctx.arg.ltoo));735 unsigned ltoCgo =736 args::getInteger(args, OPT_lto_CGO, args::getCGOptLevel(ctx.arg.ltoo));737 if (auto level = CodeGenOpt::getLevel(ltoCgo))738 ctx.arg.ltoCgo = *level;739 else740 error("invalid codegen optimization level for LTO: " + Twine(ltoCgo));741 ctx.arg.ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);742 ctx.arg.ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);743 ctx.arg.ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);744 ctx.arg.mapFile = args.getLastArgValue(OPT_Map);745 ctx.arg.optimize = args::getInteger(args, OPT_O, 1);746 ctx.arg.outputFile = args.getLastArgValue(OPT_o);747 ctx.arg.relocatable = args.hasArg(OPT_relocatable);748 ctx.arg.rpath = args::getStrings(args, OPT_rpath);749 ctx.arg.gcSections =750 args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !ctx.arg.relocatable);751 for (auto *arg : args.filtered(OPT_keep_section))752 ctx.arg.keepSections.insert(arg->getValue());753 ctx.arg.mergeDataSegments =754 args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,755 !ctx.arg.relocatable);756 ctx.arg.pie = args.hasFlag(OPT_pie, OPT_no_pie, false);757 ctx.arg.printGcSections =758 args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);759 ctx.arg.saveTemps = args.hasArg(OPT_save_temps);760 ctx.arg.searchPaths = args::getStrings(args, OPT_library_path);761 ctx.arg.shared = args.hasArg(OPT_shared);762 ctx.arg.shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck);763 ctx.arg.stripAll = args.hasArg(OPT_strip_all);764 ctx.arg.stripDebug = args.hasArg(OPT_strip_debug);765 ctx.arg.stackFirst = args.hasFlag(OPT_stack_first, OPT_no_stack_first, true);766 ctx.arg.trace = args.hasArg(OPT_trace);767 ctx.arg.thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir);768 ctx.arg.thinLTOCachePolicy = CHECK(769 parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),770 "--thinlto-cache-policy: invalid cache policy");771 ctx.arg.thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);772 ctx.arg.thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) ||773 args.hasArg(OPT_thinlto_index_only) ||774 args.hasArg(OPT_thinlto_index_only_eq);775 ctx.arg.thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||776 args.hasArg(OPT_thinlto_index_only_eq);777 ctx.arg.thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq);778 ctx.arg.thinLTOObjectSuffixReplace =779 getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq);780 std::tie(ctx.arg.thinLTOPrefixReplaceOld, ctx.arg.thinLTOPrefixReplaceNew,781 ctx.arg.thinLTOPrefixReplaceNativeObject) =782 getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace_eq);783 if (ctx.arg.thinLTOEmitIndexFiles && !ctx.arg.thinLTOIndexOnly) {784 if (args.hasArg(OPT_thinlto_object_suffix_replace_eq))785 error("--thinlto-object-suffix-replace is not supported with "786 "--thinlto-emit-index-files");787 else if (args.hasArg(OPT_thinlto_prefix_replace_eq))788 error("--thinlto-prefix-replace is not supported with "789 "--thinlto-emit-index-files");790 }791 if (!ctx.arg.thinLTOPrefixReplaceNativeObject.empty() &&792 ctx.arg.thinLTOIndexOnlyArg.empty()) {793 error("--thinlto-prefix-replace=old_dir;new_dir;obj_dir must be used with "794 "--thinlto-index-only=");795 }796 ctx.arg.unresolvedSymbols = getUnresolvedSymbolPolicy(args);797 ctx.arg.whyExtract = args.getLastArgValue(OPT_why_extract);798 errorHandler().verbose = args.hasArg(OPT_verbose);799 LLVM_DEBUG(errorHandler().verbose = true);800 801 ctx.arg.tableBase = args::getInteger(args, OPT_table_base, 0);802 ctx.arg.globalBase = args::getInteger(args, OPT_global_base, 0);803 ctx.arg.initialHeap = args::getInteger(args, OPT_initial_heap, 0);804 ctx.arg.initialMemory = args::getInteger(args, OPT_initial_memory, 0);805 ctx.arg.maxMemory = args::getInteger(args, OPT_max_memory, 0);806 ctx.arg.noGrowableMemory = args.hasArg(OPT_no_growable_memory);807 ctx.arg.zStackSize =808 args::getZOptionValue(args, OPT_z, "stack-size", WasmDefaultPageSize);809 ctx.arg.pageSize = args::getInteger(args, OPT_page_size, WasmDefaultPageSize);810 if (ctx.arg.pageSize != 1 && ctx.arg.pageSize != WasmDefaultPageSize)811 error("--page_size=N must be either 1 or 65536");812 813 // -Bdynamic by default if -pie or -shared is specified.814 if (ctx.arg.pie || ctx.arg.shared)815 ctx.arg.isStatic = false;816 817 if (ctx.arg.maxMemory != 0 && ctx.arg.noGrowableMemory) {818 // Erroring out here is simpler than defining precedence rules.819 error("--max-memory is incompatible with --no-growable-memory");820 }821 822 // Default value of exportDynamic depends on `-shared`823 ctx.arg.exportDynamic =824 args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, ctx.arg.shared);825 826 // Parse wasm32/64.827 if (auto *arg = args.getLastArg(OPT_m)) {828 StringRef s = arg->getValue();829 if (s == "wasm32")830 ctx.arg.is64 = false;831 else if (s == "wasm64")832 ctx.arg.is64 = true;833 else834 error("invalid target architecture: " + s);835 }836 837 // --threads= takes a positive integer and provides the default value for838 // --thinlto-jobs=.839 if (auto *arg = args.getLastArg(OPT_threads)) {840 StringRef v(arg->getValue());841 unsigned threads = 0;842 if (!llvm::to_integer(v, threads, 0) || threads == 0)843 error(arg->getSpelling() + ": expected a positive integer, but got '" +844 arg->getValue() + "'");845 parallel::strategy = hardware_concurrency(threads);846 ctx.arg.thinLTOJobs = v;847 }848 if (auto *arg = args.getLastArg(OPT_thinlto_jobs))849 ctx.arg.thinLTOJobs = arg->getValue();850 851 if (auto *arg = args.getLastArg(OPT_features)) {852 ctx.arg.features =853 std::optional<std::vector<std::string>>(std::vector<std::string>());854 for (StringRef s : arg->getValues())855 ctx.arg.features->push_back(std::string(s));856 }857 858 if (auto *arg = args.getLastArg(OPT_extra_features)) {859 ctx.arg.extraFeatures =860 std::optional<std::vector<std::string>>(std::vector<std::string>());861 for (StringRef s : arg->getValues())862 ctx.arg.extraFeatures->push_back(std::string(s));863 }864 865 // Legacy --allow-undefined flag which is equivalent to866 // --unresolve-symbols=ignore + --import-undefined867 if (args.hasArg(OPT_allow_undefined)) {868 ctx.arg.importUndefined = true;869 ctx.arg.unresolvedSymbols = UnresolvedPolicy::Ignore;870 }871 872 if (args.hasArg(OPT_print_map))873 ctx.arg.mapFile = "-";874 875 // --version-script: parse for export-visibility (global:/local:) only.876 if (auto *arg = args.getLastArg(OPT_version_script)) {877 if (std::optional<MemoryBufferRef> buf = readFile(arg->getValue()))878 readVersionScript(*buf);879 else880 error("cannot open version script " + StringRef(arg->getValue()));881 }882 883 std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(args);884}885 886// Some Config members do not directly correspond to any particular887// command line options, but computed based on other Config values.888// This function initialize such members. See Config.h for the details889// of these values.890static void setConfigs() {891 ctx.isPic = ctx.arg.pie || ctx.arg.shared;892 893 if (ctx.isPic) {894 if (ctx.arg.exportTable)895 error("-shared/-pie is incompatible with --export-table");896 ctx.arg.importTable = true;897 } else {898 // Default table base. Defaults to 1, reserving 0 for the NULL function899 // pointer.900 if (!ctx.arg.tableBase)901 ctx.arg.tableBase = 1;902 // The default offset for static/global data, for when --global-base is903 // not specified on the command line. The precise value of 1024 is904 // somewhat arbitrary, and pre-dates wasm-ld (Its the value that905 // emscripten used prior to wasm-ld).906 if (!ctx.arg.globalBase && !ctx.arg.relocatable && !ctx.arg.stackFirst)907 ctx.arg.globalBase = 1024;908 }909 910 if (ctx.arg.relocatable) {911 if (ctx.arg.exportTable)912 error("--relocatable is incompatible with --export-table");913 if (ctx.arg.growableTable)914 error("--relocatable is incompatible with --growable-table");915 // Ignore any --import-table, as it's redundant.916 ctx.arg.importTable = true;917 }918 919 if (ctx.arg.shared) {920 if (ctx.arg.memoryExport.has_value()) {921 error("--export-memory is incompatible with --shared");922 }923 if (!ctx.arg.memoryImport.has_value()) {924 ctx.arg.memoryImport = {defaultModule, memoryName};925 }926 }927 928 // If neither export-memory nor import-memory is specified, default to929 // exporting memory under its default name.930 if (!ctx.arg.memoryExport.has_value() && !ctx.arg.memoryImport.has_value()) {931 ctx.arg.memoryExport = memoryName;932 }933}934 935// Some command line options or some combinations of them are not allowed.936// This function checks for such errors.937static void checkOptions(opt::InputArgList &args) {938 if (!ctx.arg.stripDebug && !ctx.arg.stripAll && ctx.arg.compressRelocations)939 error("--compress-relocations is incompatible with output debug"940 " information. Please pass --strip-debug or --strip-all");941 942 if (ctx.arg.ltoPartitions == 0)943 error("--lto-partitions: number of threads must be > 0");944 if (!get_threadpool_strategy(ctx.arg.thinLTOJobs))945 error("--thinlto-jobs: invalid job count: " + ctx.arg.thinLTOJobs);946 947 if (ctx.arg.pie && ctx.arg.shared)948 error("-shared and -pie may not be used together");949 950 if (ctx.arg.outputFile.empty() && !ctx.arg.thinLTOIndexOnly)951 error("no output file specified");952 953 if (ctx.arg.importTable && ctx.arg.exportTable)954 error("--import-table and --export-table may not be used together");955 956 if (ctx.arg.relocatable) {957 if (!ctx.arg.entry.empty())958 error("entry point specified for relocatable output file");959 if (ctx.arg.gcSections)960 error("-r and --gc-sections may not be used together");961 if (ctx.arg.compressRelocations)962 error("-r -and --compress-relocations may not be used together");963 if (args.hasArg(OPT_undefined))964 error("-r -and --undefined may not be used together");965 if (ctx.arg.pie)966 error("-r and -pie may not be used together");967 if (ctx.arg.sharedMemory)968 error("-r and --shared-memory may not be used together");969 if (ctx.arg.globalBase)970 error("-r and --global-base may not by used together");971 }972 973 // To begin to prepare for Module Linking-style shared libraries, start974 // warning about uses of `-shared` and related flags outside of Experimental975 // mode, to give anyone using them a heads-up that they will be changing.976 //977 // Also, warn about flags which request explicit exports.978 if (!ctx.arg.experimentalPic) {979 // -shared will change meaning when Module Linking is implemented.980 if (ctx.arg.shared) {981 warn("creating shared libraries, with -shared, is not yet stable");982 }983 984 // -pie will change meaning when Module Linking is implemented.985 if (ctx.arg.pie) {986 warn("creating PIEs, with -pie, is not yet stable");987 }988 989 if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {990 warn("dynamic imports are not yet stable "991 "(--unresolved-symbols=import-dynamic)");992 }993 }994 995 if (ctx.arg.bsymbolic && !ctx.arg.shared) {996 warn("-Bsymbolic is only meaningful when combined with -shared");997 }998 999 if (ctx.isPic) {1000 if (ctx.arg.globalBase)1001 error("--global-base may not be used with -shared/-pie");1002 if (ctx.arg.tableBase)1003 error("--table-base may not be used with -shared/-pie");1004 }1005}1006 1007static const char *getReproduceOption(opt::InputArgList &args) {1008 if (auto *arg = args.getLastArg(OPT_reproduce))1009 return arg->getValue();1010 return getenv("LLD_REPRODUCE");1011}1012 1013// Force Sym to be entered in the output. Used for -u or equivalent.1014static Symbol *handleUndefined(StringRef name, const char *option) {1015 Symbol *sym = symtab->find(name);1016 if (!sym)1017 return nullptr;1018 1019 // Since symbol S may not be used inside the program, LTO may1020 // eliminate it. Mark the symbol as "used" to prevent it.1021 sym->isUsedInRegularObj = true;1022 1023 if (auto *lazySym = dyn_cast<LazySymbol>(sym)) {1024 lazySym->extract();1025 if (!ctx.arg.whyExtract.empty())1026 ctx.whyExtractRecords.emplace_back(option, sym->getFile(), *sym);1027 }1028 1029 return sym;1030}1031 1032static void handleLibcall(StringRef name) {1033 Symbol *sym = symtab->find(name);1034 if (sym && sym->isLazy() && isa<BitcodeFile>(sym->getFile())) {1035 if (!ctx.arg.whyExtract.empty())1036 ctx.whyExtractRecords.emplace_back("<libcall>", sym->getFile(), *sym);1037 cast<LazySymbol>(sym)->extract();1038 }1039}1040 1041static void writeWhyExtract() {1042 if (ctx.arg.whyExtract.empty())1043 return;1044 1045 std::error_code ec;1046 raw_fd_ostream os(ctx.arg.whyExtract, ec, sys::fs::OF_None);1047 if (ec) {1048 error("cannot open --why-extract= file " + ctx.arg.whyExtract + ": " +1049 ec.message());1050 return;1051 }1052 1053 os << "reference\textracted\tsymbol\n";1054 for (auto &entry : ctx.whyExtractRecords) {1055 os << std::get<0>(entry) << '\t' << toString(std::get<1>(entry)) << '\t'1056 << toString(std::get<2>(entry)) << '\n';1057 }1058}1059 1060// Equivalent of demote demoteSharedAndLazySymbols() in the ELF linker1061static void demoteLazySymbols() {1062 for (Symbol *sym : symtab->symbols()) {1063 if (auto* s = dyn_cast<LazySymbol>(sym)) {1064 if (s->signature) {1065 LLVM_DEBUG(llvm::dbgs()1066 << "demoting lazy func: " << s->getName() << "\n");1067 replaceSymbol<UndefinedFunction>(s, s->getName(), std::nullopt,1068 std::nullopt, WASM_SYMBOL_BINDING_WEAK,1069 s->getFile(), s->signature);1070 }1071 }1072 }1073}1074 1075static UndefinedGlobal *1076createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {1077 auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(1078 name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, type));1079 ctx.arg.allowUndefinedSymbols.insert(sym->getName());1080 sym->isUsedInRegularObj = true;1081 return sym;1082}1083 1084static InputGlobal *createGlobal(StringRef name, bool isMutable) {1085 llvm::wasm::WasmGlobal wasmGlobal;1086 bool is64 = ctx.arg.is64.value_or(false);1087 wasmGlobal.Type = {uint8_t(is64 ? WASM_TYPE_I64 : WASM_TYPE_I32), isMutable};1088 wasmGlobal.InitExpr = intConst(0, is64);1089 wasmGlobal.SymbolName = name;1090 return make<InputGlobal>(wasmGlobal, nullptr);1091}1092 1093static GlobalSymbol *createGlobalVariable(StringRef name, bool isMutable,1094 uint32_t flags = 0) {1095 InputGlobal *g = createGlobal(name, isMutable);1096 return symtab->addSyntheticGlobal(name, flags, g);1097}1098 1099static GlobalSymbol *createOptionalGlobal(StringRef name, bool isMutable) {1100 InputGlobal *g = createGlobal(name, isMutable);1101 return symtab->addOptionalGlobalSymbol(name, g);1102}1103 1104// Create ABI-defined synthetic symbols1105static void createSyntheticSymbols() {1106 if (ctx.arg.relocatable)1107 return;1108 1109 static WasmSignature nullSignature = {{}, {}};1110 static WasmSignature i32ArgSignature = {{}, {ValType::I32}};1111 static WasmSignature i64ArgSignature = {{}, {ValType::I64}};1112 static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false};1113 static llvm::wasm::WasmGlobalType globalTypeI64 = {WASM_TYPE_I64, false};1114 static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32,1115 true};1116 static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64,1117 true};1118 ctx.sym.callCtors = symtab->addSyntheticFunction(1119 "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,1120 make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));1121 1122 bool is64 = ctx.arg.is64.value_or(false);1123 1124 if (ctx.isPic) {1125 ctx.sym.stackPointer =1126 createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false)1127 ? &mutableGlobalTypeI641128 : &mutableGlobalTypeI32);1129 // For PIC code, we import two global variables (__memory_base and1130 // __table_base) from the environment and use these as the offset at1131 // which to load our static data and function table.1132 // See:1133 // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md1134 auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;1135 ctx.sym.memoryBase = createUndefinedGlobal("__memory_base", globalType);1136 ctx.sym.tableBase = createUndefinedGlobal("__table_base", globalType);1137 ctx.sym.memoryBase->markLive();1138 ctx.sym.tableBase->markLive();1139 } else {1140 // For non-PIC code1141 ctx.sym.stackPointer = createGlobalVariable("__stack_pointer", true);1142 ctx.sym.stackPointer->markLive();1143 }1144 1145 if (ctx.arg.sharedMemory) {1146 // TLS symbols are all hidden/dso-local1147 ctx.sym.tlsBase =1148 createGlobalVariable("__tls_base", true, WASM_SYMBOL_VISIBILITY_HIDDEN);1149 ctx.sym.tlsSize = createGlobalVariable("__tls_size", false,1150 WASM_SYMBOL_VISIBILITY_HIDDEN);1151 ctx.sym.tlsAlign = createGlobalVariable("__tls_align", false,1152 WASM_SYMBOL_VISIBILITY_HIDDEN);1153 ctx.sym.initTLS = symtab->addSyntheticFunction(1154 "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN,1155 make<SyntheticFunction>(is64 ? i64ArgSignature : i32ArgSignature,1156 "__wasm_init_tls"));1157 }1158}1159 1160static void createOptionalSymbols() {1161 if (ctx.arg.relocatable)1162 return;1163 1164 ctx.sym.dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");1165 1166 if (!ctx.arg.shared)1167 ctx.sym.dataEnd = symtab->addOptionalDataSymbol("__data_end");1168 1169 if (!ctx.isPic) {1170 ctx.sym.stackLow = symtab->addOptionalDataSymbol("__stack_low");1171 ctx.sym.stackHigh = symtab->addOptionalDataSymbol("__stack_high");1172 ctx.sym.globalBase = symtab->addOptionalDataSymbol("__global_base");1173 ctx.sym.heapBase = symtab->addOptionalDataSymbol("__heap_base");1174 ctx.sym.heapEnd = symtab->addOptionalDataSymbol("__heap_end");1175 ctx.sym.definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");1176 ctx.sym.definedTableBase = symtab->addOptionalDataSymbol("__table_base");1177 }1178 1179 ctx.sym.firstPageEnd = symtab->addOptionalDataSymbol("__wasm_first_page_end");1180 if (ctx.sym.firstPageEnd)1181 ctx.sym.firstPageEnd->setVA(ctx.arg.pageSize);1182 1183 // For non-shared memory programs we still need to define __tls_base since we1184 // allow object files built with TLS to be linked into single threaded1185 // programs, and such object files can contain references to this symbol.1186 //1187 // However, in this case __tls_base is immutable and points directly to the1188 // start of the `.tdata` static segment.1189 //1190 // __tls_size and __tls_align are not needed in this case since they are only1191 // needed for __wasm_init_tls (which we do not create in this case).1192 if (!ctx.arg.sharedMemory)1193 ctx.sym.tlsBase = createOptionalGlobal("__tls_base", false);1194}1195 1196static void processStubLibrariesPreLTO() {1197 log("-- processStubLibrariesPreLTO");1198 for (auto &stub_file : ctx.stubFiles) {1199 LLVM_DEBUG(llvm::dbgs()1200 << "processing stub file: " << stub_file->getName() << "\n");1201 for (auto [name, deps]: stub_file->symbolDependencies) {1202 auto* sym = symtab->find(name);1203 // If the symbol is not present at all (yet), or if it is present but1204 // undefined, then mark the dependent symbols as used by a regular1205 // object so they will be preserved and exported by the LTO process.1206 if (!sym || sym->isUndefined()) {1207 for (const auto dep : deps) {1208 auto* needed = symtab->find(dep);1209 if (needed ) {1210 needed->isUsedInRegularObj = true;1211 // Like with handleLibcall we have to extract any LTO archive1212 // members that might need to be exported due to stub library1213 // symbols being referenced. Without this the LTO object could be1214 // extracted during processStubLibraries, which is too late since1215 // LTO has already being performed at that point.1216 if (needed->isLazy() && isa<BitcodeFile>(needed->getFile())) {1217 if (!ctx.arg.whyExtract.empty())1218 ctx.whyExtractRecords.emplace_back(toString(stub_file),1219 needed->getFile(), *needed);1220 cast<LazySymbol>(needed)->extract();1221 }1222 }1223 }1224 }1225 }1226 }1227}1228 1229static bool addStubSymbolDeps(const StubFile *stub_file, Symbol *sym,1230 ArrayRef<StringRef> deps) {1231 // The first stub library to define a given symbol sets this and1232 // definitions in later stub libraries are ignored.1233 if (sym->forceImport)1234 return false; // Already handled1235 sym->forceImport = true;1236 if (sym->traced)1237 message(toString(stub_file) + ": importing " + sym->getName());1238 else1239 LLVM_DEBUG(llvm::dbgs() << toString(stub_file) << ": importing "1240 << sym->getName() << "\n");1241 bool depsAdded = false;1242 for (const auto dep : deps) {1243 auto *needed = symtab->find(dep);1244 if (!needed) {1245 error(toString(stub_file) + ": undefined symbol: " + dep +1246 ". Required by " + toString(*sym));1247 } else if (needed->isUndefined()) {1248 error(toString(stub_file) + ": undefined symbol: " + toString(*needed) +1249 ". Required by " + toString(*sym));1250 } else {1251 if (needed->traced)1252 message(toString(stub_file) + ": exported " + toString(*needed) +1253 " due to import of " + sym->getName());1254 else1255 LLVM_DEBUG(llvm::dbgs()1256 << "force export: " << toString(*needed) << "\n");1257 needed->forceExport = true;1258 if (auto *lazy = dyn_cast<LazySymbol>(needed)) {1259 depsAdded = true;1260 lazy->extract();1261 if (!ctx.arg.whyExtract.empty())1262 ctx.whyExtractRecords.emplace_back(toString(stub_file),1263 sym->getFile(), *sym);1264 }1265 }1266 }1267 return depsAdded;1268}1269 1270static void processStubLibraries() {1271 log("-- processStubLibraries");1272 bool depsAdded = false;1273 do {1274 depsAdded = false;1275 for (auto &stub_file : ctx.stubFiles) {1276 LLVM_DEBUG(llvm::dbgs()1277 << "processing stub file: " << stub_file->getName() << "\n");1278 1279 // First look for any imported symbols that directly match1280 // the names of the stub imports1281 for (auto [name, deps]: stub_file->symbolDependencies) {1282 auto* sym = symtab->find(name);1283 if (sym && sym->isUndefined()) {1284 depsAdded |= addStubSymbolDeps(stub_file, sym, deps);1285 } else {1286 if (sym && sym->traced)1287 message(toString(stub_file) + ": stub symbol not needed: " + name);1288 else1289 LLVM_DEBUG(llvm::dbgs()1290 << "stub symbol not needed: `" << name << "`\n");1291 }1292 }1293 1294 // Secondly looks for any symbols with an `importName` that matches1295 for (Symbol *sym : symtab->symbols()) {1296 if (sym->isUndefined() && sym->importName.has_value()) {1297 auto it = stub_file->symbolDependencies.find(sym->importName.value());1298 if (it != stub_file->symbolDependencies.end()) {1299 depsAdded |= addStubSymbolDeps(stub_file, sym, it->second);1300 }1301 }1302 }1303 }1304 } while (depsAdded);1305 1306 log("-- done processStubLibraries");1307}1308 1309// Reconstructs command line arguments so that so that you can re-run1310// the same command with the same inputs. This is for --reproduce.1311static std::string createResponseFile(const opt::InputArgList &args) {1312 SmallString<0> data;1313 raw_svector_ostream os(data);1314 1315 // Copy the command line to the output while rewriting paths.1316 for (auto *arg : args) {1317 switch (arg->getOption().getID()) {1318 case OPT_reproduce:1319 break;1320 case OPT_INPUT:1321 os << quote(relativeToRoot(arg->getValue())) << "\n";1322 break;1323 case OPT_o:1324 // If -o path contains directories, "lld @response.txt" will likely1325 // fail because the archive we are creating doesn't contain empty1326 // directories for the output path (-o doesn't create directories).1327 // Strip directories to prevent the issue.1328 os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n";1329 break;1330 default:1331 os << toString(*arg) << "\n";1332 }1333 }1334 return std::string(data);1335}1336 1337// The --wrap option is a feature to rename symbols so that you can write1338// wrappers for existing functions. If you pass `-wrap=foo`, all1339// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are1340// expected to write `wrap_foo` function as a wrapper). The original1341// symbol becomes accessible as `real_foo`, so you can call that from your1342// wrapper.1343//1344// This data structure is instantiated for each -wrap option.1345struct WrappedSymbol {1346 Symbol *sym;1347 Symbol *real;1348 Symbol *wrap;1349};1350 1351static Symbol *addUndefined(StringRef name,1352 const WasmSignature *signature = nullptr) {1353 return symtab->addUndefinedFunction(name, std::nullopt, std::nullopt,1354 WASM_SYMBOL_UNDEFINED, nullptr, signature,1355 false);1356}1357 1358// Handles -wrap option.1359//1360// This function instantiates wrapper symbols. At this point, they seem1361// like they are not being used at all, so we explicitly set some flags so1362// that LTO won't eliminate them.1363static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {1364 std::vector<WrappedSymbol> v;1365 DenseSet<StringRef> seen;1366 1367 for (auto *arg : args.filtered(OPT_wrap)) {1368 StringRef name = arg->getValue();1369 if (!seen.insert(name).second)1370 continue;1371 1372 Symbol *sym = symtab->find(name);1373 if (!sym)1374 continue;1375 1376 Symbol *real = addUndefined(saver().save("__real_" + name));1377 Symbol *wrap =1378 addUndefined(saver().save("__wrap_" + name), sym->getSignature());1379 v.push_back({sym, real, wrap});1380 1381 // We want to tell LTO not to inline symbols to be overwritten1382 // because LTO doesn't know the final symbol contents after renaming.1383 real->canInline = false;1384 sym->canInline = false;1385 1386 // Tell LTO not to eliminate these symbols.1387 sym->isUsedInRegularObj = true;1388 wrap->isUsedInRegularObj = true;1389 real->isUsedInRegularObj = false;1390 }1391 return v;1392}1393 1394// Do renaming for -wrap by updating pointers to symbols.1395//1396// When this function is executed, only InputFiles and symbol table1397// contain pointers to symbol objects. We visit them to replace pointers,1398// so that wrapped symbols are swapped as instructed by the command line.1399static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {1400 DenseMap<Symbol *, Symbol *> map;1401 for (const WrappedSymbol &w : wrapped) {1402 map[w.sym] = w.wrap;1403 map[w.real] = w.sym;1404 }1405 1406 // Update pointers in input files.1407 parallelForEach(ctx.objectFiles, [&](InputFile *file) {1408 MutableArrayRef<Symbol *> syms = file->getMutableSymbols();1409 for (Symbol *&sym : syms)1410 if (Symbol *s = map.lookup(sym))1411 sym = s;1412 });1413 1414 // Update pointers in the symbol table.1415 for (const WrappedSymbol &w : wrapped)1416 symtab->wrap(w.sym, w.real, w.wrap);1417}1418 1419static void splitSections() {1420 // splitIntoPieces needs to be called on each MergeInputChunk1421 // before calling finalizeContents().1422 LLVM_DEBUG(llvm::dbgs() << "splitSections\n");1423 parallelForEach(ctx.objectFiles, [](ObjFile *file) {1424 for (InputChunk *seg : file->segments) {1425 if (auto *s = dyn_cast<MergeInputChunk>(seg))1426 s->splitIntoPieces();1427 }1428 for (InputChunk *sec : file->customSections) {1429 if (auto *s = dyn_cast<MergeInputChunk>(sec))1430 s->splitIntoPieces();1431 }1432 });1433}1434 1435// Apply the global:/local: export visibility of a parsed --version-script.1436// Wasm has no symbol versioning, so this only governs which symbols a shared1437// module exports: symbols matched by `local:` are hidden; `global:` keeps a1438// symbol's default visibility (it never promotes an object-hidden symbol, to1439// match GNU ld). Explicit command-line exports (--export/-u/entry) win over1440// the script and are left untouched.1441static void applyVersionScript() {1442 if (!ctx.arg.hasVersionScript)1443 return;1444 1445 // Match precedence mirrors the ELF linker: exact name before wildcard, and1446 // global before local at equal specificity. Returns +1 (global), -1 (local),1447 // or 0 (no match).1448 auto classify = [](StringRef name) -> int {1449 if (ctx.arg.versionGlobalExact.count(name))1450 return 1;1451 if (ctx.arg.versionLocalExact.count(name))1452 return -1;1453 for (const GlobPattern &p : ctx.arg.versionGlobalPatterns)1454 if (p.match(name))1455 return 1;1456 for (const GlobPattern &p : ctx.arg.versionLocalPatterns)1457 if (p.match(name))1458 return -1;1459 if (ctx.arg.versionGlobalAll)1460 return 1;1461 if (ctx.arg.versionLocalAll)1462 return -1;1463 return 0;1464 };1465 1466 for (Symbol *sym : symtab->symbols()) {1467 if (!sym->isDefined() || sym->isShared() || sym->isLocal())1468 continue;1469 // Command-line exports are authoritative and must never be dropped.1470 if (sym->isExportedExplicit())1471 continue;1472 if (classify(sym->getName()) < 0)1473 sym->setHidden(true);1474 }1475}1476 1477static bool isKnownZFlag(StringRef s) {1478 // -z values wasm-ld understands. `relro` is meaningless for wasm linear1479 // memory and `defs`/`nodefs` (no-undefined) is handled by wasm-ld's existing1480 // unresolved-symbol policy / shared-import model rather than as a -z toggle,1481 // so both are accepted and otherwise ignored here (see PLAN HWJS-B-1).1482 return s.starts_with("stack-size=") || s == "muldefs" || s == "relro" ||1483 s == "norelro" || s == "defs" || s == "nodefs";1484}1485 1486// Report a warning for an unknown -z option.1487static void checkZOptions(opt::InputArgList &args) {1488 for (auto *arg : args.filtered(OPT_z))1489 if (!isKnownZFlag(arg->getValue()))1490 warn("unknown -z value: " + StringRef(arg->getValue()));1491}1492 1493LinkerDriver::LinkerDriver(Ctx &ctx) : ctx(ctx) {}1494 1495void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {1496 WasmOptTable parser;1497 opt::InputArgList args = parser.parse(argsArr.slice(1));1498 1499 // Interpret these flags early because error()/warn() depend on them.1500 auto &errHandler = errorHandler();1501 errHandler.errorLimit = args::getInteger(args, OPT_error_limit, 20);1502 errHandler.fatalWarnings =1503 args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);1504 checkZOptions(args);1505 1506 // Handle --help1507 if (args.hasArg(OPT_help)) {1508 parser.printHelp(errHandler.outs(),1509 (std::string(argsArr[0]) + " [options] file...").c_str(),1510 "LLVM Linker", false);1511 return;1512 }1513 1514 // Handle -v or -version.1515 if (args.hasArg(OPT_v) || args.hasArg(OPT_version))1516 errHandler.outs() << getLLDVersion() << "\n";1517 1518 // Handle --reproduce1519 if (const char *path = getReproduceOption(args)) {1520 Expected<std::unique_ptr<TarWriter>> errOrWriter =1521 TarWriter::create(path, path::stem(path));1522 if (errOrWriter) {1523 tar = std::move(*errOrWriter);1524 tar->append("response.txt", createResponseFile(args));1525 tar->append("version.txt", getLLDVersion() + "\n");1526 } else {1527 error("--reproduce: " + toString(errOrWriter.takeError()));1528 }1529 }1530 1531 // Parse and evaluate -mllvm options.1532 std::vector<const char *> v;1533 v.push_back("wasm-ld (LLVM option parsing)");1534 for (auto *arg : args.filtered(OPT_mllvm))1535 v.push_back(arg->getValue());1536 cl::ResetAllOptionOccurrences();1537 cl::ParseCommandLineOptions(v.size(), v.data());1538 1539 readConfigs(args);1540 setConfigs();1541 1542 // The behavior of -v or --version is a bit strange, but this is1543 // needed for compatibility with GNU linkers.1544 if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT))1545 return;1546 if (args.hasArg(OPT_version))1547 return;1548 1549 createFiles(args);1550 if (errorCount())1551 return;1552 1553 checkOptions(args);1554 if (errorCount())1555 return;1556 1557 if (auto *arg = args.getLastArg(OPT_allow_undefined_file))1558 readImportFile(arg->getValue());1559 1560 // Fail early if the output file or map file is not writable. If a user has a1561 // long link, e.g. due to a large LTO link, they do not wish to run it and1562 // find that it failed because there was a mistake in their command-line.1563 if (auto e = tryCreateFile(ctx.arg.outputFile))1564 error("cannot open output file " + ctx.arg.outputFile + ": " + e.message());1565 if (auto e = tryCreateFile(ctx.arg.mapFile))1566 error("cannot open map file " + ctx.arg.mapFile + ": " + e.message());1567 if (errorCount())1568 return;1569 1570 // Handle --trace-symbol.1571 for (auto *arg : args.filtered(OPT_trace_symbol))1572 symtab->trace(arg->getValue());1573 1574 for (auto *arg : args.filtered(OPT_export_if_defined))1575 ctx.arg.exportedSymbols.insert(arg->getValue());1576 1577 for (auto *arg : args.filtered(OPT_export)) {1578 ctx.arg.exportedSymbols.insert(arg->getValue());1579 ctx.arg.requiredExports.push_back(arg->getValue());1580 }1581 1582 createSyntheticSymbols();1583 1584 // Add all files to the symbol table. This will add almost all1585 // symbols that we need to the symbol table.1586 for (InputFile *f : files)1587 symtab->addFile(f);1588 if (errorCount())1589 return;1590 1591 // Handle the `--undefined <sym>` options.1592 for (auto *arg : args.filtered(OPT_undefined))1593 handleUndefined(arg->getValue(), "<internal>");1594 1595 // Handle the `--export <sym>` options1596 // This works like --undefined but also exports the symbol if its found1597 for (auto &iter : ctx.arg.exportedSymbols)1598 handleUndefined(iter.first(), "--export");1599 1600 Symbol *entrySym = nullptr;1601 if (!ctx.arg.relocatable && !ctx.arg.entry.empty()) {1602 entrySym = handleUndefined(ctx.arg.entry, "--entry");1603 if (entrySym && entrySym->isDefined())1604 entrySym->forceExport = true;1605 else1606 error("entry symbol not defined (pass --no-entry to suppress): " +1607 ctx.arg.entry);1608 }1609 1610 // If the user code defines a `__wasm_call_dtors` function, remember it so1611 // that we can call it from the command export wrappers. Unlike1612 // `__wasm_call_ctors` which we synthesize, `__wasm_call_dtors` is defined1613 // by libc/etc., because destructors are registered dynamically with1614 // `__cxa_atexit` and friends.1615 if (!ctx.arg.relocatable && !ctx.arg.shared &&1616 !ctx.sym.callCtors->isUsedInRegularObj &&1617 ctx.sym.callCtors->getName() != ctx.arg.entry &&1618 !ctx.arg.exportedSymbols.count(ctx.sym.callCtors->getName())) {1619 if (Symbol *callDtors =1620 handleUndefined("__wasm_call_dtors", "<internal>")) {1621 if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) {1622 if (callDtorsFunc->signature &&1623 (!callDtorsFunc->signature->Params.empty() ||1624 !callDtorsFunc->signature->Returns.empty())) {1625 error("__wasm_call_dtors must have no argument or return values");1626 }1627 ctx.sym.callDtors = callDtorsFunc;1628 } else {1629 error("__wasm_call_dtors must be a function");1630 }1631 }1632 }1633 1634 if (errorCount())1635 return;1636 1637 // Create wrapped symbols for -wrap option.1638 std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);1639 1640 // If any of our inputs are bitcode files, the LTO code generator may create1641 // references to certain library functions that might not be explicit in the1642 // bitcode file's symbol table. If any of those library functions are defined1643 // in a bitcode file in an archive member, we need to arrange to use LTO to1644 // compile those archive members by adding them to the link beforehand.1645 //1646 // We only need to add libcall symbols to the link before LTO if the symbol's1647 // definition is in bitcode. Any other required libcall symbols will be added1648 // to the link after LTO when we add the LTO object file to the link.1649 if (!ctx.bitcodeFiles.empty()) {1650 llvm::Triple TT(ctx.bitcodeFiles.front()->obj->getTargetTriple());1651 for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))1652 handleLibcall(s);1653 }1654 if (errorCount())1655 return;1656 1657 // We process the stub libraries once beofore LTO to ensure that any possible1658 // required exports are preserved by the LTO process.1659 processStubLibrariesPreLTO();1660 1661 // Do link-time optimization if given files are LLVM bitcode files.1662 // This compiles bitcode files into real object files.1663 symtab->compileBitcodeFiles();1664 if (errorCount())1665 return;1666 1667 // The LTO process can generate new undefined symbols, specifically libcall1668 // functions. Because those symbols might be declared in a stub library we1669 // need the process the stub libraries once again after LTO to handle all1670 // undefined symbols, including ones that didn't exist prior to LTO.1671 processStubLibraries();1672 1673 writeWhyExtract();1674 1675 // Bail out if normal linked output is skipped due to LTO.1676 if (ctx.arg.thinLTOIndexOnly)1677 return;1678 1679 createOptionalSymbols();1680 1681 // Resolve any variant symbols that were created due to signature1682 // mismatchs.1683 symtab->handleSymbolVariants();1684 if (errorCount())1685 return;1686 1687 // Apply symbol renames for -wrap.1688 if (!wrapped.empty())1689 wrapSymbols(wrapped);1690 1691 for (auto &iter : ctx.arg.exportedSymbols) {1692 Symbol *sym = symtab->find(iter.first());1693 if (sym && sym->isDefined())1694 sym->forceExport = true;1695 }1696 1697 // Honor --version-script export visibility now that explicit exports (above)1698 // and entry are known: `local:` symbols are hidden, `global:` keep default.1699 applyVersionScript();1700 1701 if (!ctx.arg.relocatable && !ctx.isPic) {1702 // Add synthetic dummies for weak undefined functions. Must happen1703 // after LTO otherwise functions may not yet have signatures.1704 symtab->handleWeakUndefines();1705 }1706 1707 if (entrySym)1708 entrySym->setHidden(false);1709 1710 if (errorCount())1711 return;1712 1713 // Split WASM_SEG_FLAG_STRINGS sections into pieces in preparation for garbage1714 // collection.1715 splitSections();1716 1717 // Any remaining lazy symbols should be demoted to Undefined1718 demoteLazySymbols();1719 1720 // Do size optimizations: garbage collection1721 markLive();1722 1723 // Provide the indirect function table if needed.1724 ctx.sym.indirectFunctionTable =1725 symtab->resolveIndirectFunctionTable(/*required =*/false);1726 1727 if (errorCount())1728 return;1729 1730 // Write the result to the file.1731 writeResult();1732}1733 1734} // namespace lld::wasm1735