diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index b5e28e325459c0..b29f94e94cd4e9 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1614,6 +1614,8 @@ func (p *Package) gccCmd() []string { c = append(c, "-maix64") c = append(c, "-mcmodel=large") } + // disable LTO so we get a real object + c = append(c, "-fno-lto") c = append(c, "-") //read input from standard input return c } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 8e83f02202f73c..c7a680043ec540 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -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) + // We must ensure the executable cgo is creating here has a + // reference to all symbols Go code is referring + // to -- because otherwise the system linker might decline + // to add DT_NEEDED entries for the library that has the symbol definition. + // We treat function pointer types differently to avoid link-time failures + // when using LTO with an external linker. + 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) @@ -1028,7 +1038,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) 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. diff --git a/src/cmd/go/testdata/script/issue_43830.txt b/src/cmd/go/testdata/script/issue_43830.txt new file mode 100644 index 00000000000000..984ec6f6a96624 --- /dev/null +++ b/src/cmd/go/testdata/script/issue_43830.txt @@ -0,0 +1,38 @@ +# tests golang.org/issue/43830 + +[!cgo] skip 'skipping test without cgo' +[!exec:gcc] skip 'skipping test without gcc present' +[openbsd] env CC='clang' +[!openbsd] env CC='gcc' + +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 +} diff --git a/src/cmd/go/testdata/script/issue_43830_2.txt b/src/cmd/go/testdata/script/issue_43830_2.txt new file mode 100644 index 00000000000000..5121d032bd68f3 --- /dev/null +++ b/src/cmd/go/testdata/script/issue_43830_2.txt @@ -0,0 +1,32 @@ +# tests golang.org/issue/43830 + +[!cgo] skip 'skipping test without cgo' +[!exec:gcc] skip 'skipping test without gcc present' +[openbsd] env CC='clang' +[!openbsd] env CC='gcc' + +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 + +void hello(void) { + printf("hello\n"); +}