From: Xiangdong Ji <xiangdong.ji@arm.com>
Date: Wed, 5 Aug 2020 06:02:58 +0000
Subject: cmd/dist: fix build failure of misc/cgo/test on arm64

Test7978 of misc/cgo/test fails in 'dist test' on arm64 if the C compiler
is of GCC-9.4 or above and its 'outline atomics' feature is enabled, since
the internal linking hasn't yet supported "__attribute__((constructor))"
and also mis-handles hidden visibility.

Two changes are made for 'misc/cgo/test' to fix the issue:
  1. passing "-tags=internal" for the internal linking PIE case.
  2. skipping Test7978 on arm64 for the internal linking cases.

This CL fixes 'dist test' failure only, user is expected to pass the option
'-mno-outline-atomics' via CGO_CFLAGS if running into the same problem when
building cgo program using internal linking.

Updates #39466
Change-Id: I2011bb051cae7c43eb0f1c78c7f4fbdb94bf78a6
---
 misc/cgo/test/issue7978.go  | 117 ++++++++++++++++++++++++++++++++++++++++++++
 misc/cgo/test/issue7978b.go |  24 +++++++++
 misc/cgo/test/testx.go      | 105 ---------------------------------------
 src/cmd/dist/test.go        |   2 +-
 4 files changed, 142 insertions(+), 106 deletions(-)
 create mode 100644 misc/cgo/test/issue7978.go
 create mode 100644 misc/cgo/test/issue7978b.go

diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go
new file mode 100644
index 0000000..18d418f
--- /dev/null
+++ b/misc/cgo/test/issue7978.go
@@ -0,0 +1,117 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !arm64 !internal
+
+package cgotest
+
+import (
+	"runtime"
+	"runtime/debug"
+	"strings"
+	"sync/atomic"
+	"testing"
+)
+
+/*
+#include <stdint.h>
+
+void issue7978cb(void);
+
+// use ugly atomic variable sync since that doesn't require calling back into
+// Go code or OS dependencies
+static void issue7978c(uint32_t *sync) {
+	while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 0)
+		;
+	__atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST);
+	while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 2)
+		;
+	issue7978cb();
+	__atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST);
+	while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 6)
+		;
+}
+
+*/
+import "C"
+
+// issue 7978
+
+var issue7978sync uint32
+
+func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) {
+	runtime.GC()
+	buf := make([]byte, 65536)
+	trace := string(buf[:runtime.Stack(buf, true)])
+	for _, goroutine := range strings.Split(trace, "\n\n") {
+		if strings.Contains(goroutine, "test.issue7978go") {
+			trace := strings.Split(goroutine, "\n")
+			// look for the expected function in the stack
+			for i := 0; i < depth; i++ {
+				if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) {
+					t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine)
+					return
+				}
+				if strings.Contains(trace[1+2*i], wantFunc) {
+					return
+				}
+			}
+			t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine)
+			return
+		}
+	}
+	t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace)
+}
+
+func issue7978wait(store uint32, wait uint32) {
+	if store != 0 {
+		atomic.StoreUint32(&issue7978sync, store)
+	}
+	for atomic.LoadUint32(&issue7978sync) != wait {
+		runtime.Gosched()
+	}
+}
+
+//export issue7978cb
+func issue7978cb() {
+	// Force a stack growth from the callback to put extra
+	// pressure on the runtime. See issue #17785.
+	growStack(64)
+	issue7978wait(3, 4)
+}
+
+func growStack(n int) int {
+	var buf [128]int
+	if n == 0 {
+		return 0
+	}
+	return buf[growStack(n-1)]
+}
+
+func issue7978go() {
+	C.issue7978c((*C.uint32_t)(&issue7978sync))
+	issue7978wait(7, 8)
+}
+
+func test7978(t *testing.T) {
+	if runtime.Compiler == "gccgo" {
+		t.Skip("gccgo can not do stack traces of C code")
+	}
+	debug.SetTraceback("2")
+	issue7978sync = 0
+	go issue7978go()
+	// test in c code, before callback
+	issue7978wait(0, 1)
+	issue7978check(t, "_Cfunc_issue7978c(", "", 1)
+	// test in go code, during callback
+	issue7978wait(2, 3)
+	issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
+	// test in c code, after callback
+	issue7978wait(4, 5)
+	issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1)
+	// test in go code, after return from cgo
+	issue7978wait(6, 7)
+	issue7978check(t, "test.issue7978go(", "", 3)
+	atomic.StoreUint32(&issue7978sync, 8)
+}
diff --git a/misc/cgo/test/issue7978b.go b/misc/cgo/test/issue7978b.go
new file mode 100644
index 0000000..3ab11ee
--- /dev/null
+++ b/misc/cgo/test/issue7978b.go
@@ -0,0 +1,24 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// GCC-9.4 and above on arm64 introduced the "outline atomics" that the
+// current internal linking doesn't support.
+// See issue #39466.
+
+// +build arm64,internal
+
+package cgotest
+
+import (
+	"runtime"
+	"testing"
+)
+
+func test7978(t *testing.T) {
+	if runtime.Compiler == "gccgo" {
+		t.Skip("gccgo can not do stack traces of C code")
+	}
+
+	t.Skip("skip on arm64+internal")
+}
diff --git a/misc/cgo/test/testx.go b/misc/cgo/test/testx.go
index 7fbc5c6..08c3287 100644
--- a/misc/cgo/test/testx.go
+++ b/misc/cgo/test/testx.go
@@ -12,10 +12,7 @@ package cgotest
 
 import (
 	"runtime"
-	"runtime/debug"
-	"strings"
 	"sync"
-	"sync/atomic"
 	"testing"
 	"time"
 	"unsafe"
@@ -75,28 +72,6 @@ extern int CheckIssue6907C(_GoString_);
 
 extern void f7665(void);
 
-// issue 7978
-// Stack tracing didn't work during cgo code after calling a Go
-// callback.  Make sure GC works and the stack trace is correct.
-
-#include <stdint.h>
-
-void issue7978cb(void);
-
-// use ugly atomic variable sync since that doesn't require calling back into
-// Go code or OS dependencies
-static void issue7978c(uint32_t *sync) {
-	while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 0)
-		;
-	__atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST);
-	while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 2)
-		;
-	issue7978cb();
-	__atomic_add_fetch(sync, 1, __ATOMIC_SEQ_CST);
-	while(__atomic_load_n(sync, __ATOMIC_SEQ_CST) != 6)
-		;
-}
-
 // issue 8331 part 2 - part 1 in test.go
 // A typedef of an unnamed struct is the same struct when
 // #include'd twice.  No runtime test; just make sure it compiles.
