From 9091ce77930923dacf82e0f72eac466e915c490c Mon Sep 17 00:00:00 2001
From: Clement <clement.chigot@atos.net>
Date: Tue, 19 Feb 2019 14:48:00 -0600
Subject: [PATCH 15/24] cmd, runtime: fix C trampolines on aix/ppc64

---
 src/cmd/go/internal/work/exec.go  | 21 +++++++++++++++++++++
 src/cmd/link/internal/ld/lib.go   | 28 ++++++++++++++++++++++++++++
 src/cmd/link/internal/ld/pcln.go  |  2 +-
 src/cmd/link/internal/ld/xcoff.go |  6 +++---
 src/runtime/asm_ppc64x.s          |  6 ++++++
 src/runtime/cgo/callbacks.go      |  5 +++++
 src/runtime/cgo/gcc_aix_ppc64.S   |  4 ++--
 src/runtime/cgo/gcc_aix_ppc64.c   | 22 ++++++++++++++++++++++
 8 files changed, 88 insertions(+), 6 deletions(-)
 create mode 100644 src/runtime/cgo/gcc_aix_ppc64.c

diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 07b21aaf4f..57f6ffbb4e 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2162,11 +2162,32 @@ func (b *Builder) gccld(p *load.Package, objdir, outfile string, flags []string,
 		// Filter out useless linker warnings caused by bugs outside Go.
 		// See also cmd/link/internal/ld's hostlink method.
 		var save [][]byte
+		var skipLines int
 		for _, line := range bytes.SplitAfter(out, []byte("\n")) {
 			// golang.org/issue/26073 - Apple Xcode bug
 			if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
 				continue
 			}
+
+			if skipLines > 0 {
+				skipLines--
+				continue
+			}
+
+			// Remove duplicate main symbol with runtime/cgo on AIX.
+			// With runtime/cgo, two main are available:
+			// One is generated by cgo tool with {return 0;}.
+			// The other one is the main calling runtime.rt0_go
+			// in runtime/cgo.
+			// The second can't be used by cgo programs because
+			// runtime.rt0_go is unknown to them.
+			// Therefore, we let ld remove this main version
+			// and used the cgo generated one.
+			if p.ImportPath == "runtime/cgo" && bytes.Contains(line, []byte("ld: 0711-224 WARNING: Duplicate symbol: .main")) {
+				skipLines = 1
+				continue
+			}
+
 			save = append(save, line)
 		}
 		out = bytes.Join(save, nil)
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 19d04461c3..3f610ae4a1 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1286,6 +1286,34 @@ func (ctxt *Link) hostlink() {
 
 	argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
 	argv = append(argv, hostobjCopy()...)
+	if ctxt.HeadType == objabi.Haix {
+		// We want to have C files after Go files to remove
+		// trampolines csects made by ld.
+		argv = append(argv, "-nostartfiles")
+		argv = append(argv, "/lib/crt0_64.o")
+
+		// Get gcc starting files.
+		var target, version string
+		out, err := exec.Command("gcc", "-v").CombinedOutput()
+		if err != nil {
+			Exitf("running gcc failed: %v\n%s", err, out)
+		}
+
+		for _, line := range bytes.SplitAfter(out, []byte("\n")) {
+			if bytes.Contains(line, []byte("Target:")) {
+				targetbyte := bytes.Split(line, []byte(" "))[1]
+				target = string(bytes.Trim(targetbyte, "\n"))
+			}
+			if bytes.Contains(line, []byte("gcc version")) {
+				version = string(bytes.Split(line, []byte(" "))[2])
+			}
+		}
+
+		dir := "/opt/freeware/lib/gcc/" + target + "/" + version
+
+		argv = append(argv, dir+"/pthread/ppc64/crtcxa.o")
+		argv = append(argv, dir+"/pthread/ppc64/crtdbase.o")
+	}
 
 	if ctxt.linkShared {
 		seenDirs := make(map[string]bool)
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index e4db834622..1d4315590c 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -164,7 +164,7 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
 // onlycsymbol reports whether this is a symbol that is referenced by C code.
 func onlycsymbol(s *sym.Symbol) bool {
 	switch s.Name {
-	case "_cgo_topofstack", "_cgo_panic", "crosscall2":
+	case "_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2":
 		return true
 	}
 	if strings.HasPrefix(s.Name, "_cgoexp_") {
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index ca95d5945e..4276fbe5d4 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -1224,9 +1224,9 @@ func (ctxt *Link) doxcoff() {
 	}
 
 	if ctxt.LinkMode == LinkExternal {
-		// Change main name to match __start code.
-		main := ctxt.Syms.ROLookup("_main", 0)
-		main.Name = ".main"
+		// Change rt0_go name to match name in runtime/cgo:main().
+		rt0 := ctxt.Syms.ROLookup("runtime.rt0_go", 0)
+		ctxt.Syms.Rename(rt0.Name, "runtime_rt0_go", 0, ctxt.Reachparent)
 
 		for _, s := range ctxt.Syms.Allsym {
 			if !s.Attr.CgoExport() {
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 9539423d4b..76af1e0a2b 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -854,7 +854,13 @@ TEXT runtime·return0(SB), NOSPLIT, $0
 
 // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
 // Must obey the gcc calling convention.
+#ifdef GOOS_aix
+// On AIX, _cgo_topofstack is defined in runtime/cgo, because it must
+// be a longcall in order to prevent trampolines from ld.
+TEXT __cgo_topofstack(SB),NOSPLIT|NOFRAME,$0
+#else
 TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0
+#endif
 	// g (R30) and R31 are callee-save in the C ABI, so save them
 	MOVD	g, R4
 	MOVD	R31, R5
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
index 14a218ec92..64ab24abce 100644
--- a/src/runtime/cgo/callbacks.go
+++ b/src/runtime/cgo/callbacks.go
@@ -109,3 +109,8 @@ var _cgo_yield unsafe.Pointer
 
 //go:cgo_export_static _cgo_topofstack
 //go:cgo_export_dynamic _cgo_topofstack
+
+// This is specific to AIX (see gcc_aix_ppc64.c).
+// It will be removed for others OSes.
+//go:cgo_export_static __cgo_topofstack
+//go:cgo_export_static runtime.rt0_go
diff --git a/src/runtime/cgo/gcc_aix_ppc64.S b/src/runtime/cgo/gcc_aix_ppc64.S
index ea1e4ceaaa..af0addc3fd 100644
--- a/src/runtime/cgo/gcc_aix_ppc64.S
+++ b/src/runtime/cgo/gcc_aix_ppc64.S
@@ -31,8 +31,8 @@ crosscall_ppc64:
 	stdu	1, -296(1)
 
 	// Set up Go ABI constant registers
-	bl	._cgo_reginit
-	nop
+	// Must match _cgo_reginit in runtime package.
+	xor 0, 0, 0
 
 	// Restore g pointer (r30 in Go ABI, which may have been clobbered by C)
 	mr	30, 4
diff --git a/src/runtime/cgo/gcc_aix_ppc64.c b/src/runtime/cgo/gcc_aix_ppc64.c
new file mode 100644
index 0000000000..bcb615d4b6
--- /dev/null
+++ b/src/runtime/cgo/gcc_aix_ppc64.c
@@ -0,0 +1,22 @@
+// Copyright 2018 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 aix
+// +build ppc64 ppc64le
+
+/*
+ * On AIX, call to _cgo_topofstack and main are forced to be a longcall.
+ * Without it, ld might add trampolines in the middle of .text section
+ * to reach these functions which are normally declared in runtime package.
+ */
+extern int __attribute__((longcall)) __cgo_topofstack(void);
+extern int __attribute__((longcall)) runtime_rt0_go(int argc, char **argv);
+
+int _cgo_topofstack(void) {
+	return __cgo_topofstack();
+}
+
+int main(int argc, char **argv){
+	return runtime_rt0_go(argc, argv);
+}
-- 
2.15.1

