From b402bd4499a59c6f1fac4dc2684390b5d4d1c2eb Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 31 May 2019 15:32:22 -0400 Subject: [PATCH] cmd/compile: generate ABI wrappers for //go:linkname'd symbols Calling a Go symbol from assembly in another package currently results in a link failure because the Go symbol is defined as ABIInternal, but the assembly call is from ABI0. In general this is okay because you shouldn't do this anyway, but there are special cases where this is necessary, especially between the runtime and packages closely tied to the runtime in std. Currently, we address this for runtime symbols with a hack in cmd/go that knows to scan related packages when building the symabis file for the runtime and runtime/internal/atomic. However, in addition to being a messy solution in the first place, this hack causes races in cmd/go that are difficult to work around. We considered creating dummy references from assembly in the runtime to these symbols, just to make sure they get ABI0 wrappers. However, there are a fairly large number of these symbols on some platforms, and it can vary significantly depending on build flags (e.g., race mode), so even this solution is fairly unpalatable. This CL addresses this by providing a way to mark symbols in Go code that should be made available to assembly in other packages. Rather than introduce a new pragma, we lightly expand the meaning of "//go:linkname", since that pragma already generally indicates that you're making the symbol available in a way it wasn't before. This also dovetails nicely with the behavior of go:linkname in gccgo, which makes unexported symbols available to other packages. Follow-up CLs will make use of this and then remove the hack from cmd/go. Updates #31230. Change-Id: I23060c97280626581f025c5c01fb8d24bb4c5159 Reviewed-on: https://go-review.googlesource.com/c/go/+/179860 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/gsubr.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index 6e9f80a89d..827ccf3696 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -201,7 +201,8 @@ func (f *Func) initLSym(hasBody bool) { var aliasABI obj.ABI needABIAlias := false - if abi, ok := symabiDefs[f.lsym.Name]; ok && abi == obj.ABI0 { + defABI, hasDefABI := symabiDefs[f.lsym.Name] + if hasDefABI && defABI == obj.ABI0 { // Symbol is defined as ABI0. Create an // Internal -> ABI0 wrapper. f.lsym.SetABI(obj.ABI0) @@ -215,9 +216,19 @@ func (f *Func) initLSym(hasBody bool) { } } - if abi, ok := symabiRefs[f.lsym.Name]; ok && abi == obj.ABI0 { - // Symbol is referenced as ABI0. Create an - // ABI0 -> Internal wrapper if necessary. + isLinknameExported := nam.Sym.Linkname != "" && (hasBody || hasDefABI) + if abi, ok := symabiRefs[f.lsym.Name]; (ok && abi == obj.ABI0) || isLinknameExported { + // Either 1) this symbol is definitely + // referenced as ABI0 from this package; or 2) + // this symbol is defined in this package but + // given a linkname, indicating that it may be + // referenced from another package. Create an + // ABI0 -> Internal wrapper so it can be + // called as ABI0. In case 2, it's important + // that we know it's defined in this package + // since other packages may "pull" symbols + // using linkname and we don't want to create + // duplicate ABI wrappers. if f.lsym.ABI() != obj.ABI0 { needABIAlias, aliasABI = true, obj.ABI0 } -- 2.50.0