[clang] 89d5635 - [lld][WebAssembly] Add --keep-section flag

Sam Clegg via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 2 14:24:21 PDT 2023


Author: Sam Clegg
Date: 2023-11-02T14:23:45-07:00
New Revision: 89d5635f0a834e53ac5446c6d6ea38d9166b2a55

URL: https://github.com/llvm/llvm-project/commit/89d5635f0a834e53ac5446c6d6ea38d9166b2a55
DIFF: https://github.com/llvm/llvm-project/commit/89d5635f0a834e53ac5446c6d6ea38d9166b2a55.diff

LOG: [lld][WebAssembly] Add --keep-section flag

This flag causes wasm-ld preserve a section even in the face of
`--strip-all`.  This is useful, for example, to preserve the
target_features section in the ase of clang (which can run wasm-opt
after linking), and emcc (which performs a bunch of post-link work).

Fixes: https://github.com/llvm/llvm-project/issues/60613
Fixes: https://github.com/llvm/llvm-project/issues/55781

Differential Revision: https://reviews.llvm.org/D149917

Added: 
    lld/test/wasm/strip-all.s

Modified: 
    clang/lib/Driver/ToolChains/WebAssembly.cpp
    lld/wasm/Config.h
    lld/wasm/Driver.cpp
    lld/wasm/Options.td
    lld/wasm/SyntheticSections.h

Removed: 
    lld/test/wasm/strip-all.test


################################################################################
diff  --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index fe0b30b7250b824..f04018179a5dab7 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -141,14 +141,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
   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-section=target_features");
+  }
+
   C.addCommand(std::make_unique<Command>(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 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
 
       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<Command>(
-            JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs,
+            JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs,
             Inputs, Output));
       }
     }

diff  --git a/lld/test/wasm/strip-all.s b/lld/test/wasm/strip-all.s
new file mode 100644
index 000000000000000..b0819a29f8028a4
--- /dev/null
+++ b/lld/test/wasm/strip-all.s
@@ -0,0 +1,36 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.start.o
+# RUN: wasm-ld --strip-all -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+#
+## Test alias -s
+# RUN: wasm-ld -s -o %t2.wasm %t.start.o
+# RUN: obj2yaml %t2.wasm | FileCheck %s
+#
+## Check that there is no name section
+# CHECK-NOT:   Name:    name
+# CHECK-NOT:   Name:    target_features
+#
+## Test --keep-section=name preserver the name section
+# RUN: wasm-ld --strip-all --keep-section=name -o %t3.wasm %t.start.o
+# RUN: obj2yaml %t3.wasm | FileCheck --check-prefix=CHECK-NAME %s
+#
+# CHECK-NAME:   Name:    name
+# CHECK-NAME-NOT:   Name:    target_features
+#
+## Test --keep-section can be specified more than once
+# RUN: wasm-ld --strip-all --keep-section=name --keep-section=target_features -o %t4.wasm %t.start.o
+# RUN: obj2yaml %t4.wasm | FileCheck --check-prefix=CHECK-FEATURES %s
+#
+# CHECK-FEATURES:   Name:    name
+# CHECK-FEATURES:   Name:    target_features
+
+  .globl  _start
+_start:
+  .functype _start () -> ()
+  end_function
+
+.section .custom_section.target_features,"",@
+.int8 1
+.int8 43
+.int8 15
+.ascii "mutable-globals"

diff  --git a/lld/test/wasm/strip-all.test b/lld/test/wasm/strip-all.test
deleted file mode 100644
index ae3314f30676c50..000000000000000
--- a/lld/test/wasm/strip-all.test
+++ /dev/null
@@ -1,10 +0,0 @@
-RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %t.start.o
-RUN: wasm-ld --strip-all -o %t.wasm %t.start.o
-RUN: obj2yaml %t.wasm | FileCheck %s
-
-# Test alias -s
-RUN: wasm-ld -s -o %t.wasm %t.start.o
-RUN: obj2yaml %t.wasm | FileCheck %s
-
-# Check that there is no name section
-CHECK-NOT:   Name:    name

diff  --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 876c7e80ba80d93..d76d43852acffed 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -49,6 +49,7 @@ struct Configuration {
   bool extendedConst;
   bool growableTable;
   bool gcSections;
+  llvm::StringSet<> keepSections;
   std::optional<std::pair<llvm::StringRef, llvm::StringRef>> memoryImport;
   std::optional<llvm::StringRef> memoryExport;
   bool sharedMemory;

diff  --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index c2f5f0185781f36..f8b0fc357bd90c2 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -478,6 +478,8 @@ static void readConfigs(opt::InputArgList &args) {
   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
index bb764396bf4df14..2df6196d5e8ce64 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -193,6 +193,9 @@ def growable_table: FF<"growable-table">,
 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. Can be specified multiple times to keep multiple sections">;
+
 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
index 915b35dd6fed804..11479962956aaa1 100644
--- a/lld/wasm/SyntheticSections.h
+++ b/lld/wasm/SyntheticSections.h
@@ -373,7 +373,11 @@ class NameSection : public SyntheticSection {
   NameSection(ArrayRef<OutputSegment *> 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 @@ class ProducersSection : public SyntheticSection {
   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 @@ class TargetFeaturesSection : public SyntheticSection {
   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;
 


        


More information about the cfe-commits mailing list