Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lld/test/wasm/Inputs/allow-multiple-definition.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.hidden foo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI In ELF, we now migrate used-once extra files from Inputs/ to split-file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that be included in this PR? It seems to me that it's better to leave it same as ELF test for easier tracking.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think matching ELF for now seem fine. We can try to follow the migration there as it happens.

.globl foo
foo:
.functype foo () -> (i32)
i32.const 1
end_function
38 changes: 38 additions & 0 deletions lld/test/wasm/allow-multiple-definition.s
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions lld/wasm/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand All @@ -64,6 +66,7 @@ struct Configuration {
bool importUndefined;
std::optional<bool> is64;
bool mergeDataSegments;
bool noinhibitExec;
bool pie;
bool printGcSections;
bool relocatable;
Expand Down Expand Up @@ -148,6 +151,8 @@ struct Ctx {

extern Ctx ctx;

void errorOrWarn(const llvm::Twine &msg);

} // namespace lld::wasm

#endif
24 changes: 23 additions & 1 deletion lld/wasm/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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 =
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions lld/wasm/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down Expand Up @@ -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">;

Expand Down
9 changes: 6 additions & 3 deletions lld/wasm/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down