-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Webassembly linker does not import symbols #1622
Comments
Thanks for trying this out. I wonder, how is the linker expecting to find symbols? Normally you would pass in .o files or .a files which have the symbols, or for dynamically linked libraries it may make sense to allow undefined symbols. For webassembly, it seems that you should be able to pass in other webassembly modules to the linker to resolve the symbols. Does it let you do this? If so then I think the export "foo" makes sense. That says that the symbol is expected to be found dynamically in a module named foo, and that would add it to the allow-undef list. |
In a sense, all wasm modules are dynamically linked. But all the external symbols need to be injected from javascript (or from whatever environment embeds it: const fs = require('fs')
const m = new WebAssembly.Module(fs.readFileSync('xyz'))
const env = {
inc(x) { return x+1 }
}
const i = new WebAssembly.Instance(m, {env})
console.log(i.exports.add(1,2)) // returns 4 It looks like you can hook up multiple wasm binaries and link their symbols together if you compile libraries with With wasm2.zig: export fn inc(a: i32) i32 {
return a+1;
} You can build if you pass
(module
...
(func $add (type 1) (param i32 i32) (result i32)
get_local 0
call $inc
get_local 1
i32.add)
(func $inc (type 2) (param i32) (result i32)
get_local 0
i32.const 1
i32.add)
...
(export "add" (func $add))
(export "inc" (func $inc))) |
... Ideally you'd want to be able to make a library which imports a bunch of functions from javascript (eg cargo's web-sys crate ) and then you could link to that & call functions from zig. You still need the undefined symbol list when linking the final result though - the linker wants to know which functions your javascript runtime is expected to provide. |
Here's what I think should happen:
Sound good? |
Points 2 and 3 I agree with. That sounds good 👍 I'm not sure about deprecating @bnoordhuis thoughts? sephsmac:zig josephg$ wasm2wat wasm.o
(module
(type (;0;) (func (param i32 i32) (result i32)))
(type (;1;) (func (param i32) (result i32)))
(import "env" "__linear_memory" (memory (;0;) 0))
(import "env" "__indirect_function_table" (table (;0;) 0 anyfunc))
(import "env" "inc" (func (;0;) (type 1)))
(func (;1;) (type 0) (param i32 i32) (result i32)
get_local 0
call 0
get_local 1
i32.add))
sephsmac:zig josephg$ wasm-ld wasm.o -o wasmolib.wasm --relocatable
sephsmac:zig josephg$ wasm2wat wasmolib.wasm
(module
(type (;0;) (func (param i32) (result i32)))
(type (;1;) (func (param i32 i32) (result i32)))
(import "env" "inc" (func $inc (type 0)))
(func $add (type 1) (param i32 i32) (result i32)
get_local 0
call $inc
get_local 1
i32.add)
(table (;0;) 1 1 anyfunc)
(memory (;0;) 0)) |
Andrew's proposal sounds good. I don't have a strong opinion on One thing about (Not a leading question. I genuinely don't know.) |
Yes. When you build a static library it has all the symbols available for use, and then the linker does a final garbage collection when you link against the static library, omitting unused symbols. |
@josephg regarding |
In ziglang#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 ziglang#1622, and introduces an `import_symbols` flag to ignore undefined symbols, assuming that the webassembly runtime will define them.
In ziglang#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 ziglang#1622, and introduces an `import_symbols` flag to ignore undefined symbols, assuming that the webassembly runtime will define them.
Related to #1570...
Consider this zig code:
... Which expects the symbol
inc
to be imported from javascript (or whatever environment is embedding the wasm build).It won't compile, because the linker is (correctly) identifying that it has no idea where
inc
will come from in the built artifact:The wasm linker supports 2 option arguments for dealing with this:
So either this:
or this:
How should zig import functions from JS? For now maybe just pass
--allow-undefined
to wasm-ld?But that said, larger projects we want that link error if you forget to add a function. We could have
extern "wasm" fn blah() void;
, or something like that. Then compilation could drop all those function names into a text file and pass them via--allow-undefined-file=
to the linker.?? Thoughts?
The text was updated successfully, but these errors were encountered: