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

cmd/link: don't resolve WebAssembly imports at link-time #29108

Open
PiotrSikora opened this Issue Dec 5, 2018 · 5 comments

Comments

Projects
None yet
4 participants
@PiotrSikora

PiotrSikora commented Dec 5, 2018

What version of Go are you using (go version)?

$ go version
go version go1.11.2 linux/amd64

But also tested with devel:

$ go version
go version devel +be09bdf589 Tue Dec 4 23:01:00 2018 +0000 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/user/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/user/go"
GOPROXY=""
GORACE=""
GOROOT="/home/user/Google/go"
GOTMPDIR=""
GOTOOLDIR="/home/user/Google/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="clang-8"
CXX="clang++-8"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build949670883=/tmp/go-build -gno-record-gcc-switches"

What did you do?

$ cat wasm_log.go
package main

import (
        _ "unsafe" // for go:linkname
)

//go:linkname wasm_log wasm_log
func wasm_log(s string)

func main() {
        wasm_log("Hello, world!")
}

Note: the wasm_log function is provided by the host environment and is expected to be resolved at runtime, when the WASM module is instantiated.

What did you expect to see?

Compiled WASM module that communicates with the host environment.

For the comparison, it builds successfully with TinyGo, and the resulting WASM module works as expected:

$ tinygo build -target=wasm -no-debug -o wasm_log.wasm wasm_log.go
$ wavm-disas wasm_log.wasm wasm_log.wat
$ cat wasm_log.wat
(module
  (type $0 (func (result i32)))
  (type $1 (func (param i32 i32)))
  (type $2 (func))
  (import "env" "io_get_stdout" (func $io_get_stdout (result i32)))
  (import "env" "wasm_log" (func $wasm_log (param i32 i32)))
  (export "memory" (memory $4))
  (export "__heap_base" (global $6))
  (export "__data_end" (global $7))
  (export "_start" (func $_start))
  (export "cwa_main" (func $cwa_main))
  (memory $4  2)
  (table $3  1 1 anyfunc)
  (global $5  (mut i32) (i32.const 66576))
  (global $6  i32 (i32.const 66576))
  (global $7  i32 (i32.const 1037))
  (data $4 (i32.const 1024)
    "Hello, world!")

  (func $__wasm_call_ctors (type $2)
    )

  (func $_start (type $2)
    call $io_get_stdout
    drop
    )

  (func $cwa_main (type $2)
    call $io_get_stdout
    drop
    i32.const 1024
    i32.const 13
    call $wasm_log
    ))

What did you see instead?

With go1.11.2:

$ GOOS=js GOARCH=wasm go build -o wasm_log.wasm wasm_log.go
# command-line-arguments
./wasm_log.go:8:6: missing function body

With devel (thanks to https://golang.org/cl/151318):

$ GOOS=js GOARCH=wasm go build -o wasm_log.wasm wasm_log.go
# command-line-arguments
main.main: relocation target wasm_log not defined
@agnivade

This comment has been minimized.

Member

agnivade commented Dec 5, 2018

IIUC, you are proposing //go:linkname to be treated differently in a wasm environment.

Will leave to @neelance @bradfitz to take a call.

@neelance

This comment has been minimized.

Member

neelance commented Dec 5, 2018

Currently the CallImport instruction is used to call imported functions, see https://github.com/golang/go/blob/master/src/syscall/js/js_js.s. This is not public API though.

@cherrymui

This comment has been minimized.

Contributor

cherrymui commented Dec 5, 2018

Supporting generating Wasm modules is probably a good idea.

I think this would be a different build mode, like c-archive or c-shared on other platforms, that generates a library instead of an executable. The library can be "loaded"/"linked" at later time. Maybe we just reuse one of them, although it is not really "c".

@cherrymui

This comment has been minimized.

Contributor

cherrymui commented Dec 5, 2018

IIUC, you are proposing //go:linkname to be treated differently in a wasm environment.

I don't think this needs anything with //go:linkname .

@PiotrSikora

This comment has been minimized.

PiotrSikora commented Dec 5, 2018

Right now //go:linkname is needed to work-around the "missing function body" issue, and in case of TinyGo, it's used to change the function name in import in the WASM output, but yeah, if the linker had first-class support for WASM, then this shouldn't be necessary.

I could see a value in adding //go:wasm_import function_name [module_name] to make the dynamic import explicit, and to avoid any name clashes with resolved imports. Basically, a WASM-equivalent of //go:cgo_import_dynamic (which I couldn't figure out how to abuse to make it work for WASM).

Note that imports in WASM have both: module name and function name, so it would be great if one could specify both, with "env" being the default if no module name was provided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment