diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -141,14 +141,25 @@ CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + // When optimizing, if wasm-opt is available, run it. + std::string WasmOptPath; + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); + if (WasmOptPath == "wasm-opt") { + WasmOptPath = {}; + } + } + + if (!WasmOptPath.empty()) { + CmdArgs.push_back("--keep-secton=target_features"); + } + C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), Linker, CmdArgs, Inputs, Output)); - // When optimizing, if wasm-opt is available, run it. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - auto WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); - if (WasmOptPath != "wasm-opt") { + if (!WasmOptPath.empty()) { StringRef OOpt = "s"; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) @@ -160,13 +171,13 @@ if (OOpt != "0") { const char *WasmOpt = Args.MakeArgString(WasmOptPath); - ArgStringList CmdArgs; - CmdArgs.push_back(Output.getFilename()); - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + ArgStringList OptArgs; + OptArgs.push_back(Output.getFilename()); + OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + OptArgs.push_back("-o"); + OptArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique( - JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs, + JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs, Inputs, Output)); } } diff --git a/lld/test/wasm/strip-all.test b/lld/test/wasm/strip-all.test --- a/lld/test/wasm/strip-all.test +++ b/lld/test/wasm/strip-all.test @@ -8,3 +8,10 @@ # Check that there is no name section CHECK-NOT: Name: name + +# Test --keep-section +RUN: wasm-ld --strip-all --keep-section=name -o %t.wasm %t.start.o +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=CHECK-FOUND %s + +# Check that name section was preserved +CHECK-FOUND: Name: name diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -49,6 +49,7 @@ bool extendedConst; bool growableTable; bool gcSections; + llvm::StringSet<> keepSections; std::optional> memoryImport; std::optional memoryExport; bool sharedMemory; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -478,6 +478,8 @@ config->relocatable = args.hasArg(OPT_relocatable); config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable); + for (auto *arg : args.filtered(OPT_keep_section)) + config->keepSections.insert(arg->getValue()); config->mergeDataSegments = args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments, !config->relocatable); diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -193,6 +193,9 @@ def global_base: JJ<"global-base=">, HelpText<"Memory offset at which to place global data (Defaults to 1024)">; +defm keep_section: Eq<"keep-section", + "Preserve a section even when --strip-all is given. This is useful for compiler drivers such as clang or emcc that, for example, depend on the features section for post-link processing.">; + def import_memory: FF<"import-memory">, HelpText<"Import the module's memory from the default module of \"env\" with the name \"memory\".">; def import_memory_with_name: JJ<"import-memory=">, diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -373,7 +373,11 @@ NameSection(ArrayRef segments) : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"), segments(segments) {} - bool isNeeded() const override { return !config->stripAll && numNames() > 0; } + bool isNeeded() const override { + if (config->stripAll && !config->keepSections.count(name)) + return false; + return numNames() > 0; + } void writeBody() override; unsigned numNames() const { // We always write at least one name which is the name of the @@ -393,7 +397,9 @@ ProducersSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {} bool isNeeded() const override { - return !config->stripAll && fieldCount() > 0; + if (config->stripAll && !config->keepSections.count(name)) + return false; + return fieldCount() > 0; } void writeBody() override; void addInfo(const llvm::wasm::WasmProducerInfo &info); @@ -412,7 +418,9 @@ TargetFeaturesSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {} bool isNeeded() const override { - return !config->stripAll && features.size() > 0; + if (config->stripAll && !config->keepSections.count(name)) + return false; + return features.size() > 0; } void writeBody() override;