[lld] wasm-ld: Add allow-multiple-definition flag (PR #97699)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 23 22:14:09 PDT 2024


Martin =?utf-8?q?Žukovec?= <martin.zukovec at xlab.si>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/97699 at github.com>


https://github.com/mzukovec updated https://github.com/llvm/llvm-project/pull/97699

>From 4765387b0682063a85fb7dd3379fd24996889925 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C5=BDukovec?= <martin.zukovec at xlab.si>
Date: Mon, 8 Jul 2024 20:44:34 +0200
Subject: [PATCH 1/2] Add allow-multiple-definition and noinhibit-exec flags to
 wasm-ld to enable duplicated definitions.

---
 .../wasm/Inputs/allow-multiple-definition.s   |  6 +++
 lld/test/wasm/allow-multiple-definition.s     | 38 +++++++++++++++++++
 lld/wasm/Config.h                             |  5 +++
 lld/wasm/Driver.cpp                           | 24 +++++++++++-
 lld/wasm/Options.td                           |  7 ++++
 lld/wasm/SymbolTable.cpp                      |  9 +++--
 6 files changed, 85 insertions(+), 4 deletions(-)
 create mode 100644 lld/test/wasm/Inputs/allow-multiple-definition.s
 create mode 100644 lld/test/wasm/allow-multiple-definition.s

diff --git a/lld/test/wasm/Inputs/allow-multiple-definition.s b/lld/test/wasm/Inputs/allow-multiple-definition.s
new file mode 100644
index 0000000000000..7a5577cb12791
--- /dev/null
+++ b/lld/test/wasm/Inputs/allow-multiple-definition.s
@@ -0,0 +1,6 @@
+  .hidden foo
+  .globl  foo
+foo:
+  .functype foo () -> (i32)
+  i32.const 1
+  end_function
diff --git a/lld/test/wasm/allow-multiple-definition.s b/lld/test/wasm/allow-multiple-definition.s
new file mode 100644
index 0000000000000..93fccd3c46f90
--- /dev/null
+++ b/lld/test/wasm/allow-multiple-definition.s
@@ -0,0 +1,38 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/allow-multiple-definition.s -o %t2
+# RUN: not wasm-ld %t1 %t2 -o /dev/null
+# RUN: not wasm-ld --allow-multiple-definition --no-allow-multiple-definition %t1 %t2 -o /dev/null
+# RUN: wasm-ld --allow-multiple-definition --fatal-warnings %t1 %t2 -o %t3
+# RUN: wasm-ld --allow-multiple-definition --fatal-warnings %t2 %t1 -o %t4
+# RUN: llvm-objdump --no-print-imm-hex -d %t3 | FileCheck %s
+# RUN: llvm-objdump --no-print-imm-hex -d %t4 | FileCheck --check-prefix=REVERT %s
+
+# RUN: wasm-ld --noinhibit-exec %t2 %t1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN
+# WARN: warning: duplicate symbol: foo
+
+# RUN: wasm-ld -z muldefs --fatal-warnings  %t1 %t2 -o %t3
+# RUN: wasm-ld -z muldefs --fatal-warnings  %t2 %t1 -o %t4
+# RUN: llvm-objdump --no-print-imm-hex -d %t3 | FileCheck %s
+# RUN: llvm-objdump --no-print-imm-hex -d %t4 | FileCheck --check-prefix=REVERT %s
+
+# CHECK:  i32.const 0
+# REVERT:  i32.const 1
+
+# inputs contain different constants for function foo return.
+# Tests below checks that order of files in command line
+# affects on what symbol will be used.
+# If flag allow-multiple-definition is enabled the first
+# meet symbol should be used.
+
+  .hidden foo
+  .globl  foo
+foo:
+  .functype foo () -> (i32)
+  i32.const 0
+  end_function
+
+  .globl _start
+_start:
+  .functype  _start () -> (i32)
+  call foo
+  end_function
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 915c53c437172..05a547ff9278a 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -12,6 +12,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/Support/CachePruning.h"
 #include <optional>
@@ -43,6 +44,7 @@ enum class BuildIdKind { None, Fast, Sha1, Hexstring, Uuid };
 // and such fields have the same name as the corresponding options.
 // Most fields are initialized by the driver.
 struct Configuration {
+  bool allowMultipleDefinition;
   bool bsymbolic;
   bool checkFeatures;
   bool compressRelocations;
@@ -64,6 +66,7 @@ struct Configuration {
   bool importUndefined;
   std::optional<bool> is64;
   bool mergeDataSegments;
+  bool noinhibitExec;
   bool pie;
   bool printGcSections;
   bool relocatable;
@@ -148,6 +151,8 @@ struct Ctx {
 
 extern Ctx ctx;
 
+void errorOrWarn(const llvm::Twine &msg);
+
 } // namespace lld::wasm
 
 #endif
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 8c83d17db02f5..e70fc7d9af37f 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -47,6 +47,13 @@ namespace lld::wasm {
 Configuration *config;
 Ctx ctx;
 
+void errorOrWarn(const llvm::Twine &msg) {
+  if (config->noinhibitExec)
+    warn(msg);
+  else
+    error(msg);
+}
+
 void Ctx::reset() {
   objectFiles.clear();
   stubFiles.clear();
@@ -99,6 +106,16 @@ class LinkerDriver {
 
   std::vector<InputFile *> files;
 };
+
+static bool hasZOption(opt::InputArgList &args, StringRef key) {
+  bool ret = false;
+  for (const auto *arg : args.filtered(OPT_z))
+    if (key == arg->getValue()) {
+      ret = true;
+      arg->claim();
+    }
+  return ret;
+}
 } // anonymous namespace
 
 bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
@@ -467,6 +484,10 @@ getBuildId(opt::InputArgList &args) {
 
 // Initializes Config members by the command line options.
 static void readConfigs(opt::InputArgList &args) {
+  config->allowMultipleDefinition =
+      hasZOption(args, "muldefs") ||
+      args.hasFlag(OPT_allow_multiple_definition,
+                   OPT_no_allow_multiple_definition, false);
   config->bsymbolic = args.hasArg(OPT_Bsymbolic);
   config->checkFeatures =
       args.hasFlag(OPT_check_features, OPT_no_check_features, true);
@@ -479,6 +500,7 @@ static void readConfigs(opt::InputArgList &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);
 
   if (args.hasArg(OPT_import_memory_with_name)) {
     config->memoryImport =
@@ -1162,7 +1184,7 @@ static void splitSections() {
 
 static bool isKnownZFlag(StringRef s) {
   // For now, we only support a very limited set of -z flags
-  return s.starts_with("stack-size=");
+  return s.starts_with("stack-size=") || s.starts_with("muldefs");
 }
 
 // Report a warning for an unknown -z option.
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
index 3a70ee65f7c4f..c5febd145a54f 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -42,6 +42,10 @@ def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
 
 def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries (default)">;
 
+defm allow_multiple_definition: B<"allow-multiple-definition",
+    "Allow multiple definitions",
+    "Do not allow multiple definitions (default)">;
+
 def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">;
 
 def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
@@ -105,6 +109,9 @@ defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option proces
 
 defm Map: Eq<"Map", "Print a link map to the specified file">;
 
+def noinhibit_exec: F<"noinhibit-exec">,
+  HelpText<"Retain the executable output file whenever it is still usable">;
+
 def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
   HelpText<"Path to file to write output">;
 
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index a5d37a5eba6d5..515c87df700db 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -319,9 +319,12 @@ static bool shouldReplace(const Symbol *existing, InputFile *newFile,
   }
 
   // Neither symbol is week. They conflict.
-  error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
-        toString(existing->getFile()) + "\n>>> defined in " +
-        toString(newFile));
+  if (config->allowMultipleDefinition) {
+    return false;
+  }
+  errorOrWarn("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
+              toString(existing->getFile()) + "\n>>> defined in " +
+              toString(newFile));
   return true;
 }
 

>From 2b6654b265a25e3bc3dbf77b435ce8ca130e7788 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C5=BDukovec?= <martin.zukovec at xlab.si>
Date: Wed, 24 Jul 2024 07:13:57 +0200
Subject: [PATCH 2/2] Remove redundant braces in SymbolTable if

---
 lld/wasm/SymbolTable.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 515c87df700db..d2216ff5a39a0 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -319,9 +319,9 @@ static bool shouldReplace(const Symbol *existing, InputFile *newFile,
   }
 
   // Neither symbol is week. They conflict.
-  if (config->allowMultipleDefinition) {
+  if (config->allowMultipleDefinition)
     return false;
-  }
+
   errorOrWarn("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
               toString(existing->getFile()) + "\n>>> defined in " +
               toString(newFile));



More information about the llvm-commits mailing list