]> Cypherpunks repositories - gostls13.git/commitdiff
cmd, runtime: fix C trampolines on aix/ppc64
authorClément Chigot <clement.chigot@atos.net>
Wed, 20 Feb 2019 15:52:35 +0000 (16:52 +0100)
committerIan Lance Taylor <iant@golang.org>
Tue, 19 Mar 2019 03:18:05 +0000 (03:18 +0000)
C trampolines are made by fixup CSECTS which are added between two
symbols. If such CSECTS is added inside Go functions, all method
offsets stored in moduledatas will be wrong.
In order to prevent this, every C code is moved at the end of the
executable and long calls are created for GO functions called by C
code.
The main function can't longer be made in Go as AIX __start isn't using
a long call to branch on it. Therefore, a main is defined on
runtime/cgo.

Change-Id: I214b18decdb83107cf7325b298609eef9f9d1330
Reviewed-on: https://go-review.googlesource.com/c/go/+/164010
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/go/internal/work/exec.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/pcln.go
src/cmd/link/internal/ld/xcoff.go
src/runtime/asm_ppc64x.s
src/runtime/cgo/callbacks_aix.go [new file with mode: 0644]
src/runtime/cgo/gcc_aix_ppc64.S
src/runtime/cgo/gcc_aix_ppc64.c [new file with mode: 0644]

index 3310beb709ab22abee05b4ba134195f7e16b02e3..0e10f2c92622fb8a48c40e56b8c5cfdbff3c0bfc 100644 (file)
@@ -2150,11 +2150,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)
index f12c8aeed7dd2c646638c049127a67e08c53cea2..076d2a71b947646cc1724b0c3d3802e05c48a088 100644 (file)
@@ -1288,6 +1288,25 @@ 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")
+
+               extld := ctxt.extld()
+               // Get starting files.
+               getPathFile := func(file string) string {
+                       args := []string{"-maix64", "--print-file-name=" + file}
+                       out, err := exec.Command(extld, args...).CombinedOutput()
+                       if err != nil {
+                               log.Fatalf("running %s failed: %v\n%s", extld, err, out)
+                       }
+                       return strings.Trim(string(out), "\n")
+               }
+               argv = append(argv, getPathFile("crtcxa.o"))
+               argv = append(argv, getPathFile("crtdbase.o"))
+       }
 
        if ctxt.linkShared {
                seenDirs := make(map[string]bool)
index e32f9e7110acff9eee6fee198d1be189a7e14a8f..5c590608e301c50ef32b2d8e65721567a6272e66 100644 (file)
@@ -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_") {
index f4422ff023700ce9863b00c7519a32e9abef88ad..7fcd8a3c97d8b688d8006027db824d9c2405612c 100644 (file)
@@ -1218,9 +1218,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() {
index 9ac83e55903f968de497264bb35cade505392e6f..d7fc66bda195f2211248a7c6a6bc5b322eccbfa6 100644 (file)
@@ -113,6 +113,7 @@ TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
 TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
        RET
 
+// Any changes must be reflected to runtime/cgo/gcc_aix_ppc64.S:.crosscall_ppc64
 TEXT _cgo_reginit(SB),NOSPLIT|NOFRAME,$0-0
        // crosscall_ppc64 and crosscall2 need to reginit, but can't
        // get at the 'runtime.reginit' symbol.
@@ -847,7 +848,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_aix.go b/src/runtime/cgo/callbacks_aix.go
new file mode 100644 (file)
index 0000000..2665493
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2019 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.
+
+package cgo
+
+// These functions must be exported in order to perform
+// longcall on cgo programs (cf gcc_aix_ppc64.c).
+// go:cgo_export_static __cgo_topofstack
+// go:cgo_export_static runtime.rt0_go
index bff6dd1999a9844014d1b90c19122db0980f3430..a00fae24d219e05d2f2047d5c4eb0e71426b7b41 100644 (file)
@@ -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 (file)
index 0000000..d54c0ff
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2019 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 Go 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);
+}