]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/link, cmd/cgo: support -flto in CFLAGS
authorIan Lance Taylor <iant@golang.org>
Tue, 25 May 2021 23:31:41 +0000 (16:31 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 1 Jun 2021 19:59:18 +0000 (19:59 +0000)
The linker now accepts unrecognized object files in external linking mode.
These objects will simply be passed to the external linker.
This permits using -flto which can generate pure byte code objects,
whose symbol table the linker does not know how to read.

The cgo tool now passes -fno-lto when generating objects whose symbols
it needs to read. The cgo tool now emits matching types in different
objects, so that the lto linker does not report a mismatch.

This is based on https://golang.org/cl/293290 by Derek Parker.

For #43505
Fixes #43830
Fixes #46295

Change-Id: I6787de213417466784ddef5af8899e453b4ae1ad
Reviewed-on: https://go-review.googlesource.com/c/go/+/322614
Trust: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
src/cmd/cgo/gcc.go
src/cmd/cgo/out.go
src/cmd/dist/test.go
src/cmd/go/testdata/script/cgo_lto2_issue43830.txt [new file with mode: 0644]
src/cmd/go/testdata/script/cgo_lto_issue43830.txt [new file with mode: 0644]
src/cmd/link/internal/ld/ar.go
src/cmd/link/internal/ld/config.go
src/cmd/link/internal/ld/lib.go

index ae61725bc751d02f67e8aced126488bc92c52e7d..a73e998877af812762afcc4716c17b78adf7f065 100644 (file)
@@ -1638,6 +1638,8 @@ func (p *Package) gccCmd() []string {
                c = append(c, "-maix64")
                c = append(c, "-mcmodel=large")
        }
+       // disable LTO so we get an object whose symbols we can read
+       c = append(c, "-fno-lto")
        c = append(c, "-") //read input from standard input
        return c
 }
index 8c31d5b7941759da83701cbfb7983a66c48990d8..94152f4278cb04b44325a936c50d8d11887f4b3d 100644 (file)
@@ -168,8 +168,18 @@ func (p *Package) writeDefs() {
                        if *gccgo {
                                fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
                        } else {
-                               fmt.Fprintf(fm, "extern char %s[];\n", n.C)
-                               fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+                               // Force a reference to all symbols so that
+                               // the external linker will add DT_NEEDED
+                               // entries as needed on ELF systems.
+                               // Treat function variables differently
+                               // to avoid type confict errors from LTO
+                               // (Link Time Optimization).
+                               if n.Kind == "fpvar" {
+                                       fmt.Fprintf(fm, "extern void %s();\n", n.C)
+                               } else {
+                                       fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+                                       fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+                               }
                                fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
                                fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
                                fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
@@ -1042,7 +1052,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                // This unpacks the argument struct above and calls the Go function.
                fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
 
-               fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
+               fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
 
                if gccResult != "void" {
                        // Write results back to frame.
index 50bf80ba5960bd084f3f9d4453ff99c1283db57f..bc49c6d80402e37389dcd51cc0c660727d4d65fe 100644 (file)
@@ -722,14 +722,29 @@ func (t *tester) registerTests() {
                                },
                        })
                        if t.hasCxx() {
-                               t.tests = append(t.tests, distTest{
-                                       name:    "swig_callback",
-                                       heading: "../misc/swig/callback",
-                                       fn: func(dt *distTest) error {
-                                               t.addCmd(dt, "misc/swig/callback", t.goTest())
-                                               return nil
+                               t.tests = append(t.tests,
+                                       distTest{
+                                               name:    "swig_callback",
+                                               heading: "../misc/swig/callback",
+                                               fn: func(dt *distTest) error {
+                                                       t.addCmd(dt, "misc/swig/callback", t.goTest())
+                                                       return nil
+                                               },
+                                       },
+                                       distTest{
+                                               name:    "swig_callback_lto",
+                                               heading: "../misc/swig/callback",
+                                               fn: func(dt *distTest) error {
+                                                       cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
+                                                       cmd.Env = append(os.Environ(),
+                                                               "CGO_CFLAGS=-flto",
+                                                               "CGO_CXXFLAGS=-flto",
+                                                               "CGO_LDFLAGS=-flto",
+                                                       )
+                                                       return nil
+                                               },
                                        },
-                               })
+                               )
                        }
                }
        }
