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 <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 6e9f80a..827ccf3 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -201,7 +201,8 @@
 
 		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 @@
 			}
 		}
 
-		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
 			}