-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
What version of Go are you using (go version)?
go version go1.6 darwin/amd64
go version devel +aa3650f Wed Mar 9 09:13:43 2016 +0000 darwin/amd64
What operating system and processor architecture are you using (go env)?
Mac OS X 10.9.5 on Intel Core i7-3615QM
GOARCH="amd64"
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/tsuna/go"
GOROOT="/usr/local/Cellar/go/1.6/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.6/libexec/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"
What did you do?
The Go manual on Compiler Directives says:
The //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code.
For example let's say (hypothetically) that I wanted to call the strhash function defined in the runtime package, I could do:
package key
import "unsafe"
//go:linkname strhash runtime.strhash
func strhash(a unsafe.Pointer, h uintptr) uintptr
func hash(s string) uintptr {
return strhash(unsafe.Pointer(&s), 0)
}What did you expect to see?
The code above should build with no special ceremony.
What did you see instead?
The code doesn't build for a silly reason:
strhash.go:6: missing function body for "strhash"
This comes from the fact that in cmd/compile/internal/gc/pgen.go we do:
if fn.Nbody == nil {
if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
goto ret
}So in order to pass this check, we need to not have pure_go, which comes from the -complete flag in cmd/compile/internal/gc/lex.go:
obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)which is passed from cmd/go/build.go under the following circumstances:
// If we're giving the compiler the entire package (no C etc files), tell it that,
// so that it can give good error messages about forward declarations.
// Exceptions: a few standard packages have forward declarations for
// pieces supplied behind-the-scenes by package runtime.
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
extFiles++
}
}
if extFiles == 0 {
gcargs = append(gcargs, "-complete")
}So one workaround to not be -complete is to include an empty .s file in the package using the //go:linkname directive, as this will make len(p.SFiles) be 1, which in turn will make extFiles non-zero, so that the -complete flag won't get passed and we can pass the check above, and then the code builds and runs as expected. Phew!