WebAssembly: do not link with --allow-undefined unconditionally

In #1622, when targeting WebAsembly, the --allow-undefined flag
became unconditionally added to the linker.

This is not always desirable.

First, this is error prone. Code with references to unkown symbols
will link just fine, but then fail at run-time.

This behavior is inconsistent with all other targets.

For freestanding wasm applications, and applications that only use
WASI, undefined references are better reported at compile-time.

This behavior is also inconsistent with clang itself. Autoconf and
cmake scripts checking for function presence think that all tested
functions exist, but then resulting application cannot run.

For example, this is one of the reasons compilation of Ruby 3.2.0
to WASI fails with zig cc, while it works out of the box with clang.
But all applications checking for symbol existence before compilation
are affected.

This reverts the behavior to the one Zig had before #1622, and
introduces an `import_symbols` flag to ignore undefined symbols,
assuming that the webassembly runtime will define them.
This commit is contained in:
Frank Denis 2022-12-25 22:04:01 +01:00
parent 0c30e006c9
commit 7802c26449
4 changed files with 13 additions and 1 deletions

View File

@ -954,6 +954,7 @@ pub const InitOptions = struct {
linker_allow_shlib_undefined: ?bool = null,
linker_bind_global_refs_locally: ?bool = null,
linker_import_memory: ?bool = null,
linker_import_symbols: bool = false,
linker_import_table: bool = false,
linker_export_table: bool = false,
linker_initial_memory: ?u64 = null,
@ -1811,6 +1812,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
.compress_debug_sections = options.linker_compress_debug_sections orelse .none,
.import_memory = options.linker_import_memory orelse false,
.import_symbols = options.linker_import_symbols,
.import_table = options.linker_import_table,
.export_table = options.linker_export_table,
.initial_memory = options.linker_initial_memory,

View File

@ -128,6 +128,7 @@ pub const Options = struct {
compress_debug_sections: CompressDebugSections,
bind_global_refs_locally: bool,
import_memory: bool,
import_symbols: bool,
import_table: bool,
export_table: bool,
initial_memory: ?u64,

View File

@ -3461,8 +3461,10 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
} else if (wasm.base.options.entry == null) {
try argv.append("--no-entry"); // So lld doesn't look for _start.
}
if (wasm.base.options.import_symbols) {
try argv.appendSlice(&[_][]const u8{"--allow-undefined"});
}
try argv.appendSlice(&[_][]const u8{
"--allow-undefined",
"-o",
full_out_path,
});

View File

@ -517,6 +517,7 @@ const usage_build_generic =
\\ -dead_strip (Darwin) remove functions and data that are unreachable by the entry point or exported symbols
\\ -dead_strip_dylibs (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
\\ --import-memory (WebAssembly) import memory from the environment
\\ --import-symbols (WebAssembly) import missing symbols from the host environment
\\ --import-table (WebAssembly) import function table from the host environment
\\ --export-table (WebAssembly) export function table to the host environment
\\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
@ -718,6 +719,7 @@ fn buildOutputType(
var linker_allow_shlib_undefined: ?bool = null;
var linker_bind_global_refs_locally: ?bool = null;
var linker_import_memory: ?bool = null;
var linker_import_symbols: bool = false;
var linker_import_table: bool = false;
var linker_export_table: bool = false;
var linker_initial_memory: ?u64 = null;
@ -1316,6 +1318,8 @@ fn buildOutputType(
}
} else if (mem.eql(u8, arg, "--import-memory")) {
linker_import_memory = true;
} else if (mem.eql(u8, arg, "--import-symbols")) {
linker_import_symbols = true;
} else if (mem.eql(u8, arg, "--import-table")) {
linker_import_table = true;
} else if (mem.eql(u8, arg, "--export-table")) {
@ -1837,6 +1841,8 @@ fn buildOutputType(
linker_bind_global_refs_locally = true;
} else if (mem.eql(u8, arg, "--import-memory")) {
linker_import_memory = true;
} else if (mem.eql(u8, arg, "--import-symbols")) {
linker_import_symbols = true;
} else if (mem.eql(u8, arg, "--import-table")) {
linker_import_table = true;
} else if (mem.eql(u8, arg, "--export-table")) {
@ -2977,6 +2983,7 @@ fn buildOutputType(
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
.linker_import_memory = linker_import_memory,
.linker_import_symbols = linker_import_symbols,
.linker_import_table = linker_import_table,
.linker_export_table = linker_export_table,
.linker_initial_memory = linker_initial_memory,