@@ -440,86 +415,6 @@ func test7665(t *testing.T) {
 	}
 }
 
-// issue 7978
-
-var issue7978sync uint32
-
-func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) {
-	runtime.GC()
-	buf := make([]byte, 65536)
-	trace := string(buf[:runtime.Stack(buf, true)])
-	for _, goroutine := range strings.Split(trace, "\n\n") {
-		if strings.Contains(goroutine, "test.issue7978go") {
-			trace := strings.Split(goroutine, "\n")
-			// look for the expected function in the stack
-			for i := 0; i < depth; i++ {
-				if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) {
-					t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine)
-					return
-				}
-				if strings.Contains(trace[1+2*i], wantFunc) {
-					return
-				}
-			}
-			t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine)
-			return
-		}
-	}
-	t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace)
-}
-
-func issue7978wait(store uint32, wait uint32) {
-	if store != 0 {
-		atomic.StoreUint32(&issue7978sync, store)
-	}
-	for atomic.LoadUint32(&issue7978sync) != wait {
-		runtime.Gosched()
-	}
-}
-
-//export issue7978cb
-func issue7978cb() {
-	// Force a stack growth from the callback to put extra
-	// pressure on the runtime. See issue #17785.
-	growStack(64)
-	issue7978wait(3, 4)
-}
-
-func growStack(n int) int {
-	var buf [128]int
-	if n == 0 {
-		return 0
-	}
-	return buf[growStack(n-1)]
-}
-
-func issue7978go() {
-	C.issue7978c((*C.uint32_t)(&issue7978sync))
-	issue7978wait(7, 8)
-}
-
-func test7978(t *testing.T) {
-	if runtime.Compiler == "gccgo" {
-		t.Skip("gccgo can not do stack traces of C code")
-	}
-	debug.SetTraceback("2")
-	issue7978sync = 0
-	go issue7978go()
-	// test in c code, before callback
-	issue7978wait(0, 1)
-	issue7978check(t, "_Cfunc_issue7978c(", "", 1)
-	// test in go code, during callback
-	issue7978wait(2, 3)
-	issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
-	// test in c code, after callback
-	issue7978wait(4, 5)
-	issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1)
-	// test in go code, after return from cgo
-	issue7978wait(6, 7)
-	issue7978check(t, "test.issue7978go(", "", 3)
-	atomic.StoreUint32(&issue7978sync, 8)
-}
-
 // issue 8331 part 2
 
 var issue8331Var C.issue8331
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 2dc9459..ef0c743 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -1145,7 +1145,7 @@ func (t *tester) cgoTest(dt *distTest) error {
 			if t.supportedBuildmode("pie") {
 				t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
 				if t.internalLink() && t.internalLinkPIE() {
-					t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal")
+					t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal")
 				}
 				t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie")
 				t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie")
