diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 0c2ba3eebffc4..1fa6c42d9cd86 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -126,17 +126,9 @@ struct Config { llvm::SmallVector buildIdVector; }; -struct ConfigWrapper { - Config c; - Config *operator->() { return &c; } -}; - -// The only instance of Configuration struct. -extern ConfigWrapper config; - // The Ctx object hold all other (non-configuration) global state. struct Ctx { - Config &arg; + Config arg; llvm::SmallVector objectFiles; llvm::SmallVector stubFiles; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 02471950fb519..c3a74dde6480e 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -44,17 +44,16 @@ using namespace llvm::sys; using namespace llvm::wasm; namespace lld::wasm { -ConfigWrapper config; Ctx ctx; void errorOrWarn(const llvm::Twine &msg) { - if (config->noinhibitExec) + if (ctx.arg.noinhibitExec) warn(msg); else error(msg); } -Ctx::Ctx() : arg(config.c) {} +Ctx::Ctx() {} void Ctx::reset() { arg.~Config(); @@ -268,7 +267,7 @@ opt::InputArgList WasmOptTable::parse(ArrayRef argv) { static void readImportFile(StringRef filename) { if (std::optional buf = readFile(filename)) for (StringRef sym : args::getLines(*buf)) - config->allowUndefinedSymbols.insert(sym); + ctx.arg.allowUndefinedSymbols.insert(sym); } // Returns slices of MB by parsing MB as an archive file. @@ -345,7 +344,7 @@ void LinkerDriver::addFile(StringRef path) { case file_magic::bitcode: case file_magic::wasm_object: { auto obj = createObjectFile(mbref, "", 0, inLib); - if (config->isStatic && isa(obj)) { + if (ctx.arg.isStatic && isa(obj)) { error("attempted static link of dynamic object " + path); break; } @@ -364,7 +363,7 @@ void LinkerDriver::addFile(StringRef path) { } static std::optional findFromSearchPaths(StringRef path) { - for (StringRef dir : config->searchPaths) + for (StringRef dir : ctx.arg.searchPaths) if (std::optional s = findFile(dir, path)) return s; return std::nullopt; @@ -373,8 +372,8 @@ static std::optional findFromSearchPaths(StringRef path) { // This is for -l. We'll look for lib.a from // search paths. static std::optional searchLibraryBaseName(StringRef name) { - for (StringRef dir : config->searchPaths) { - if (!config->isStatic) + for (StringRef dir : ctx.arg.searchPaths) { + if (!ctx.arg.isStatic) if (std::optional s = findFile(dir, "lib" + name + ".so")) return s; if (std::optional s = findFile(dir, "lib" + name + ".a")) @@ -408,10 +407,10 @@ void LinkerDriver::createFiles(opt::InputArgList &args) { addFile(arg->getValue()); break; case OPT_Bstatic: - config->isStatic = true; + ctx.arg.isStatic = true; break; case OPT_Bdynamic: - config->isStatic = false; + ctx.arg.isStatic = false; break; case OPT_whole_archive: inWholeArchive = true; @@ -527,99 +526,98 @@ getBuildId(opt::InputArgList &args) { // Initializes Config members by the command line options. static void readConfigs(opt::InputArgList &args) { - config->allowMultipleDefinition = + ctx.arg.allowMultipleDefinition = hasZOption(args, "muldefs") || args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false); - config->bsymbolic = args.hasArg(OPT_Bsymbolic); - config->checkFeatures = + ctx.arg.bsymbolic = args.hasArg(OPT_Bsymbolic); + ctx.arg.checkFeatures = args.hasFlag(OPT_check_features, OPT_no_check_features, true); - config->compressRelocations = args.hasArg(OPT_compress_relocations); - config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); - config->disableVerify = args.hasArg(OPT_disable_verify); - config->emitRelocs = args.hasArg(OPT_emit_relocs); - config->experimentalPic = args.hasArg(OPT_experimental_pic); - config->entry = getEntry(args); - config->exportAll = args.hasArg(OPT_export_all); - config->exportTable = args.hasArg(OPT_export_table); - config->growableTable = args.hasArg(OPT_growable_table); - config->noinhibitExec = args.hasArg(OPT_noinhibit_exec); + ctx.arg.compressRelocations = args.hasArg(OPT_compress_relocations); + ctx.arg.demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); + ctx.arg.disableVerify = args.hasArg(OPT_disable_verify); + ctx.arg.emitRelocs = args.hasArg(OPT_emit_relocs); + ctx.arg.experimentalPic = args.hasArg(OPT_experimental_pic); + ctx.arg.entry = getEntry(args); + ctx.arg.exportAll = args.hasArg(OPT_export_all); + ctx.arg.exportTable = args.hasArg(OPT_export_table); + ctx.arg.growableTable = args.hasArg(OPT_growable_table); + ctx.arg.noinhibitExec = args.hasArg(OPT_noinhibit_exec); if (args.hasArg(OPT_import_memory_with_name)) { - config->memoryImport = + ctx.arg.memoryImport = args.getLastArgValue(OPT_import_memory_with_name).split(","); } else if (args.hasArg(OPT_import_memory)) { - config->memoryImport = + ctx.arg.memoryImport = std::pair(defaultModule, memoryName); } else { - config->memoryImport = + ctx.arg.memoryImport = std::optional>(); } if (args.hasArg(OPT_export_memory_with_name)) { - config->memoryExport = - args.getLastArgValue(OPT_export_memory_with_name); + ctx.arg.memoryExport = args.getLastArgValue(OPT_export_memory_with_name); } else if (args.hasArg(OPT_export_memory)) { - config->memoryExport = memoryName; + ctx.arg.memoryExport = memoryName; } else { - config->memoryExport = std::optional(); + ctx.arg.memoryExport = std::optional(); } - config->sharedMemory = args.hasArg(OPT_shared_memory); - config->soName = args.getLastArgValue(OPT_soname); - config->importTable = args.hasArg(OPT_import_table); - config->importUndefined = args.hasArg(OPT_import_undefined); - config->ltoo = args::getInteger(args, OPT_lto_O, 2); - if (config->ltoo > 3) - error("invalid optimization level for LTO: " + Twine(config->ltoo)); + ctx.arg.sharedMemory = args.hasArg(OPT_shared_memory); + ctx.arg.soName = args.getLastArgValue(OPT_soname); + ctx.arg.importTable = args.hasArg(OPT_import_table); + ctx.arg.importUndefined = args.hasArg(OPT_import_undefined); + ctx.arg.ltoo = args::getInteger(args, OPT_lto_O, 2); + if (ctx.arg.ltoo > 3) + error("invalid optimization level for LTO: " + Twine(ctx.arg.ltoo)); unsigned ltoCgo = - args::getInteger(args, OPT_lto_CGO, args::getCGOptLevel(config->ltoo)); + args::getInteger(args, OPT_lto_CGO, args::getCGOptLevel(ctx.arg.ltoo)); if (auto level = CodeGenOpt::getLevel(ltoCgo)) - config->ltoCgo = *level; + ctx.arg.ltoCgo = *level; else error("invalid codegen optimization level for LTO: " + Twine(ltoCgo)); - config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); - config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq); - config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); - config->mapFile = args.getLastArgValue(OPT_Map); - config->optimize = args::getInteger(args, OPT_O, 1); - config->outputFile = args.getLastArgValue(OPT_o); - config->relocatable = args.hasArg(OPT_relocatable); - config->gcSections = - args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable); + ctx.arg.ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); + ctx.arg.ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq); + ctx.arg.ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); + ctx.arg.mapFile = args.getLastArgValue(OPT_Map); + ctx.arg.optimize = args::getInteger(args, OPT_O, 1); + ctx.arg.outputFile = args.getLastArgValue(OPT_o); + ctx.arg.relocatable = args.hasArg(OPT_relocatable); + ctx.arg.gcSections = + args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !ctx.arg.relocatable); for (auto *arg : args.filtered(OPT_keep_section)) - config->keepSections.insert(arg->getValue()); - config->mergeDataSegments = + ctx.arg.keepSections.insert(arg->getValue()); + ctx.arg.mergeDataSegments = args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments, - !config->relocatable); - config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false); - config->printGcSections = + !ctx.arg.relocatable); + ctx.arg.pie = args.hasFlag(OPT_pie, OPT_no_pie, false); + ctx.arg.printGcSections = args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); - config->saveTemps = args.hasArg(OPT_save_temps); - config->searchPaths = args::getStrings(args, OPT_library_path); - config->shared = args.hasArg(OPT_shared); - config->shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck); - config->stripAll = args.hasArg(OPT_strip_all); - config->stripDebug = args.hasArg(OPT_strip_debug); - config->stackFirst = args.hasArg(OPT_stack_first); - config->trace = args.hasArg(OPT_trace); - config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); - config->thinLTOCachePolicy = CHECK( + ctx.arg.saveTemps = args.hasArg(OPT_save_temps); + ctx.arg.searchPaths = args::getStrings(args, OPT_library_path); + ctx.arg.shared = args.hasArg(OPT_shared); + ctx.arg.shlibSigCheck = !args.hasArg(OPT_no_shlib_sigcheck); + ctx.arg.stripAll = args.hasArg(OPT_strip_all); + ctx.arg.stripDebug = args.hasArg(OPT_strip_debug); + ctx.arg.stackFirst = args.hasArg(OPT_stack_first); + ctx.arg.trace = args.hasArg(OPT_trace); + ctx.arg.thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); + ctx.arg.thinLTOCachePolicy = CHECK( parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)), "--thinlto-cache-policy: invalid cache policy"); - config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); - config->thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) || + ctx.arg.thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); + ctx.arg.thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) || args.hasArg(OPT_thinlto_index_only) || args.hasArg(OPT_thinlto_index_only_eq); - config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || + ctx.arg.thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || args.hasArg(OPT_thinlto_index_only_eq); - config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq); - config->thinLTOObjectSuffixReplace = + ctx.arg.thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq); + ctx.arg.thinLTOObjectSuffixReplace = getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq); - std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew, - config->thinLTOPrefixReplaceNativeObject) = + std::tie(ctx.arg.thinLTOPrefixReplaceOld, ctx.arg.thinLTOPrefixReplaceNew, + ctx.arg.thinLTOPrefixReplaceNativeObject) = getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace_eq); - if (config->thinLTOEmitIndexFiles && !config->thinLTOIndexOnly) { + if (ctx.arg.thinLTOEmitIndexFiles && !ctx.arg.thinLTOIndexOnly) { if (args.hasArg(OPT_thinlto_object_suffix_replace_eq)) error("--thinlto-object-suffix-replace is not supported with " "--thinlto-emit-index-files"); @@ -627,45 +625,45 @@ static void readConfigs(opt::InputArgList &args) { error("--thinlto-prefix-replace is not supported with " "--thinlto-emit-index-files"); } - if (!config->thinLTOPrefixReplaceNativeObject.empty() && - config->thinLTOIndexOnlyArg.empty()) { + if (!ctx.arg.thinLTOPrefixReplaceNativeObject.empty() && + ctx.arg.thinLTOIndexOnlyArg.empty()) { error("--thinlto-prefix-replace=old_dir;new_dir;obj_dir must be used with " "--thinlto-index-only="); } - config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); - config->whyExtract = args.getLastArgValue(OPT_why_extract); + ctx.arg.unresolvedSymbols = getUnresolvedSymbolPolicy(args); + ctx.arg.whyExtract = args.getLastArgValue(OPT_why_extract); errorHandler().verbose = args.hasArg(OPT_verbose); LLVM_DEBUG(errorHandler().verbose = true); - config->tableBase = args::getInteger(args, OPT_table_base, 0); - config->globalBase = args::getInteger(args, OPT_global_base, 0); - config->initialHeap = args::getInteger(args, OPT_initial_heap, 0); - config->initialMemory = args::getInteger(args, OPT_initial_memory, 0); - config->maxMemory = args::getInteger(args, OPT_max_memory, 0); - config->noGrowableMemory = args.hasArg(OPT_no_growable_memory); - config->zStackSize = + ctx.arg.tableBase = args::getInteger(args, OPT_table_base, 0); + ctx.arg.globalBase = args::getInteger(args, OPT_global_base, 0); + ctx.arg.initialHeap = args::getInteger(args, OPT_initial_heap, 0); + ctx.arg.initialMemory = args::getInteger(args, OPT_initial_memory, 0); + ctx.arg.maxMemory = args::getInteger(args, OPT_max_memory, 0); + ctx.arg.noGrowableMemory = args.hasArg(OPT_no_growable_memory); + ctx.arg.zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize); // -Bdynamic by default if -pie or -shared is specified. - if (config->pie || config->shared) - config->isStatic = false; + if (ctx.arg.pie || ctx.arg.shared) + ctx.arg.isStatic = false; - if (config->maxMemory != 0 && config->noGrowableMemory) { + if (ctx.arg.maxMemory != 0 && ctx.arg.noGrowableMemory) { // Erroring out here is simpler than defining precedence rules. error("--max-memory is incompatible with --no-growable-memory"); } // Default value of exportDynamic depends on `-shared` - config->exportDynamic = - args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, config->shared); + ctx.arg.exportDynamic = + args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, ctx.arg.shared); // Parse wasm32/64. if (auto *arg = args.getLastArg(OPT_m)) { StringRef s = arg->getValue(); if (s == "wasm32") - config->is64 = false; + ctx.arg.is64 = false; else if (s == "wasm64") - config->is64 = true; + ctx.arg.is64 = true; else error("invalid target architecture: " + s); } @@ -679,36 +677,36 @@ static void readConfigs(opt::InputArgList &args) { error(arg->getSpelling() + ": expected a positive integer, but got '" + arg->getValue() + "'"); parallel::strategy = hardware_concurrency(threads); - config->thinLTOJobs = v; + ctx.arg.thinLTOJobs = v; } if (auto *arg = args.getLastArg(OPT_thinlto_jobs)) - config->thinLTOJobs = arg->getValue(); + ctx.arg.thinLTOJobs = arg->getValue(); if (auto *arg = args.getLastArg(OPT_features)) { - config->features = + ctx.arg.features = std::optional>(std::vector()); for (StringRef s : arg->getValues()) - config->features->push_back(std::string(s)); + ctx.arg.features->push_back(std::string(s)); } if (auto *arg = args.getLastArg(OPT_extra_features)) { - config->extraFeatures = + ctx.arg.extraFeatures = std::optional>(std::vector()); for (StringRef s : arg->getValues()) - config->extraFeatures->push_back(std::string(s)); + ctx.arg.extraFeatures->push_back(std::string(s)); } // Legacy --allow-undefined flag which is equivalent to // --unresolve-symbols=ignore + --import-undefined if (args.hasArg(OPT_allow_undefined)) { - config->importUndefined = true; - config->unresolvedSymbols = UnresolvedPolicy::Ignore; + ctx.arg.importUndefined = true; + ctx.arg.unresolvedSymbols = UnresolvedPolicy::Ignore; } if (args.hasArg(OPT_print_map)) - config->mapFile = "-"; + ctx.arg.mapFile = "-"; - std::tie(config->buildId, config->buildIdVector) = getBuildId(args); + std::tie(ctx.arg.buildId, ctx.arg.buildIdVector) = getBuildId(args); } // Some Config members do not directly correspond to any particular @@ -716,86 +714,86 @@ static void readConfigs(opt::InputArgList &args) { // This function initialize such members. See Config.h for the details // of these values. static void setConfigs() { - ctx.isPic = config->pie || config->shared; + ctx.isPic = ctx.arg.pie || ctx.arg.shared; if (ctx.isPic) { - if (config->exportTable) + if (ctx.arg.exportTable) error("-shared/-pie is incompatible with --export-table"); - config->importTable = true; + ctx.arg.importTable = true; } else { // Default table base. Defaults to 1, reserving 0 for the NULL function // pointer. - if (!config->tableBase) - config->tableBase = 1; + if (!ctx.arg.tableBase) + ctx.arg.tableBase = 1; // The default offset for static/global data, for when --global-base is // not specified on the command line. The precise value of 1024 is // somewhat arbitrary, and pre-dates wasm-ld (Its the value that // emscripten used prior to wasm-ld). - if (!config->globalBase && !config->relocatable && !config->stackFirst) - config->globalBase = 1024; + if (!ctx.arg.globalBase && !ctx.arg.relocatable && !ctx.arg.stackFirst) + ctx.arg.globalBase = 1024; } - if (config->relocatable) { - if (config->exportTable) + if (ctx.arg.relocatable) { + if (ctx.arg.exportTable) error("--relocatable is incompatible with --export-table"); - if (config->growableTable) + if (ctx.arg.growableTable) error("--relocatable is incompatible with --growable-table"); // Ignore any --import-table, as it's redundant. - config->importTable = true; + ctx.arg.importTable = true; } - if (config->shared) { - if (config->memoryExport.has_value()) { + if (ctx.arg.shared) { + if (ctx.arg.memoryExport.has_value()) { error("--export-memory is incompatible with --shared"); } - if (!config->memoryImport.has_value()) { - config->memoryImport = - std::pair(defaultModule, memoryName); + if (!ctx.arg.memoryImport.has_value()) { + ctx.arg.memoryImport = std::pair( + defaultModule, memoryName); } } // If neither export-memory nor import-memory is specified, default to // exporting memory under its default name. - if (!config->memoryExport.has_value() && !config->memoryImport.has_value()) { - config->memoryExport = memoryName; + if (!ctx.arg.memoryExport.has_value() && !ctx.arg.memoryImport.has_value()) { + ctx.arg.memoryExport = memoryName; } } // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &args) { - if (!config->stripDebug && !config->stripAll && config->compressRelocations) + if (!ctx.arg.stripDebug && !ctx.arg.stripAll && ctx.arg.compressRelocations) error("--compress-relocations is incompatible with output debug" " information. Please pass --strip-debug or --strip-all"); - if (config->ltoPartitions == 0) + if (ctx.arg.ltoPartitions == 0) error("--lto-partitions: number of threads must be > 0"); - if (!get_threadpool_strategy(config->thinLTOJobs)) - error("--thinlto-jobs: invalid job count: " + config->thinLTOJobs); + if (!get_threadpool_strategy(ctx.arg.thinLTOJobs)) + error("--thinlto-jobs: invalid job count: " + ctx.arg.thinLTOJobs); - if (config->pie && config->shared) + if (ctx.arg.pie && ctx.arg.shared) error("-shared and -pie may not be used together"); - if (config->outputFile.empty() && !config->thinLTOIndexOnly) + if (ctx.arg.outputFile.empty() && !ctx.arg.thinLTOIndexOnly) error("no output file specified"); - if (config->importTable && config->exportTable) + if (ctx.arg.importTable && ctx.arg.exportTable) error("--import-table and --export-table may not be used together"); - if (config->relocatable) { - if (!config->entry.empty()) + if (ctx.arg.relocatable) { + if (!ctx.arg.entry.empty()) error("entry point specified for relocatable output file"); - if (config->gcSections) + if (ctx.arg.gcSections) error("-r and --gc-sections may not be used together"); - if (config->compressRelocations) + if (ctx.arg.compressRelocations) error("-r -and --compress-relocations may not be used together"); if (args.hasArg(OPT_undefined)) error("-r -and --undefined may not be used together"); - if (config->pie) + if (ctx.arg.pie) error("-r and -pie may not be used together"); - if (config->sharedMemory) + if (ctx.arg.sharedMemory) error("-r and --shared-memory may not be used together"); - if (config->globalBase) + if (ctx.arg.globalBase) error("-r and --global-base may not by used together"); } @@ -804,31 +802,31 @@ static void checkOptions(opt::InputArgList &args) { // mode, to give anyone using them a heads-up that they will be changing. // // Also, warn about flags which request explicit exports. - if (!config->experimentalPic) { + if (!ctx.arg.experimentalPic) { // -shared will change meaning when Module Linking is implemented. - if (config->shared) { + if (ctx.arg.shared) { warn("creating shared libraries, with -shared, is not yet stable"); } // -pie will change meaning when Module Linking is implemented. - if (config->pie) { + if (ctx.arg.pie) { warn("creating PIEs, with -pie, is not yet stable"); } - if (config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) { + if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic) { warn("dynamic imports are not yet stable " "(--unresolved-symbols=import-dynamic)"); } } - if (config->bsymbolic && !config->shared) { + if (ctx.arg.bsymbolic && !ctx.arg.shared) { warn("-Bsymbolic is only meaningful when combined with -shared"); } if (ctx.isPic) { - if (config->globalBase) + if (ctx.arg.globalBase) error("--global-base may not be used with -shared/-pie"); - if (config->tableBase) + if (ctx.arg.tableBase) error("--table-base may not be used with -shared/-pie"); } } @@ -851,7 +849,7 @@ static Symbol *handleUndefined(StringRef name, const char *option) { if (auto *lazySym = dyn_cast(sym)) { lazySym->extract(); - if (!config->whyExtract.empty()) + if (!ctx.arg.whyExtract.empty()) ctx.whyExtractRecords.emplace_back(option, sym->getFile(), *sym); } @@ -861,20 +859,20 @@ static Symbol *handleUndefined(StringRef name, const char *option) { static void handleLibcall(StringRef name) { Symbol *sym = symtab->find(name); if (sym && sym->isLazy() && isa(sym->getFile())) { - if (!config->whyExtract.empty()) + if (!ctx.arg.whyExtract.empty()) ctx.whyExtractRecords.emplace_back("", sym->getFile(), *sym); cast(sym)->extract(); } } static void writeWhyExtract() { - if (config->whyExtract.empty()) + if (ctx.arg.whyExtract.empty()) return; std::error_code ec; - raw_fd_ostream os(config->whyExtract, ec, sys::fs::OF_None); + raw_fd_ostream os(ctx.arg.whyExtract, ec, sys::fs::OF_None); if (ec) { - error("cannot open --why-extract= file " + config->whyExtract + ": " + + error("cannot open --why-extract= file " + ctx.arg.whyExtract + ": " + ec.message()); return; } @@ -905,14 +903,14 @@ static UndefinedGlobal * createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { auto *sym = cast(symtab->addUndefinedGlobal( name, std::nullopt, std::nullopt, WASM_SYMBOL_UNDEFINED, nullptr, type)); - config->allowUndefinedSymbols.insert(sym->getName()); + ctx.arg.allowUndefinedSymbols.insert(sym->getName()); sym->isUsedInRegularObj = true; return sym; } static InputGlobal *createGlobal(StringRef name, bool isMutable) { llvm::wasm::WasmGlobal wasmGlobal; - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); wasmGlobal.Type = {uint8_t(is64 ? WASM_TYPE_I64 : WASM_TYPE_I32), isMutable}; wasmGlobal.InitExpr = intConst(0, is64); wasmGlobal.SymbolName = name; @@ -931,7 +929,7 @@ static GlobalSymbol *createOptionalGlobal(StringRef name, bool isMutable) { // Create ABI-defined synthetic symbols static void createSyntheticSymbols() { - if (config->relocatable) + if (ctx.arg.relocatable) return; static WasmSignature nullSignature = {{}, {}}; @@ -947,11 +945,11 @@ static void createSyntheticSymbols() { "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_call_ctors")); - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); if (ctx.isPic) { WasmSym::stackPointer = - createUndefinedGlobal("__stack_pointer", config->is64.value_or(false) + createUndefinedGlobal("__stack_pointer", ctx.arg.is64.value_or(false) ? &mutableGlobalTypeI64 : &mutableGlobalTypeI32); // For PIC code, we import two global variables (__memory_base and @@ -970,7 +968,7 @@ static void createSyntheticSymbols() { WasmSym::stackPointer->markLive(); } - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { WasmSym::tlsBase = createGlobalVariable("__tls_base", true); WasmSym::tlsSize = createGlobalVariable("__tls_size", false); WasmSym::tlsAlign = createGlobalVariable("__tls_align", false); @@ -983,12 +981,12 @@ static void createSyntheticSymbols() { } static void createOptionalSymbols() { - if (config->relocatable) + if (ctx.arg.relocatable) return; WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle"); - if (!config->shared) + if (!ctx.arg.shared) WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end"); if (!ctx.isPic) { @@ -1010,7 +1008,7 @@ static void createOptionalSymbols() { // // __tls_size and __tls_align are not needed in this case since they are only // needed for __wasm_init_tls (which we do not create in this case). - if (!config->sharedMemory) + if (!ctx.arg.sharedMemory) WasmSym::tlsBase = createOptionalGlobal("__tls_base", false); } @@ -1035,7 +1033,7 @@ static void processStubLibrariesPreLTO() { // extracted during processStubLibraries, which is too late since // LTO has already being performed at that point. if (needed->isLazy() && isa(needed->getFile())) { - if (!config->whyExtract.empty()) + if (!ctx.arg.whyExtract.empty()) ctx.whyExtractRecords.emplace_back(toString(stub_file), needed->getFile(), *needed); cast(needed)->extract(); @@ -1079,7 +1077,7 @@ static bool addStubSymbolDeps(const StubFile *stub_file, Symbol *sym, if (auto *lazy = dyn_cast(needed)) { depsAdded = true; lazy->extract(); - if (!config->whyExtract.empty()) + if (!ctx.arg.whyExtract.empty()) ctx.whyExtractRecords.emplace_back(toString(stub_file), sym->getFile(), *sym); } diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp index 9383dcaeb4f55..ccdc92f5c8d71 100644 --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -67,7 +67,7 @@ uint32_t InputChunk::getSize() const { return ms->builder.getSize(); if (const auto *f = dyn_cast(this)) { - if (config->compressRelocations && f->file) { + if (ctx.arg.compressRelocations && f->file) { return f->getCompressedSize(); } } @@ -84,7 +84,7 @@ uint32_t InputChunk::getInputSize() const { // Copy this input chunk to an mmap'ed output file and apply relocations. void InputChunk::writeTo(uint8_t *buf) const { if (const auto *f = dyn_cast(this)) { - if (file && config->compressRelocations) + if (file && ctx.arg.compressRelocations) return f->writeCompressed(buf); } else if (const auto *ms = dyn_cast(this)) { ms->builder.write(buf + outSecOff); @@ -269,7 +269,7 @@ static unsigned getRelocWidth(const WasmRelocation &rel, uint64_t value) { // This function only computes the final output size. It must be called // before getSize() is used to calculate of layout of the code section. void InputFunction::calculateSize() { - if (!file || !config->compressRelocations) + if (!file || !ctx.arg.compressRelocations) return; LLVM_DEBUG(dbgs() << "calculateSize: " << name << "\n"); @@ -365,7 +365,7 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const { LLVM_DEBUG(dbgs() << "generating runtime relocations: " << name << " count=" << relocations.size() << "\n"); - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); bool generated = false; unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST : WASM_OPCODE_I32_CONST; diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index d6769bcf5c823..f545449e1246f 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -112,7 +112,7 @@ class InputChunk { InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0, uint32_t flags = 0) : name(name), file(f), alignment(alignment), flags(flags), sectionKind(k), - live(!config->gcSections), discarded(false) {} + live(!ctx.arg.gcSections), discarded(false) {} ArrayRef data() const { return rawData; } uint64_t getTombstone() const; @@ -156,7 +156,7 @@ class SyntheticMergedChunk; // be found by looking at the next one). struct SectionPiece { SectionPiece(size_t off, uint32_t hash, bool live) - : inputOff(off), live(live || !config->gcSections), hash(hash >> 1) {} + : inputOff(off), live(live || !ctx.arg.gcSections), hash(hash >> 1) {} uint32_t inputOff; uint32_t live : 1; diff --git a/lld/wasm/InputElement.h b/lld/wasm/InputElement.h index 10dc2a3e4a826..c2a24c8ff5f4e 100644 --- a/lld/wasm/InputElement.h +++ b/lld/wasm/InputElement.h @@ -24,7 +24,7 @@ namespace wasm { class InputElement { protected: InputElement(StringRef name, ObjFile *f) - : file(f), live(!config->gcSections), name(name) {} + : file(f), live(!ctx.arg.gcSections), name(name) {} public: StringRef getName() const { return name; } @@ -65,7 +65,7 @@ class InputGlobal : public InputElement { const WasmInitExpr &getInitExpr() const { return initExpr; } void setPointerValue(uint64_t value) { - initExpr = intConst(value, config->is64.value_or(false)); + initExpr = intConst(value, ctx.arg.is64.value_or(false)); } private: diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp index 221f02aa1c157..614cddddd1b19 100644 --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -47,7 +47,7 @@ std::string toString(const wasm::InputFile *file) { namespace wasm { std::string replaceThinLTOSuffix(StringRef path) { - auto [suffix, repl] = config->thinLTOObjectSuffixReplace; + auto [suffix, repl] = ctx.arg.thinLTOObjectSuffixReplace; if (path.consume_back(suffix)) return (path + repl).str(); return std::string(path); @@ -55,10 +55,10 @@ std::string replaceThinLTOSuffix(StringRef path) { void InputFile::checkArch(Triple::ArchType arch) const { bool is64 = arch == Triple::wasm64; - if (is64 && !config->is64) { + if (is64 && !ctx.arg.is64) { fatal(toString(this) + ": must specify -mwasm64 to process wasm64 object files"); - } else if (config->is64.value_or(false) != is64) { + } else if (ctx.arg.is64.value_or(false) != is64) { fatal(toString(this) + ": wasm32 object file can't be linked in wasm64 mode"); } @@ -169,7 +169,7 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone, uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex(); if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB || reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB64) - index -= config->tableBase; + index -= ctx.arg.tableBase; return index; } case R_WASM_MEMORY_ADDR_LEB: @@ -360,7 +360,7 @@ void ObjFile::addLegacyIndirectFunctionTableIfNeeded( } static bool shouldMerge(const WasmSection &sec) { - if (config->optimize == 0) + if (ctx.arg.optimize == 0) return false; // Sadly we don't have section attributes yet for custom sections, so we // currently go by the name alone. @@ -383,7 +383,7 @@ static bool shouldMerge(const WasmSegment &seg) { // On a regular link we don't merge sections if -O0 (default is -O1). This // sometimes makes the linker significantly faster, although the output will // be bigger. - if (config->optimize == 0) + if (ctx.arg.optimize == 0) return false; // A mergeable section with size 0 is useless because they don't have @@ -845,7 +845,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef m, StringRef archiveName, this->archiveName = std::string(archiveName); std::string path = mb.getBufferIdentifier().str(); - if (config->thinLTOIndexOnly) + if (ctx.arg.thinLTOIndexOnly) path = replaceThinLTOSuffix(mb.getBufferIdentifier()); // ThinLTO assumes that all MemoryBufferRefs given to it have a unique diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h index 1b1de98d2d17a..fd7fcb13f4426 100644 --- a/lld/wasm/InputFiles.h +++ b/lld/wasm/InputFiles.h @@ -73,7 +73,7 @@ class InputFile { protected: InputFile(Kind k, MemoryBufferRef m) - : mb(m), fileKind(k), live(!config->gcSections) {} + : mb(m), fileKind(k), live(!ctx.arg.gcSections) {} void checkArch(llvm::Triple::ArchType arch) const; diff --git a/lld/wasm/LTO.cpp b/lld/wasm/LTO.cpp index d9fff748bdb65..b9bd48acd6dc1 100644 --- a/lld/wasm/LTO.cpp +++ b/lld/wasm/LTO.cpp @@ -44,8 +44,8 @@ using namespace lld::wasm; using namespace lld; static std::string getThinLTOOutputFile(StringRef modulePath) { - return lto::getThinLTOOutputFile(modulePath, config->thinLTOPrefixReplaceOld, - config->thinLTOPrefixReplaceNew); + return lto::getThinLTOOutputFile(modulePath, ctx.arg.thinLTOPrefixReplaceOld, + ctx.arg.thinLTOPrefixReplaceNew); } static lto::Config createConfig() { @@ -56,23 +56,23 @@ static lto::Config createConfig() { c.Options.FunctionSections = true; c.Options.DataSections = true; - c.DisableVerify = config->disableVerify; + c.DisableVerify = ctx.arg.disableVerify; c.DiagHandler = diagnosticHandler; - c.OptLevel = config->ltoo; + c.OptLevel = ctx.arg.ltoo; c.MAttrs = getMAttrs(); - c.CGOptLevel = config->ltoCgo; - c.DebugPassManager = config->ltoDebugPassManager; - c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty(); + c.CGOptLevel = ctx.arg.ltoCgo; + c.DebugPassManager = ctx.arg.ltoDebugPassManager; + c.AlwaysEmitRegularLTOObj = !ctx.arg.ltoObjPath.empty(); - if (config->relocatable) + if (ctx.arg.relocatable) c.RelocModel = std::nullopt; else if (ctx.isPic) c.RelocModel = Reloc::PIC_; else c.RelocModel = Reloc::Static; - if (config->saveTemps) - checkError(c.addSaveTemps(config->outputFile.str() + ".", + if (ctx.arg.saveTemps) + checkError(c.addSaveTemps(ctx.arg.outputFile.str() + ".", /*UseInputModulePath*/ true)); return c; } @@ -81,27 +81,27 @@ namespace lld::wasm { BitcodeCompiler::BitcodeCompiler() { // Initialize indexFile. - if (!config->thinLTOIndexOnlyArg.empty()) - indexFile = openFile(config->thinLTOIndexOnlyArg); + if (!ctx.arg.thinLTOIndexOnlyArg.empty()) + indexFile = openFile(ctx.arg.thinLTOIndexOnlyArg); // Initialize ltoObj. lto::ThinBackend backend; auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); }; - if (config->thinLTOIndexOnly) { + if (ctx.arg.thinLTOIndexOnly) { backend = lto::createWriteIndexesThinBackend( - llvm::hardware_concurrency(config->thinLTOJobs), - std::string(config->thinLTOPrefixReplaceOld), - std::string(config->thinLTOPrefixReplaceNew), - std::string(config->thinLTOPrefixReplaceNativeObject), - config->thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite); + llvm::hardware_concurrency(ctx.arg.thinLTOJobs), + std::string(ctx.arg.thinLTOPrefixReplaceOld), + std::string(ctx.arg.thinLTOPrefixReplaceNew), + std::string(ctx.arg.thinLTOPrefixReplaceNativeObject), + ctx.arg.thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite); } else { backend = lto::createInProcessThinBackend( - llvm::heavyweight_hardware_concurrency(config->thinLTOJobs), - onIndexWrite, config->thinLTOEmitIndexFiles, - config->thinLTOEmitImportsFiles); + llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs), + onIndexWrite, ctx.arg.thinLTOEmitIndexFiles, + ctx.arg.thinLTOEmitImportsFiles); } ltoObj = std::make_unique(createConfig(), backend, - config->ltoPartitions); + ctx.arg.ltoPartitions); } BitcodeCompiler::~BitcodeCompiler() = default; @@ -123,7 +123,7 @@ void BitcodeCompiler::add(BitcodeFile &f) { ArrayRef syms = f.getSymbols(); std::vector resols(syms.size()); - if (config->thinLTOEmitIndexFiles) { + if (ctx.arg.thinLTOEmitIndexFiles) { thinIndices.insert(obj.getName()); } @@ -139,7 +139,7 @@ void BitcodeCompiler::add(BitcodeFile &f) { // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f; - r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj || + r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj || sym->isNoStrip() || (r.Prevailing && sym->isExported()); if (r.Prevailing) @@ -175,7 +175,7 @@ static void thinLTOCreateEmptyIndexFiles() { ModuleSummaryIndex m(/*HaveGVs*/ false); m.setSkipModuleByDistributedBackend(); writeIndexToFile(m, *os); - if (config->thinLTOEmitImportsFiles) + if (ctx.arg.thinLTOEmitImportsFiles) openFile(path + ".imports"); } } @@ -191,8 +191,8 @@ std::vector BitcodeCompiler::compile() { // to cache native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. FileCache cache; - if (!config->thinLTOCacheDir.empty()) - cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir, + if (!ctx.arg.thinLTOCacheDir.empty()) + cache = check(localCache("ThinLTO", "Thin", ctx.arg.thinLTOCacheDir, [&](size_t task, const Twine &moduleName, std::unique_ptr mb) { files[task] = std::move(mb); @@ -210,16 +210,16 @@ std::vector BitcodeCompiler::compile() { for (StringRef s : thinIndices) { std::string path(s); openFile(path + ".thinlto.bc"); - if (config->thinLTOEmitImportsFiles) + if (ctx.arg.thinLTOEmitImportsFiles) openFile(path + ".imports"); } - if (config->thinLTOEmitIndexFiles) + if (ctx.arg.thinLTOEmitIndexFiles) thinLTOCreateEmptyIndexFiles(); - if (config->thinLTOIndexOnly) { - if (!config->ltoObjPath.empty()) - saveBuffer(buf[0].second, config->ltoObjPath); + if (ctx.arg.thinLTOIndexOnly) { + if (!ctx.arg.ltoObjPath.empty()) + saveBuffer(buf[0].second, ctx.arg.ltoObjPath); // ThinLTO with index only option is required to generate only the index // files. After that, we exit from linker and ThinLTO backend runs in a @@ -229,8 +229,8 @@ std::vector BitcodeCompiler::compile() { return {}; } - if (!config->thinLTOCacheDir.empty()) - pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy, files); + if (!ctx.arg.thinLTOCacheDir.empty()) + pruneCache(ctx.arg.thinLTOCacheDir, ctx.arg.thinLTOCachePolicy, files); std::vector ret; for (unsigned i = 0; i != maxTasks; ++i) { @@ -239,7 +239,7 @@ std::vector BitcodeCompiler::compile() { if (objBuf.empty()) continue; ret.emplace_back(objBuf.data(), objBuf.size()); - if (!config->saveTemps) + if (!ctx.arg.saveTemps) continue; // If the input bitcode file is path/to/x.o and -o specifies a.out, the @@ -248,7 +248,7 @@ std::vector BitcodeCompiler::compile() { StringRef ltoObjName; if (bitcodeFilePath == "ld-temp.o") { ltoObjName = - saver().save(Twine(config->outputFile) + ".lto" + + saver().save(Twine(ctx.arg.outputFile) + ".lto" + (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".o"); } else { StringRef directory = sys::path::parent_path(bitcodeFilePath); @@ -258,7 +258,7 @@ std::vector BitcodeCompiler::compile() { StringRef baseName = bitcodeFilePath.ends_with(")") ? sys::path::filename(bitcodeFilePath) : sys::path::stem(bitcodeFilePath); - StringRef outputFileBaseName = sys::path::filename(config->outputFile); + StringRef outputFileBaseName = sys::path::filename(ctx.arg.outputFile); SmallString<256> path; sys::path::append(path, directory, outputFileBaseName + ".lto." + baseName + ".o"); @@ -268,10 +268,10 @@ std::vector BitcodeCompiler::compile() { saveBuffer(objBuf, ltoObjName); } - if (!config->ltoObjPath.empty()) { - saveBuffer(buf[0].second, config->ltoObjPath); + if (!ctx.arg.ltoObjPath.empty()) { + saveBuffer(buf[0].second, ctx.arg.ltoObjPath); for (unsigned i = 1; i != maxTasks; ++i) - saveBuffer(buf[i].second, config->ltoObjPath + Twine(i)); + saveBuffer(buf[i].second, ctx.arg.ltoObjPath + Twine(i)); } for (std::unique_ptr &file : files) diff --git a/lld/wasm/MapFile.cpp b/lld/wasm/MapFile.cpp index c96b64cb64838..d8487e48b8c6b 100644 --- a/lld/wasm/MapFile.cpp +++ b/lld/wasm/MapFile.cpp @@ -103,14 +103,14 @@ getSymbolStrings(ArrayRef syms) { } void lld::wasm::writeMapFile(ArrayRef outputSections) { - if (config->mapFile.empty()) + if (ctx.arg.mapFile.empty()) return; // Open a map file for writing. std::error_code ec; - raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); + raw_fd_ostream os(ctx.arg.mapFile, ec, sys::fs::OF_None); if (ec) { - error("cannot open " + config->mapFile + ": " + ec.message()); + error("cannot open " + ctx.arg.mapFile + ": " + ec.message()); return; } diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp index 1b99f03747fb0..13c7a3d894fe3 100644 --- a/lld/wasm/MarkLive.cpp +++ b/lld/wasm/MarkLive.cpp @@ -106,8 +106,8 @@ void MarkLive::enqueueRetainedSegments(const ObjFile *file) { void MarkLive::run() { // Add GC root symbols. - if (!config->entry.empty()) - enqueue(symtab->find(config->entry)); + if (!ctx.arg.entry.empty()) + enqueue(symtab->find(ctx.arg.entry)); // We need to preserve any no-strip or exported symbol for (Symbol *sym : symtab->symbols()) @@ -166,7 +166,7 @@ void MarkLive::mark() { } void markLive() { - if (!config->gcSections) + if (!ctx.arg.gcSections) return; LLVM_DEBUG(dbgs() << "markLive\n"); @@ -175,7 +175,7 @@ void markLive() { marker.run(); // Report garbage-collected sections. - if (config->printGcSections) { + if (ctx.arg.printGcSections) { for (const ObjFile *obj : ctx.objectFiles) { for (InputChunk *c : obj->functions) if (!c->live) @@ -207,7 +207,7 @@ void markLive() { bool MarkLive::isCallCtorsLive() { // In a reloctable link, we don't call `__wasm_call_ctors`. - if (config->relocatable) + if (ctx.arg.relocatable) return false; // In Emscripten-style PIC, we call `__wasm_call_ctors` which calls diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp index e4f75829ec4c3..95f7ecc29de6b 100644 --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -105,13 +105,13 @@ void DataSection::finalizeContents() { }); #endif - assert((config->sharedMemory || !ctx.isPic || config->extendedConst || + assert((ctx.arg.sharedMemory || !ctx.isPic || ctx.arg.extendedConst || activeCount <= 1) && "output segments should have been combined by now"); writeUleb128(os, segmentCount, "data segment count"); bodySize = dataSectionHeader.size(); - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); for (OutputSegment *segment : segments) { if (!segment->requiredInBinary()) @@ -121,7 +121,7 @@ void DataSection::finalizeContents() { if (segment->initFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX) writeUleb128(os, 0, "memory index"); if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) { - if (ctx.isPic && config->extendedConst) { + if (ctx.isPic && ctx.arg.extendedConst) { writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get"); writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "literal (global index)"); diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp index 45ad32701616a..745dfde76ab70 100644 --- a/lld/wasm/Relocations.cpp +++ b/lld/wasm/Relocations.cpp @@ -22,13 +22,13 @@ static bool requiresGOTAccess(const Symbol *sym) { if (sym->isShared()) return true; if (!ctx.isPic && - config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic) + ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic) return false; if (sym->isHidden() || sym->isLocal()) return false; // With `-Bsymbolic` (or when building an executable) as don't need to use // the GOT for symbols that are defined within the current module. - if (sym->isDefined() && (!config->shared || config->bsymbolic)) + if (sym->isDefined() && (!ctx.arg.shared || ctx.arg.bsymbolic)) return false; return true; } @@ -38,15 +38,15 @@ static bool allowUndefined(const Symbol* sym) { // link time. if (sym->isImported()) return true; - if (isa(sym) && config->importUndefined) + if (isa(sym) && ctx.arg.importUndefined) return true; - return config->allowUndefinedSymbols.count(sym->getName()) != 0; + return ctx.arg.allowUndefinedSymbols.count(sym->getName()) != 0; } static void reportUndefined(ObjFile *file, Symbol *sym) { if (!allowUndefined(sym)) { - switch (config->unresolvedSymbols) { + switch (ctx.arg.unresolvedSymbols) { case UnresolvedPolicy::ReportError: error(toString(file) + ": undefined symbol: " + toString(*sym)); break; @@ -63,8 +63,8 @@ static void reportUndefined(ObjFile *file, Symbol *sym) { if (auto *f = dyn_cast(sym)) { if (!f->stubFunction && - config->unresolvedSymbols != UnresolvedPolicy::ImportDynamic && - !config->importUndefined) { + ctx.arg.unresolvedSymbols != UnresolvedPolicy::ImportDynamic && + !ctx.arg.importUndefined) { f->stubFunction = symtab->createUndefinedStub(*f->getSignature()); f->stubFunction->markLive(); // Mark the function itself as a stub which prevents it from being @@ -125,7 +125,7 @@ void scanRelocations(InputChunk *chunk) { // In single-threaded builds TLS is lowered away and TLS data can be // merged with normal data and allowing TLS relocation in non-TLS // segments. - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { if (!sym->isTLS()) { error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + @@ -146,7 +146,7 @@ void scanRelocations(InputChunk *chunk) { if (ctx.isPic || (sym->isUndefined() && - config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) { + ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) { switch (reloc.Type) { case R_WASM_TABLE_INDEX_SLEB: case R_WASM_TABLE_INDEX_SLEB64: @@ -173,7 +173,7 @@ void scanRelocations(InputChunk *chunk) { } } - if (!config->relocatable && sym->isUndefined()) { + if (!ctx.arg.relocatable && sym->isUndefined()) { switch (reloc.Type) { case R_WASM_TABLE_INDEX_REL_SLEB: case R_WASM_TABLE_INDEX_REL_SLEB64: diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 4cbf44b4d0398..f57359083d242 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -53,7 +53,7 @@ void SymbolTable::addFile(InputFile *file, StringRef symName) { return; } - if (config->trace) + if (ctx.arg.trace) message(toString(file)); // LLVM bitcode file @@ -125,7 +125,7 @@ std::pair SymbolTable::insertName(StringRef name) { sym->canInline = true; sym->traced = trace; sym->forceExport = false; - sym->referenced = !config->gcSections; + sym->referenced = !ctx.arg.gcSections; symVector.emplace_back(sym); return {sym, true}; } @@ -235,7 +235,7 @@ DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, uint64_t value) { Symbol *s = find(name); - if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) + if (!s && (ctx.arg.exportAll || ctx.arg.exportedSymbols.count(name) != 0)) s = insertName(name).first; else if (!s || s->isDefined()) return nullptr; @@ -317,7 +317,7 @@ static bool shouldReplace(const Symbol *existing, InputFile *newFile, } // Neither symbol is week. They conflict. - if (config->allowMultipleDefinition) + if (ctx.arg.allowMultipleDefinition) return false; errorOrWarn("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + @@ -387,7 +387,7 @@ Symbol *SymbolTable::addSharedFunction(StringRef name, uint32_t flags, checkSig = ud->isCalledDirectly; if (checkSig && !signatureMatches(existingFunction, sig)) { - if (config->shlibSigCheck) { + if (ctx.arg.shlibSigCheck) { reportFunctionSignatureMismatch(name, existingFunction, sig, file); } else { // With --no-shlib-sigcheck we ignore the signature of the function as @@ -637,7 +637,7 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name, lazy->signature = sig; } else { lazy->extract(); - if (!config->whyExtract.empty()) + if (!ctx.arg.whyExtract.empty()) ctx.whyExtractRecords.emplace_back(toString(file), s->getFile(), *s); } } else { @@ -652,7 +652,7 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name, if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { if (existingFunction->isShared()) { // Special handling for when the existing function is a shared symbol - if (config->shlibSigCheck) { + if (ctx.arg.shlibSigCheck) { reportFunctionSignatureMismatch(name, existingFunction, sig, file); } else { existingFunction->signature = sig; @@ -788,12 +788,12 @@ TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { WasmTableType *type = make(); type->ElemType = ValType::FUNCREF; type->Limits = limits; - uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; + uint32_t flags = ctx.arg.exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; flags |= WASM_SYMBOL_UNDEFINED; Symbol *sym = addUndefinedTable(name, name, defaultModule, flags, nullptr, type); sym->markLive(); - sym->forceExport = config->exportTable; + sym->forceExport = ctx.arg.exportTable; return cast(sym); } @@ -803,10 +803,10 @@ TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) { WasmTableType type{ValType::FUNCREF, limits}; WasmTable desc{invalidIndex, type, name}; InputTable *table = make(desc, nullptr); - uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; + uint32_t flags = ctx.arg.exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; TableSymbol *sym = addSyntheticTable(name, flags, table); sym->markLive(); - sym->forceExport = config->exportTable; + sym->forceExport = ctx.arg.exportTable; return sym; } @@ -830,7 +830,7 @@ TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) { } } - if (config->importTable) { + if (ctx.arg.importTable) { if (existing) { existing->importModule = defaultModule; existing->importName = functionTableName; @@ -838,7 +838,7 @@ TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) { } if (required) return createUndefinedIndirectFunctionTable(functionTableName); - } else if ((existing && existing->isLive()) || config->exportTable || + } else if ((existing && existing->isLive()) || ctx.arg.exportTable || required) { // A defined table is required. Either because the user request an exported // table or because the table symbol is already live. The existing table is @@ -885,7 +885,7 @@ void SymbolTable::addLazy(StringRef name, InputFile *file) { LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); const InputFile *oldFile = s->getFile(); LazySymbol(name, 0, file).extract(); - if (!config->whyExtract.empty()) + if (!ctx.arg.whyExtract.empty()) ctx.whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s); } diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index e62e7bec609f5..a687fd6d6c4ef 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -35,7 +35,7 @@ std::string maybeDemangleSymbol(StringRef name) { // `main` in the case where we need to pass it arguments. if (name == "__main_argc_argv") return "main"; - if (wasm::config->demangle) + if (wasm::ctx.arg.demangle) return demangle(name); return name.str(); } @@ -235,10 +235,10 @@ bool Symbol::isExported() const { // Shared libraries must export all weakly defined symbols // in case they contain the version that will be chosen by // the dynamic linker. - if (config->shared && isLive() && isWeak() && !isHidden()) + if (ctx.arg.shared && isLive() && isWeak() && !isHidden()) return true; - if (config->exportAll || (config->exportDynamic && !isHidden())) + if (ctx.arg.exportAll || (ctx.arg.exportDynamic && !isHidden())) return true; return isExportedExplicit(); diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index 80b658773bd20..b409fffc50a6c 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -139,7 +139,7 @@ class Symbol { protected: Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f) - : name(name), file(f), symbolKind(k), referenced(!config->gcSections), + : name(name), file(f), symbolKind(k), referenced(!ctx.arg.gcSections), requiresGOT(false), isUsedInRegularObj(false), forceExport(false), forceImport(false), canInline(false), traced(false), isStub(false), flags(flags) {} diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 6b32d12ebeb45..715fba1ee6da5 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -55,7 +55,7 @@ class SubSection { bool DylinkSection::isNeeded() const { return ctx.isPic || - config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic || + ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic || !ctx.sharedFiles.empty(); } @@ -162,7 +162,7 @@ void TypeSection::writeBody() { uint32_t ImportSection::getNumImports() const { assert(isSealed); uint32_t numImports = importedSymbols.size() + gotSymbols.size(); - if (config->memoryImport.has_value()) + if (ctx.arg.memoryImport.has_value()) ++numImports; return numImports; } @@ -232,20 +232,20 @@ void ImportSection::writeBody() { writeUleb128(os, getNumImports(), "import count"); - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); - if (config->memoryImport) { + if (ctx.arg.memoryImport) { WasmImport import; - import.Module = config->memoryImport->first; - import.Field = config->memoryImport->second; + import.Module = ctx.arg.memoryImport->first; + import.Field = ctx.arg.memoryImport->second; import.Kind = WASM_EXTERNAL_MEMORY; import.Memory.Flags = 0; import.Memory.Minimum = out.memorySec->numMemoryPages; - if (out.memorySec->maxMemoryPages != 0 || config->sharedMemory) { + if (out.memorySec->maxMemoryPages != 0 || ctx.arg.sharedMemory) { import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; import.Memory.Maximum = out.memorySec->maxMemoryPages; } - if (config->sharedMemory) + if (ctx.arg.sharedMemory) import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; if (is64) import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64; @@ -351,14 +351,14 @@ void TableSection::assignIndexes() { void MemorySection::writeBody() { raw_ostream &os = bodyOutputStream; - bool hasMax = maxMemoryPages != 0 || config->sharedMemory; + bool hasMax = maxMemoryPages != 0 || ctx.arg.sharedMemory; writeUleb128(os, 1, "memory count"); unsigned flags = 0; if (hasMax) flags |= WASM_LIMITS_FLAG_HAS_MAX; - if (config->sharedMemory) + if (ctx.arg.sharedMemory) flags |= WASM_LIMITS_FLAG_IS_SHARED; - if (config->is64.value_or(false)) + if (ctx.arg.is64.value_or(false)) flags |= WASM_LIMITS_FLAG_IS_64; writeUleb128(os, flags, "memory limits flags"); writeUleb128(os, numMemoryPages, "initial pages"); @@ -415,8 +415,8 @@ void GlobalSection::addInternalGOTEntry(Symbol *sym) { } void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { - assert(!config->extendedConst); - bool is64 = config->is64.value_or(false); + assert(!ctx.arg.extendedConst); + bool is64 = ctx.arg.is64.value_or(false); unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST : WASM_OPCODE_I32_CONST; unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD @@ -466,7 +466,7 @@ void GlobalSection::writeBody() { writeGlobalType(os, g->getType()); writeInitExpr(os, g->getInitExpr()); } - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; for (const Symbol *sym : internalGotSymbols) { bool mutable_ = false; @@ -474,11 +474,11 @@ void GlobalSection::writeBody() { // In the case of dynamic linking, unless we have 'extended-const' // available, these global must to be mutable since they get updated to // the correct runtime value during `__wasm_apply_global_relocs`. - if (!config->extendedConst && ctx.isPic && !sym->isTLS()) + if (!ctx.arg.extendedConst && ctx.isPic && !sym->isTLS()) mutable_ = true; // With multi-theadeding any TLS globals must be mutable since they get // set during `__wasm_apply_global_tls_relocs` - if (config->sharedMemory && sym->isTLS()) + if (ctx.arg.sharedMemory && sym->isTLS()) mutable_ = true; } WasmGlobalType type{itype, mutable_}; @@ -487,7 +487,7 @@ void GlobalSection::writeBody() { bool useExtendedConst = false; uint32_t globalIdx; int64_t offset; - if (config->extendedConst && ctx.isPic) { + if (ctx.arg.extendedConst && ctx.isPic) { if (auto *d = dyn_cast(sym)) { if (!sym->isTLS()) { globalIdx = WasmSym::memoryBase->getGlobalIndex(); @@ -518,7 +518,7 @@ void GlobalSection::writeBody() { // In the sharedMemory case TLS globals are set during // `__wasm_apply_global_tls_relocs`, but in the non-shared case // we know the absolute value at link time. - initExpr = intConst(d->getVA(/*absolute=*/!config->sharedMemory), is64); + initExpr = intConst(d->getVA(/*absolute=*/!ctx.arg.sharedMemory), is64); else if (auto *f = dyn_cast(sym)) initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64); else { @@ -566,7 +566,7 @@ void ElemSection::addEntry(FunctionSymbol *sym) { // They only exist so that the calls to missing functions can validate. if (sym->hasTableIndex() || sym->isStub) return; - sym->setTableIndex(config->tableBase + indirectFunctions.size()); + sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); indirectFunctions.emplace_back(sym); } @@ -589,8 +589,8 @@ void ElemSection::writeBody() { initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; initExpr.Inst.Value.Global = WasmSym::tableBase->getGlobalIndex(); } else { - bool is64 = config->is64.value_or(false); - initExpr = intConst(config->tableBase, is64); + bool is64 = ctx.arg.is64.value_or(false); + initExpr = intConst(ctx.arg.tableBase, is64); } writeInitExpr(os, initExpr); @@ -602,7 +602,7 @@ void ElemSection::writeBody() { } writeUleb128(os, indirectFunctions.size(), "elem count"); - uint32_t tableIndex = config->tableBase; + uint32_t tableIndex = ctx.arg.tableBase; for (const FunctionSymbol *sym : indirectFunctions) { assert(sym->getTableIndex() == tableIndex); (void) tableIndex; @@ -622,7 +622,7 @@ void DataCountSection::writeBody() { } bool DataCountSection::isNeeded() const { - return numSegments && config->sharedMemory; + return numSegments && ctx.arg.sharedMemory; } void LinkingSection::writeBody() { @@ -786,9 +786,9 @@ unsigned NameSection::numNamedDataSegments() const { void NameSection::writeBody() { { SubSection sub(WASM_NAMES_MODULE); - StringRef moduleName = config->soName; - if (config->soName.empty()) - moduleName = llvm::sys::path::filename(config->outputFile); + StringRef moduleName = ctx.arg.soName; + if (ctx.arg.soName.empty()) + moduleName = llvm::sys::path::filename(ctx.arg.outputFile); writeStr(sub.os, moduleName, "module name"); sub.writeTo(bodyOutputStream); } @@ -917,14 +917,14 @@ void RelocSection::writeBody() { } static size_t getHashSize() { - switch (config->buildId) { + switch (ctx.arg.buildId) { case BuildIdKind::Fast: case BuildIdKind::Uuid: return 16; case BuildIdKind::Sha1: return 20; case BuildIdKind::Hexstring: - return config->buildIdVector.size(); + return ctx.arg.buildIdVector.size(); case BuildIdKind::None: return 0; } diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h index 10183e93d2a28..068fbed11f4a7 100644 --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -228,7 +228,7 @@ class MemorySection : public SyntheticSection { public: MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {} - bool isNeeded() const override { return !config->memoryImport.has_value(); } + bool isNeeded() const override { return !ctx.arg.memoryImport.has_value(); } void writeBody() override; uint64_t numMemoryPages = 0; @@ -286,7 +286,7 @@ class GlobalSection : public SyntheticSection { // transform a `global.get` to an `i32.const`. void addInternalGOTEntry(Symbol *sym); bool needsRelocations() { - if (config->extendedConst) + if (ctx.arg.extendedConst) return false; return llvm::any_of(internalGotSymbols, [=](Symbol *sym) { return !sym->isTLS(); }); @@ -354,7 +354,7 @@ class LinkingSection : public SyntheticSection { : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"), initFunctions(initFunctions), dataSegments(dataSegments) {} bool isNeeded() const override { - return config->relocatable || config->emitRelocs; + return ctx.arg.relocatable || ctx.arg.emitRelocs; } void writeBody() override; void addToSymtab(Symbol *sym); @@ -373,7 +373,7 @@ class NameSection : public SyntheticSection { : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"), segments(segments) {} bool isNeeded() const override { - if (config->stripAll && !config->keepSections.count(name)) + if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name)) return false; return numNames() > 0; } @@ -396,7 +396,7 @@ class ProducersSection : public SyntheticSection { ProducersSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {} bool isNeeded() const override { - if (config->stripAll && !config->keepSections.count(name)) + if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name)) return false; return fieldCount() > 0; } @@ -417,7 +417,7 @@ class TargetFeaturesSection : public SyntheticSection { TargetFeaturesSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {} bool isNeeded() const override { - if (config->stripAll && !config->keepSections.count(name)) + if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name)) return false; return features.size() > 0; } @@ -443,7 +443,7 @@ class BuildIdSection : public SyntheticSection { BuildIdSection(); void writeBody() override; bool isNeeded() const override { - return config->buildId != BuildIdKind::None; + return ctx.arg.buildId != BuildIdKind::None; } void writeBuildId(llvm::ArrayRef buf); void writeTo(uint8_t *buf) override { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index aeac1a51824f5..76e38f548157c 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -132,7 +132,7 @@ class Writer { void Writer::calculateCustomSections() { log("calculateCustomSections"); - bool stripDebug = config->stripDebug || config->stripAll; + bool stripDebug = ctx.arg.stripDebug || ctx.arg.stripAll; for (ObjFile *file : ctx.objectFiles) { for (InputChunk *section : file->customSections) { // Exclude COMDAT sections that are not selected for inclusion @@ -172,7 +172,7 @@ void Writer::createCustomSections() { LLVM_DEBUG(dbgs() << "createCustomSection: " << name << "\n"); OutputSection *sec = make(std::string(name), pair.second); - if (config->relocatable || config->emitRelocs) { + if (ctx.arg.relocatable || ctx.arg.emitRelocs) { auto *sym = make(sec); out.linkingSec->addToSymtab(sym); sec->sectionSym = sym; @@ -282,8 +282,8 @@ static void makeUUID(unsigned version, llvm::ArrayRef fileHash, void Writer::writeBuildId() { if (!out.buildIdSec->isNeeded()) return; - if (config->buildId == BuildIdKind::Hexstring) { - out.buildIdSec->writeBuildId(config->buildIdVector); + if (ctx.arg.buildId == BuildIdKind::Hexstring) { + out.buildIdSec->writeBuildId(ctx.arg.buildIdVector); return; } @@ -292,7 +292,7 @@ void Writer::writeBuildId() { std::vector buildId(hashSize); llvm::ArrayRef buf{buffer->getBufferStart(), size_t(fileSize)}; - switch (config->buildId) { + switch (ctx.arg.buildId) { case BuildIdKind::Fast: { std::vector fileHash(8); computeHash(fileHash, buf, [](uint8_t *dest, ArrayRef arr) { @@ -324,9 +324,9 @@ static void setGlobalPtr(DefinedGlobal *g, uint64_t memoryPtr) { // to each of the input data sections as well as the explicit stack region. // The default memory layout is as follows, from low to high. // -// - initialized data (starting at config->globalBase) +// - initialized data (starting at ctx.arg.globalBase) // - BSS data (not currently implemented in llvm) -// - explicit stack (config->ZStackSize) +// - explicit stack (ctx.arg.ZStackSize) // - heap start / unallocated // // The --stack-first option means that stack is placed before any static data. @@ -337,33 +337,33 @@ void Writer::layoutMemory() { uint64_t memoryPtr = 0; auto placeStack = [&]() { - if (config->relocatable || ctx.isPic) + if (ctx.arg.relocatable || ctx.isPic) return; memoryPtr = alignTo(memoryPtr, stackAlignment); if (WasmSym::stackLow) WasmSym::stackLow->setVA(memoryPtr); - if (config->zStackSize != alignTo(config->zStackSize, stackAlignment)) + if (ctx.arg.zStackSize != alignTo(ctx.arg.zStackSize, stackAlignment)) error("stack size must be " + Twine(stackAlignment) + "-byte aligned"); - log("mem: stack size = " + Twine(config->zStackSize)); + log("mem: stack size = " + Twine(ctx.arg.zStackSize)); log("mem: stack base = " + Twine(memoryPtr)); - memoryPtr += config->zStackSize; + memoryPtr += ctx.arg.zStackSize; setGlobalPtr(cast(WasmSym::stackPointer), memoryPtr); if (WasmSym::stackHigh) WasmSym::stackHigh->setVA(memoryPtr); log("mem: stack top = " + Twine(memoryPtr)); }; - if (config->stackFirst) { + if (ctx.arg.stackFirst) { placeStack(); - if (config->globalBase) { - if (config->globalBase < memoryPtr) { + if (ctx.arg.globalBase) { + if (ctx.arg.globalBase < memoryPtr) { error("--global-base cannot be less than stack size when --stack-first is used"); return; } - memoryPtr = config->globalBase; + memoryPtr = ctx.arg.globalBase; } } else { - memoryPtr = config->globalBase; + memoryPtr = ctx.arg.globalBase; } log("mem: global base = " + Twine(memoryPtr)); @@ -385,7 +385,7 @@ void Writer::layoutMemory() { log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name, memoryPtr, seg->size, seg->alignment)); - if (!config->relocatable && seg->isTLS()) { + if (!ctx.arg.relocatable && seg->isTLS()) { if (WasmSym::tlsSize) { auto *tlsSize = cast(WasmSym::tlsSize); setGlobalPtr(tlsSize, seg->size); @@ -394,7 +394,7 @@ void Writer::layoutMemory() { auto *tlsAlign = cast(WasmSym::tlsAlign); setGlobalPtr(tlsAlign, int64_t{1} << seg->alignment); } - if (!config->sharedMemory && WasmSym::tlsBase) { + if (!ctx.arg.sharedMemory && WasmSym::tlsBase) { auto *tlsBase = cast(WasmSym::tlsBase); setGlobalPtr(tlsBase, memoryPtr); } @@ -404,7 +404,7 @@ void Writer::layoutMemory() { } // Make space for the memory initialization flag - if (config->sharedMemory && hasPassiveInitializedSegments()) { + if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) { memoryPtr = alignTo(memoryPtr, 4); WasmSym::initMemoryFlag = symtab->addSyntheticDataSymbol( "__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN); @@ -423,7 +423,7 @@ void Writer::layoutMemory() { if (ctx.isPic) out.dylinkSec->memSize = staticDataSize; - if (!config->stackFirst) + if (!ctx.arg.stackFirst) placeStack(); if (WasmSym::heapBase) { @@ -438,31 +438,31 @@ void Writer::layoutMemory() { } uint64_t maxMemorySetting = 1ULL << 32; - if (config->is64.value_or(false)) { + if (ctx.arg.is64.value_or(false)) { // TODO: Update once we decide on a reasonable limit here: // https://github.com/WebAssembly/memory64/issues/33 maxMemorySetting = 1ULL << 34; } - if (config->initialHeap != 0) { - if (config->initialHeap != alignTo(config->initialHeap, WasmPageSize)) + if (ctx.arg.initialHeap != 0) { + if (ctx.arg.initialHeap != alignTo(ctx.arg.initialHeap, WasmPageSize)) error("initial heap must be " + Twine(WasmPageSize) + "-byte aligned"); uint64_t maxInitialHeap = maxMemorySetting - memoryPtr; - if (config->initialHeap > maxInitialHeap) + if (ctx.arg.initialHeap > maxInitialHeap) error("initial heap too large, cannot be greater than " + Twine(maxInitialHeap)); - memoryPtr += config->initialHeap; + memoryPtr += ctx.arg.initialHeap; } - if (config->initialMemory != 0) { - if (config->initialMemory != alignTo(config->initialMemory, WasmPageSize)) + if (ctx.arg.initialMemory != 0) { + if (ctx.arg.initialMemory != alignTo(ctx.arg.initialMemory, WasmPageSize)) error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned"); - if (memoryPtr > config->initialMemory) + if (memoryPtr > ctx.arg.initialMemory) error("initial memory too small, " + Twine(memoryPtr) + " bytes needed"); - if (config->initialMemory > maxMemorySetting) + if (ctx.arg.initialMemory > maxMemorySetting) error("initial memory too large, cannot be greater than " + Twine(maxMemorySetting)); - memoryPtr = config->initialMemory; + memoryPtr = ctx.arg.initialMemory; } memoryPtr = alignTo(memoryPtr, WasmPageSize); @@ -479,23 +479,23 @@ void Writer::layoutMemory() { } uint64_t maxMemory = 0; - if (config->maxMemory != 0) { - if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize)) + if (ctx.arg.maxMemory != 0) { + if (ctx.arg.maxMemory != alignTo(ctx.arg.maxMemory, WasmPageSize)) error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned"); - if (memoryPtr > config->maxMemory) + if (memoryPtr > ctx.arg.maxMemory) error("maximum memory too small, " + Twine(memoryPtr) + " bytes needed"); - if (config->maxMemory > maxMemorySetting) + if (ctx.arg.maxMemory > maxMemorySetting) error("maximum memory too large, cannot be greater than " + Twine(maxMemorySetting)); - maxMemory = config->maxMemory; - } else if (config->noGrowableMemory) { + maxMemory = ctx.arg.maxMemory; + } else if (ctx.arg.noGrowableMemory) { maxMemory = memoryPtr; } // If no maxMemory config was supplied but we are building with // shared memory, we need to pick a sensible upper limit. - if (config->sharedMemory && maxMemory == 0) { + if (ctx.arg.sharedMemory && maxMemory == 0) { if (ctx.isPic) maxMemory = maxMemorySetting; else @@ -552,7 +552,7 @@ void Writer::addSections() { createCustomSections(); addSection(out.linkingSec); - if (config->emitRelocs || config->relocatable) { + if (ctx.arg.emitRelocs || ctx.arg.relocatable) { createRelocSections(); } @@ -583,18 +583,18 @@ void Writer::populateTargetFeatures() { allowed.insert("mutable-globals"); } - if (config->extraFeatures.has_value()) { - auto &extraFeatures = *config->extraFeatures; + if (ctx.arg.extraFeatures.has_value()) { + auto &extraFeatures = *ctx.arg.extraFeatures; allowed.insert(extraFeatures.begin(), extraFeatures.end()); } // Only infer used features if user did not specify features - bool inferFeatures = !config->features.has_value(); + bool inferFeatures = !ctx.arg.features.has_value(); if (!inferFeatures) { - auto &explicitFeatures = *config->features; + auto &explicitFeatures = *ctx.arg.features; allowed.insert(explicitFeatures.begin(), explicitFeatures.end()); - if (!config->checkFeatures) + if (!ctx.arg.checkFeatures) goto done; } @@ -626,10 +626,10 @@ void Writer::populateTargetFeatures() { for (const auto &key : used.keys()) allowed.insert(std::string(key)); - if (!config->checkFeatures) + if (!ctx.arg.checkFeatures) goto done; - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { if (disallowed.count("shared-mem")) error("--shared-memory is disallowed by " + disallowed["shared-mem"] + " because it was not compiled with 'atomics' or 'bulk-memory' " @@ -679,19 +679,19 @@ void Writer::populateTargetFeatures() { // instruction, then we can also avoid including the segments. // Finally, if we are emitting relocations, they may refer to locations within // the bss segments, so these segments need to exist in the binary. - if (config->emitRelocs || - (config->memoryImport.has_value() && !allowed.count("bulk-memory"))) + if (ctx.arg.emitRelocs || + (ctx.arg.memoryImport.has_value() && !allowed.count("bulk-memory"))) ctx.emitBssSegments = true; if (allowed.count("extended-const")) - config->extendedConst = true; + ctx.arg.extendedConst = true; for (auto &feature : allowed) log("Allowed feature: " + feature); } void Writer::checkImportExportTargetFeatures() { - if (config->relocatable || !config->checkFeatures) + if (ctx.arg.relocatable || !ctx.arg.checkFeatures) return; if (out.targetFeaturesSec->features.count("mutable-globals") == 0) { @@ -727,14 +727,14 @@ static bool shouldImport(Symbol *sym) { // When a symbol is weakly defined in a shared library we need to allow // it to be overridden by another module so need to both import // and export the symbol. - if (config->shared && sym->isWeak() && !sym->isUndefined() && + if (ctx.arg.shared && sym->isWeak() && !sym->isUndefined() && !sym->isHidden()) return true; if (sym->isShared()) return true; if (!sym->isUndefined()) return false; - if (sym->isWeak() && !config->relocatable && !ctx.isPic) + if (sym->isWeak() && !ctx.arg.relocatable && !ctx.isPic) return false; // In PIC mode we only need to import functions when they are called directly. @@ -745,10 +745,10 @@ static bool shouldImport(Symbol *sym) { return false; } - if (ctx.isPic || config->relocatable || config->importUndefined || - config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) + if (ctx.isPic || ctx.arg.relocatable || ctx.arg.importUndefined || + ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic) return true; - if (config->allowUndefinedSymbols.count(sym->getName()) != 0) + if (ctx.arg.allowUndefinedSymbols.count(sym->getName()) != 0) return true; return sym->isImported(); @@ -773,12 +773,12 @@ void Writer::calculateImports() { } void Writer::calculateExports() { - if (config->relocatable) + if (ctx.arg.relocatable) return; - if (!config->relocatable && config->memoryExport.has_value()) { + if (!ctx.arg.relocatable && ctx.arg.memoryExport.has_value()) { out.exportSec->exports.push_back( - WasmExport{*config->memoryExport, WASM_EXTERNAL_MEMORY, 0}); + WasmExport{*ctx.arg.memoryExport, WASM_EXTERNAL_MEMORY, 0}); } unsigned globalIndex = @@ -827,7 +827,7 @@ void Writer::calculateExports() { } void Writer::populateSymtab() { - if (!config->relocatable && !config->emitRelocs) + if (!ctx.arg.relocatable && !ctx.arg.emitRelocs) return; for (Symbol *sym : symtab->symbols()) @@ -931,13 +931,13 @@ static void finalizeIndirectFunctionTable() { out.importSec->addImport(WasmSym::indirectFunctionTable); } - uint32_t tableSize = config->tableBase + out.elemSec->numEntries(); + uint32_t tableSize = ctx.arg.tableBase + out.elemSec->numEntries(); WasmLimits limits = {0, tableSize, 0}; - if (WasmSym::indirectFunctionTable->isDefined() && !config->growableTable) { + if (WasmSym::indirectFunctionTable->isDefined() && !ctx.arg.growableTable) { limits.Flags |= WASM_LIMITS_FLAG_HAS_MAX; limits.Maximum = limits.Minimum; } - if (config->is64.value_or(false)) + if (ctx.arg.is64.value_or(false)) limits.Flags |= WASM_LIMITS_FLAG_IS_64; WasmSym::indirectFunctionTable->setLimits(limits); } @@ -1001,7 +1001,7 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { // symbols are be relative to single __tls_base. if (seg.isTLS()) return ".tdata"; - if (!config->mergeDataSegments) + if (!ctx.arg.mergeDataSegments) return seg.name; if (seg.name.starts_with(".text.")) return ".text"; @@ -1017,9 +1017,9 @@ static StringRef getOutputDataSegmentName(const InputChunk &seg) { OutputSegment *Writer::createOutputSegment(StringRef name) { LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); OutputSegment *s = make(name); - if (config->sharedMemory) + if (ctx.arg.sharedMemory) s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; - if (!config->relocatable && name.starts_with(".bss")) + if (!ctx.arg.relocatable && name.starts_with(".bss")) s->isBss = true; segments.push_back(s); return s; @@ -1035,7 +1035,7 @@ void Writer::createOutputSegments() { // When running in relocatable mode we can't merge segments that are part // of comdat groups since the ultimate linker needs to be able exclude or // include them individually. - if (config->relocatable && !segment->getComdatName().empty()) { + if (ctx.arg.relocatable && !segment->getComdatName().empty()) { s = createOutputSegment(name); } else { if (segmentMap.count(name) == 0) @@ -1075,8 +1075,8 @@ void Writer::combineOutputSegments() { // combines all data segments into a single .data segment. // This restriction does not apply when the extended const extension is // available: https://github.com/WebAssembly/extended-const - assert(!config->extendedConst); - assert(ctx.isPic && !config->sharedMemory); + assert(!ctx.arg.extendedConst); + assert(ctx.isPic && !ctx.arg.sharedMemory); if (segments.size() <= 1) return; OutputSegment *combined = make(".data"); @@ -1117,7 +1117,7 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) { bool Writer::needsPassiveInitialization(const OutputSegment *segment) { // If bulk memory features is supported then we can perform bss initialization // (via memory.fill) during `__wasm_init_memory`. - if (config->memoryImport.has_value() && !segment->requiredInBinary()) + if (ctx.arg.memoryImport.has_value() && !segment->requiredInBinary()) return true; return segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE; } @@ -1129,7 +1129,7 @@ bool Writer::hasPassiveInitializedSegments() { } void Writer::createSyntheticInitFunctions() { - if (config->relocatable) + if (ctx.arg.relocatable) return; static WasmSignature nullSignature = {{}, {}}; @@ -1146,14 +1146,14 @@ void Writer::createSyntheticInitFunctions() { "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, make(nullSignature, "__wasm_init_memory")); WasmSym::initMemory->markLive(); - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { // This global is assigned during __wasm_init_memory in the shared memory // case. WasmSym::tlsBase->markLive(); } } - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { if (out.globalSec->needsTLSRelocations()) { WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1203,11 +1203,11 @@ void Writer::createInitMemoryFunction() { assert(WasmSym::initMemory); assert(hasPassiveInitializedSegments()); uint64_t flagAddress; - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { assert(WasmSym::initMemoryFlag); flagAddress = WasmSym::initMemoryFlag->getVA(); } - bool is64 = config->is64.value_or(false); + bool is64 = ctx.arg.is64.value_or(false); std::string bodyContent; { raw_string_ostream os(bodyContent); @@ -1271,7 +1271,7 @@ void Writer::createInitMemoryFunction() { } }; - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { // With PIC code we cache the flag address in local 0 if (ctx.isPic) { writeUleb128(os, 1, "num local decls"); @@ -1334,7 +1334,7 @@ void Writer::createInitMemoryFunction() { // When we initialize the TLS segment we also set the `__tls_base` // global. This allows the runtime to use this static copy of the // TLS data for the first/main thread. - if (config->sharedMemory && s->isTLS()) { + if (ctx.arg.sharedMemory && s->isTLS()) { if (ctx.isPic) { // Cache the result of the addionion in local 0 writeU8(os, WASM_OPCODE_LOCAL_TEE, "local.tee"); @@ -1368,7 +1368,7 @@ void Writer::createInitMemoryFunction() { } } - if (config->sharedMemory) { + if (ctx.arg.sharedMemory) { // Set flag to 2 to mark end of initialization writeGetFlagAddress(); writeI32Const(os, 2, "flag value"); @@ -1407,7 +1407,7 @@ void Writer::createInitMemoryFunction() { if (needsPassiveInitialization(s) && !s->isBss) { // The TLS region should not be dropped since its is needed // during the initialization of each thread (__wasm_init_tls). - if (config->sharedMemory && s->isTLS()) + if (ctx.arg.sharedMemory && s->isTLS()) continue; // data.drop instruction writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); @@ -1460,7 +1460,7 @@ void Writer::createApplyDataRelocationsFunction() { writeUleb128(os, 0, "num locals"); bool generated = false; for (const OutputSegment *seg : segments) - if (!config->sharedMemory || !seg->isTLS()) + if (!ctx.arg.sharedMemory || !seg->isTLS()) for (const InputChunk *inSeg : seg->inputSegments) generated |= inSeg->generateRelocationCode(os); @@ -1656,7 +1656,7 @@ void Writer::createInitTLSFunction() { // This is then used either when creating the output linking section or to // synthesize the "__wasm_call_ctors" function. void Writer::calculateInitFunctions() { - if (!config->relocatable && !WasmSym::callCtors->isLive()) + if (!ctx.arg.relocatable && !WasmSym::callCtors->isLive()) return; for (ObjFile *file : ctx.objectFiles) { @@ -1708,7 +1708,7 @@ void Writer::run() { // For PIC code the table base is assigned dynamically by the loader. // For non-PIC, we start at 1 so that accessing table index 0 always traps. if (!ctx.isPic && WasmSym::definedTableBase) - WasmSym::definedTableBase->setVA(config->tableBase); + WasmSym::definedTableBase->setVA(ctx.arg.tableBase); log("-- createOutputSegments"); createOutputSegments(); @@ -1717,7 +1717,7 @@ void Writer::run() { log("-- layoutMemory"); layoutMemory(); - if (!config->relocatable) { + if (!ctx.arg.relocatable) { // Create linker synthesized __start_SECNAME/__stop_SECNAME symbols // This has to be done after memory layout is performed. for (const OutputSegment *seg : segments) { @@ -1725,7 +1725,7 @@ void Writer::run() { } } - for (auto &pair : config->exportedSymbols) { + for (auto &pair : ctx.arg.exportedSymbols) { Symbol *sym = symtab->find(pair.first()); if (sym && sym->isDefined()) sym->forceExport = true; @@ -1733,12 +1733,12 @@ void Writer::run() { // Delay reporting errors about explicit exports until after // addStartStopSymbols which can create optional symbols. - for (auto &name : config->requiredExports) { + for (auto &name : ctx.arg.requiredExports) { Symbol *sym = symtab->find(name); if (!sym || !sym->isDefined()) { - if (config->unresolvedSymbols == UnresolvedPolicy::ReportError) + if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ReportError) error(Twine("symbol exported via --export not found: ") + name); - if (config->unresolvedSymbols == UnresolvedPolicy::Warn) + if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn) warn(Twine("symbol exported via --export not found: ") + name); } } @@ -1750,7 +1750,7 @@ void Writer::run() { // `__memory_base` import. Unless we support the extended const expression we // can't do addition inside the constant expression, so we much combine the // segments into a single one that can live at `__memory_base`. - if (ctx.isPic && !config->extendedConst && !config->sharedMemory) { + if (ctx.isPic && !ctx.arg.extendedConst && !ctx.arg.sharedMemory) { // In shared memory mode all data segments are passive and initialized // via __wasm_init_memory. log("-- combineOutputSegments"); @@ -1774,7 +1774,7 @@ void Writer::run() { log("-- calculateInitFunctions"); calculateInitFunctions(); - if (!config->relocatable) { + if (!ctx.arg.relocatable) { // Create linker synthesized functions if (WasmSym::applyGlobalRelocs) createApplyGlobalRelocationsFunction(); @@ -1793,7 +1793,7 @@ void Writer::run() { // If the input contains a call to `__wasm_call_ctors`, either in one of // the input objects or an explicit export from the command-line, we // assume ctors and dtors are taken care of already. - if (!config->relocatable && !ctx.isPic && + if (!ctx.arg.relocatable && !ctx.isPic && !WasmSym::callCtors->isUsedInRegularObj && !WasmSym::callCtors->isExported()) { log("-- createCommandExportWrappers"); @@ -1861,14 +1861,14 @@ void Writer::run() { // Open a result file. void Writer::openFile() { - log("writing: " + config->outputFile); + log("writing: " + ctx.arg.outputFile); Expected> bufferOrErr = - FileOutputBuffer::create(config->outputFile, fileSize, + FileOutputBuffer::create(ctx.arg.outputFile, fileSize, FileOutputBuffer::F_executable); if (!bufferOrErr) - error("failed to open " + config->outputFile + ": " + + error("failed to open " + ctx.arg.outputFile + ": " + toString(bufferOrErr.takeError())); else buffer = std::move(*bufferOrErr);