[lld] 0367305 - [lld][WebAssembly] Add allow-multiple-definition flag (#97699)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 4 08:50:15 PDT 2024
Author: mzukovec
Date: 2024-09-04T08:50:10-07:00
New Revision: 0367305af849da7ee9237fd83c04ed3a01e8d223
URL: https://github.com/llvm/llvm-project/commit/0367305af849da7ee9237fd83c04ed3a01e8d223
DIFF: https://github.com/llvm/llvm-project/commit/0367305af849da7ee9237fd83c04ed3a01e8d223.diff
LOG: [lld][WebAssembly] Add allow-multiple-definition flag (#97699)
Add `allow-multiple-definition` flag to `wasm-ld`. This follows the ELF
linker logic. In case of duplication, the first symbol met is used.
This PR resolves the #97543
Added:
lld/test/wasm/Inputs/allow-multiple-definition.s
lld/test/wasm/allow-multiple-definition.s
Modified:
lld/wasm/Config.h
lld/wasm/Driver.cpp
lld/wasm/Options.td
lld/wasm/SymbolTable.cpp
Removed:
################################################################################
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 00000000000000..7a5577cb12791e
--- /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 00000000000000..93fccd3c46f907
--- /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
diff erent 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 915c53c4371729..05a547ff9278a1 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 5368fe79b7eb89..cb8fe2534f5fe7 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 =
@@ -1173,7 +1195,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 3a70ee65f7c4fb..c5febd145a54f3 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 a5d37a5eba6d5e..d2216ff5a39a0e 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;
}
More information about the llvm-commits
mailing list