diff --git a/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto2_issue43830.txt
new file mode 100644 (file)
index 0000000..e2483ba
--- /dev/null
@@ -0,0 +1,33 @@
+# tests golang.org/issue/43830
+
+[!cgo] skip 'skipping test without cgo'
+[openbsd] env CC='clang'
+[openbsd] [!exec:clang] skip 'skipping test without clang present'
+[!openbsd] env CC='gcc'
+[!openbsd] [!exec:gcc] skip 'skipping test without gcc present'
+
+env CGO_CFLAGS='-Wno-ignored-optimization-argument -flto -ffat-lto-objects'
+
+go build main.go
+
+-- main.go --
+
+package main
+
+import "fmt"
+
+// #include "hello.h"
+import "C"
+
+func main() {
+       hello := C.hello
+       fmt.Printf("%v\n", hello)
+}
+
+-- hello.h --
+
+#include <stdio.h>
+
+void hello(void) {
+  printf("hello\n");
+}
diff --git a/src/cmd/go/testdata/script/cgo_lto_issue43830.txt b/src/cmd/go/testdata/script/cgo_lto_issue43830.txt
new file mode 100644 (file)
index 0000000..06ab2f3
--- /dev/null
@@ -0,0 +1,39 @@
+# tests golang.org/issue/43830
+
+[!cgo] skip 'skipping test without cgo'
+[openbsd] env CC='clang'
+[openbsd] [!exec:clang] skip 'skipping test without clang present'
+[!openbsd] env CC='gcc'
+[!openbsd] [!exec:gcc] skip 'skipping test without gcc present'
+
+env CGO_CFLAGS='-Wno-ignored-optimization-argument -flto -ffat-lto-objects'
+
+go build main.go add.go
+
+-- main.go --
+
+package main
+
+/*
+int c_add(int a, int b) {
+       return myadd(a, b);
+}
+*/
+import "C"
+
+func main() {
+       println(C.c_add(1, 2))
+}
+
+-- add.go --
+
+package main
+
+import "C"
+
+/* test */
+
+//export myadd
+func myadd(a C.int, b C.int) C.int {
+       return a + b
+}
index 22f53a4df2ee369ce71df17390178ac1b94d04ff..23915f90329a0a81e74736815c678b1de876de75 100644 (file)
@@ -124,6 +124,10 @@ func hostArchive(ctxt *Link, name string) {
 
                        libgcc := sym.Library{Pkg: "libgcc"}
                        h := ldobj(ctxt, f, &libgcc, l, pname, name)
+                       if h.ld == nil {
+                               Errorf(nil, "%s unrecognized object file at offset %d", name, off)
+                               continue
+                       }
                        f.MustSeek(h.off, 0)
                        h.ld(ctxt, f, h.pkg, h.length, h.pn)
                }
index ae0d7520ebc0790360d3f399c9a0e517f449556c..20f1d0b8c12c6848fd68f83a7e4b41cd1c9f2b7a 100644 (file)
@@ -241,6 +241,10 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
                return true, "dynamically linking with a shared library"
        }
 
+       if unknownObjFormat {
+               return true, "some input objects have an unrecognized file format"
+       }
+
        return false, ""
 }
 
@@ -248,7 +252,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
 //
 // It is called after flags are processed and inputs are processed,
 // so the ctxt.LinkMode variable has an initial value from the -linkmode
-// flag and the iscgo externalobj variables are set.
+// flag and the iscgo, externalobj, and unknownObjFormat variables are set.
 func determineLinkMode(ctxt *Link) {
        extNeeded, extReason := mustLinkExternal(ctxt)
        via := ""
index e8f001ba8ec095f5e3e73a363db3b4537ee025a3..644faeb2fbc2fd039b65681621a296cc700d2e53 100644 (file)
@@ -343,10 +343,16 @@ var (
 const pkgdef = "__.PKGDEF"
 
 var (
-       // Set if we see an object compiled by the host compiler that is not
-       // from a package that is known to support internal linking mode.
+       // externalobj is set to true if we see an object compiled by
+       // the host compiler that is not from a package that is known
+       // to support internal linking mode.
        externalobj = false
-       theline     string
+
+       // unknownObjFormat is set to true if we see an object whose
+       // format we don't recognize.
+       unknownObjFormat = false
+
+       theline string
 )
 
 func Lflag(ctxt *Link, arg string) {
@@ -1065,6 +1071,10 @@ func hostobjs(ctxt *Link) {
                }
 
                f.MustSeek(h.off, 0)
+               if h.ld == nil {
+                       Errorf(nil, "%s: unrecognized object file format", h.pn)
+                       continue
+               }
                h.ld(ctxt, f, h.pkg, h.length, h.pn)
                f.Close()
        }
@@ -1855,6 +1865,14 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
                return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
        }
 
+       if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
+               // An unrecognized object is just passed to the external linker.
+               // If we try to read symbols from this object, we will
+               // report an error at that time.
+               unknownObjFormat = true
+               return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
+       }
+
        /* check the header */
        line, err := f.ReadString('\n')
        if err != nil {
@@ -1874,7 +1892,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
                        return nil
                }
 
-               Errorf(nil, "%s: not an object file: @%d %02x%02x%02x%02x", pn, start, c1, c2, c3, c4)
+               Errorf(nil, "%s: not an object file: @%d %q", pn, start, line)
                return nil
        }