-
Notifications
You must be signed in to change notification settings - Fork 989
Closed
Labels
Description
When setting the target as WASI specifying a module to import a function named write
, the generated wasm code will import "wasi_snapshot_preview1" "fd_write"
rather than a function called write
from the correct module.
Example go program with the incorrect import:
package main
//go:wasm-module my_module
//export foo
func foo() int // <-- Works correctly
//go:wasm-module my_module
//export write
func bar() int // <-- imports fd_write from wasi_snapshot_preview1
func main() {
foo()
bar()
}
Compiled using tinygo build -target=wasi -scheduler=none -wasm-abi=generic -o ./module.wasm main.go
Result after converting main.wasm to wat:
(module
(type (;0;) (func (result i32)))
(type (;1;) (func (param i32 i32 i32 i32) (result i32)))
(type (;2;) (func (param i32 i32 i32) (result i32)))
(type (;3;) (func))
(type (;4;) (func (param i32 i32)))
(import "my_module" "foo" (func $foo (type 0)))
(import "wasi_snapshot_preview1" "fd_write" (func $__wasi_fd_write (type 1)))
(func $memset (type 2) (param i32 i32 i32) (result i32)
(local i32 i32 i32 i64)
block ;; label = @1
local.get 2
i32.eqz
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8
local.get 2
local.get 0
i32.add
local.tee 3
i32.const -1
i32.add
local.get 1
i32.store8
local.get 2
i32.const 3
i32.lt_u
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8 offset=2
local.get 0
local.get 1
i32.store8 offset=1
local.get 3
i32.const -3
i32.add
local.get 1
i32.store8
local.get 3
i32.const -2
i32.add
local.get 1
i32.store8
local.get 2
i32.const 7
i32.lt_u
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8 offset=3
local.get 3
i32.const -4
i32.add
local.get 1
i32.store8
local.get 2
i32.const 9
i32.lt_u
br_if 0 (;@1;)
local.get 0
i32.const 0
local.get 0
i32.sub
i32.const 3
i32.and
local.tee 4
i32.add
local.tee 3
local.get 1
i32.const 255
i32.and
i32.const 16843009
i32.mul
local.tee 1
i32.store
local.get 3
local.get 2
local.get 4
i32.sub
i32.const -4
i32.and
local.tee 4
i32.add
local.tee 2
i32.const -4
i32.add
local.get 1
i32.store
local.get 4
i32.const 9
i32.lt_u
br_if 0 (;@1;)
local.get 3
local.get 1
i32.store offset=8
local.get 3
local.get 1
i32.store offset=4
local.get 2
i32.const -8
i32.add
local.get 1
i32.store
local.get 2
i32.const -12
i32.add
local.get 1
i32.store
local.get 4
i32.const 25
i32.lt_u
br_if 0 (;@1;)
local.get 3
local.get 1
i32.store offset=24
local.get 3
local.get 1
i32.store offset=20
local.get 3
local.get 1
i32.store offset=16
local.get 3
local.get 1
i32.store offset=12
local.get 2
i32.const -16
i32.add
local.get 1
i32.store
local.get 2
i32.const -20
i32.add
local.get 1
i32.store
local.get 2
i32.const -24
i32.add
local.get 1
i32.store
local.get 2
i32.const -28
i32.add
local.get 1
i32.store
local.get 4
local.get 3
i32.const 4
i32.and
i32.const 24
i32.or
local.tee 5
i32.sub
local.tee 2
i32.const 32
i32.lt_u
br_if 0 (;@1;)
local.get 1
i64.extend_i32_u
local.tee 6
i64.const 32
i64.shl
local.get 6
i64.or
local.set 6
local.get 3
local.get 5
i32.add
local.set 1
loop ;; label = @2
local.get 1
local.get 6
i64.store
local.get 1
i32.const 24
i32.add
local.get 6
i64.store
local.get 1
i32.const 16
i32.add
local.get 6
i64.store
local.get 1
i32.const 8
i32.add
local.get 6
i64.store
local.get 1
i32.const 32
i32.add
local.set 1
local.get 2
i32.const -32
i32.add
local.tee 2
i32.const 31
i32.gt_u
br_if 0 (;@2;)
end
end
local.get 0)
(func $write (type 2) (param i32 i32 i32) (result i32)
(local i32)
global.get 0
i32.const 16
i32.sub
local.tee 3
global.set 0
local.get 3
local.get 2
i32.store offset=12
local.get 3
local.get 1
i32.store offset=8
block ;; label = @1
block ;; label = @2
local.get 0
local.get 3
i32.const 8
i32.add
i32.const 1
local.get 3
i32.const 4
i32.add
call $__wasi_fd_write
local.tee 0
i32.eqz
br_if 0 (;@2;)
i32.const 0
i32.const 8
local.get 0
local.get 0
i32.const 76
i32.eq
select
i32.store offset=65536
i32.const -1
local.set 0
br 1 (;@1;)
end
local.get 3
i32.load offset=4
local.set 0
end
local.get 3
i32.const 16
i32.add
global.set 0
local.get 0)
(func $_start (type 3)
(local i32)
i32.const 65540
i32.const 0
memory.size
i32.const 16
i32.shl
i32.const 65540
i32.sub
i32.const 6
i32.shr_u
call $memset
drop
local.get 0
local.get 0
call $command-line-arguments.main)
(func $command-line-arguments.main (type 4) (param i32 i32)
call $foo
drop
call $write
drop)
(table (;0;) 1 1 funcref)
(memory (;0;) 2)
(global (;0;) (mut i32) (i32.const 65536))
(export "memory" (memory 0))
(export "_start" (func $_start))
(export "command-line-arguments.main" (func $command-line-arguments.main)))
For comparison, the same file but changing the //go:export directive to anything
other than write
outputs the correct import:
package main
//go:wasm-module my_module
//export foo
func foo() int // <-- Works correctly
//go:wasm-module my_module
//export bar
func bar() int // <-- Works correctly
func main() {
foo()
bar()
}
wat output:
(module
(type (;0;) (func (result i32)))
(type (;1;) (func (param i32 i32 i32) (result i32)))
(type (;2;) (func))
(type (;3;) (func (param i32 i32)))
(import "my_module" "foo" (func $foo (type 0)))
(import "my_module" "bar" (func $bar (type 0)))
(func $memset (type 1) (param i32 i32 i32) (result i32)
(local i32 i32 i32 i64)
block ;; label = @1
local.get 2
i32.eqz
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8
local.get 2
local.get 0
i32.add
local.tee 3
i32.const -1
i32.add
local.get 1
i32.store8
local.get 2
i32.const 3
i32.lt_u
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8 offset=2
local.get 0
local.get 1
i32.store8 offset=1
local.get 3
i32.const -3
i32.add
local.get 1
i32.store8
local.get 3
i32.const -2
i32.add
local.get 1
i32.store8
local.get 2
i32.const 7
i32.lt_u
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8 offset=3
local.get 3
i32.const -4
i32.add
local.get 1
i32.store8
local.get 2
i32.const 9
i32.lt_u
br_if 0 (;@1;)
local.get 0
i32.const 0
local.get 0
i32.sub
i32.const 3
i32.and
local.tee 4
i32.add
local.tee 3
local.get 1
i32.const 255
i32.and
i32.const 16843009
i32.mul
local.tee 1
i32.store
local.get 3
local.get 2
local.get 4
i32.sub
i32.const -4
i32.and
local.tee 4
i32.add
local.tee 2
i32.const -4
i32.add
local.get 1
i32.store
local.get 4
i32.const 9
i32.lt_u
br_if 0 (;@1;)
local.get 3
local.get 1
i32.store offset=8
local.get 3
local.get 1
i32.store offset=4
local.get 2
i32.const -8
i32.add
local.get 1
i32.store
local.get 2
i32.const -12
i32.add
local.get 1
i32.store
local.get 4
i32.const 25
i32.lt_u
br_if 0 (;@1;)
local.get 3
local.get 1
i32.store offset=24
local.get 3
local.get 1
i32.store offset=20
local.get 3
local.get 1
i32.store offset=16
local.get 3
local.get 1
i32.store offset=12
local.get 2
i32.const -16
i32.add
local.get 1
i32.store
local.get 2
i32.const -20
i32.add
local.get 1
i32.store
local.get 2
i32.const -24
i32.add
local.get 1
i32.store
local.get 2
i32.const -28
i32.add
local.get 1
i32.store
local.get 4
local.get 3
i32.const 4
i32.and
i32.const 24
i32.or
local.tee 5
i32.sub
local.tee 2
i32.const 32
i32.lt_u
br_if 0 (;@1;)
local.get 1
i64.extend_i32_u
local.tee 6
i64.const 32
i64.shl
local.get 6
i64.or
local.set 6
local.get 3
local.get 5
i32.add
local.set 1
loop ;; label = @2
local.get 1
local.get 6
i64.store
local.get 1
i32.const 24
i32.add
local.get 6
i64.store
local.get 1
i32.const 16
i32.add
local.get 6
i64.store
local.get 1
i32.const 8
i32.add
local.get 6
i64.store
local.get 1
i32.const 32
i32.add
local.set 1
local.get 2
i32.const -32
i32.add
local.tee 2
i32.const 31
i32.gt_u
br_if 0 (;@2;)
end
end
local.get 0)
(func $_start (type 2)
(local i32)
i32.const 65536
i32.const 0
memory.size
i32.const 16
i32.shl
i32.const 65536
i32.sub
i32.const 6
i32.shr_u
call $memset
drop
local.get 0
local.get 0
call $command-line-arguments.main)
(func $command-line-arguments.main (type 3) (param i32 i32)
call $foo
drop
call $bar
drop)
(table (;0;) 1 1 funcref)
(memory (;0;) 1)
(global (;0;) (mut i32) (i32.const 65536))
(export "memory" (memory 0))
(export "_start" (func $_start))
(export "command-line-arguments.main" (func $command-line-arguments.main)))
It also seems to import correctly when no module or export directive is set:
package main
//go:wasm-module my_module
//export foo
func foo() int // <-- Works correctly
func write() int // <-- imports from env
func main() {
foo()
write()
}
Gives:
(module
(type (;0;) (func (result i32)))
(type (;1;) (func (param i32 i32) (result i32)))
(type (;2;) (func (param i32 i32 i32) (result i32)))
(type (;3;) (func))
(type (;4;) (func (param i32 i32)))
(import "my_module" "foo" (func $foo (type 0)))
(import "env" "command-line-arguments.write" (func $command-line-arguments.write (type 1)))
(func $memset (type 2) (param i32 i32 i32) (result i32)
(local i32 i32 i32 i64)
block ;; label = @1
local.get 2
i32.eqz
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8
local.get 2
local.get 0
i32.add
local.tee 3
i32.const -1
i32.add
local.get 1
i32.store8
local.get 2
i32.const 3
i32.lt_u
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8 offset=2
local.get 0
local.get 1
i32.store8 offset=1
local.get 3
i32.const -3
i32.add
local.get 1
i32.store8
local.get 3
i32.const -2
i32.add
local.get 1
i32.store8
local.get 2
i32.const 7
i32.lt_u
br_if 0 (;@1;)
local.get 0
local.get 1
i32.store8 offset=3
local.get 3
i32.const -4
i32.add
local.get 1
i32.store8
local.get 2
i32.const 9
i32.lt_u
br_if 0 (;@1;)
local.get 0
i32.const 0
local.get 0
i32.sub
i32.const 3
i32.and
local.tee 4
i32.add
local.tee 3
local.get 1
i32.const 255
i32.and
i32.const 16843009
i32.mul
local.tee 1
i32.store
local.get 3
local.get 2
local.get 4
i32.sub
i32.const -4
i32.and
local.tee 4
i32.add
local.tee 2
i32.const -4
i32.add
local.get 1
i32.store
local.get 4
i32.const 9
i32.lt_u
br_if 0 (;@1;)
local.get 3
local.get 1
i32.store offset=8
local.get 3
local.get 1
i32.store offset=4
local.get 2
i32.const -8
i32.add
local.get 1
i32.store
local.get 2
i32.const -12
i32.add
local.get 1
i32.store
local.get 4
i32.const 25
i32.lt_u
br_if 0 (;@1;)
local.get 3
local.get 1
i32.store offset=24
local.get 3
local.get 1
i32.store offset=20
local.get 3
local.get 1
i32.store offset=16
local.get 3
local.get 1
i32.store offset=12
local.get 2
i32.const -16
i32.add
local.get 1
i32.store
local.get 2
i32.const -20
i32.add
local.get 1
i32.store
local.get 2
i32.const -24
i32.add
local.get 1
i32.store
local.get 2
i32.const -28
i32.add
local.get 1
i32.store
local.get 4
local.get 3
i32.const 4
i32.and
i32.const 24
i32.or
local.tee 5
i32.sub
local.tee 2
i32.const 32
i32.lt_u
br_if 0 (;@1;)
local.get 1
i64.extend_i32_u
local.tee 6
i64.const 32
i64.shl
local.get 6
i64.or
local.set 6
local.get 3
local.get 5
i32.add
local.set 1
loop ;; label = @2
local.get 1
local.get 6
i64.store
local.get 1
i32.const 24
i32.add
local.get 6
i64.store
local.get 1
i32.const 16
i32.add
local.get 6
i64.store
local.get 1
i32.const 8
i32.add
local.get 6
i64.store
local.get 1
i32.const 32
i32.add
local.set 1
local.get 2
i32.const -32
i32.add
local.tee 2
i32.const 31
i32.gt_u
br_if 0 (;@2;)
end
end
local.get 0)
(func $_start (type 3)
(local i32)
i32.const 65536
i32.const 0
memory.size
i32.const 16
i32.shl
i32.const 65536
i32.sub
i32.const 6
i32.shr_u
call $memset
drop
local.get 0
local.get 0
call $command-line-arguments.main)
(func $command-line-arguments.main (type 4) (param i32 i32)
(local i32)
call $foo
drop
local.get 2
local.get 2
call $command-line-arguments.write
drop)
(table (;0;) 1 1 funcref)
(memory (;0;) 1)
(global (;0;) (mut i32) (i32.const 65536))
(export "memory" (memory 0))
(export "_start" (func $_start))
(export "command-line-arguments.main" (func $command-line-arguments.main)))
torch2424torch2424torch2424torch2424