From 7802c26449657b205dcaa47bb6575bb26171c024 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 25 Dec 2022 22:04:01 +0100 Subject: [PATCH] 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. --- src/Compilation.zig | 2 ++ src/link.zig | 1 + src/link/Wasm.zig | 4 +++- src/main.zig | 7 +++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index b385fa5f72baf7f94258acb297d25c18d1715c05..ab91e3cbb3d662aed38afd2e55bd915e5bc99d69 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -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, diff --git a/src/link.zig b/src/link.zig index 450763ac18af6d2930be0703858d61f218d18002..1dadacc2fe23e8209e7c8d5df04f4dfff6492c4f 100644 --- a/src/link.zig +++ b/src/link.zig @@ -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, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 346c92ebbef17dd8b541adb18321651524e57e4d..1f929da150d55dd3f57c87ef8aa110c2db369d96 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -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, }); diff --git a/src/main.zig b/src/main.zig index ec0eb74e9338f30f0fc9dc8a7b79afe1739de422..d9cc147604dabfb9897ad0a7114c7c86eb2f8e6d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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, -- 2.54.0