Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gccgo: compile cgo got error in aarch64, clang, gold (or lld) #54367

Open
And-ZJ opened this issue Aug 10, 2022 · 3 comments
Open

gccgo: compile cgo got error in aarch64, clang, gold (or lld) #54367

And-ZJ opened this issue Aug 10, 2022 · 3 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@And-ZJ
Copy link
Contributor

And-ZJ commented Aug 10, 2022

What version of Go are you using (go version)?

$ go version
# go version
go version go1.19 linux/arm64

# gccgo --version
gccgo (GCC) 12.1.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Does this issue reproduce with the latest release?

I didn't test golang/go master branch, but there should be.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="off"
GOARCH="arm64"
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GOOS="linux"
GOROOT="/usr/GoRelease/go1.19"
GOTOOLDIR="/usr/GoRelease/go1.19/pkg/tool/linux_arm64"
GOVERSION="go1.19"
GCCGO="/usr/gcc-12.1.0-install/bin/gccgo"
CC="/usr/llvm/bin/clang"
CXX="/usr/llvm/bin/clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
GOGCCFLAGS="-fPIC -pthread -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1375830659=/tmp/go-build -gno-record-gcc-switches

Linux kernel 4.19.90 aarch64

What did you do?

A simple cgo code:

// cgo.go
package main

// #include <stdio.h>
// #include <stdlib.h>
//
// static void myprint(char* s) {
//   printf("%s\n", s);
// }
import "C"
import (
	"unsafe"
)

func main() {
	_Cfunc := C.CString("Hello from stdio")
	C.myprint(_Cfunc)
	C.free(unsafe.Pointer(_Cfunc))
}

export GCCGO="/usr/gcc-12.1.0-install/bin/gccgo"
export CC="/usr/llvm/bin/clang"
export CXX="/usr/llvm/bin/clang++"

(LD_LIBRARY_PATH also needs to be set)

(1) If not use gccgo, these commands all work properly.

go build -a cgo.go
go build -a -ldflags="-extld=clang -extldflags=-fuse-ld=gold" cgo.go
go build -a -ldflags="-extld=clang -extldflags=-fuse-ld=lld" cgo.go

(2) If use gccgo, but use ld linker (default is ld) , these commands also work properly.

go build -a -compiler=gccgo cgo.go
go build -a -compiler=gccgo -gccgoflags="-fuse-ld=bfd" cgo.go

(3) If use gccgo, but use gold or lld linker, got some error:

# go build -compiler=gccgo -gccgoflags="-fuse-ld=gold" cgo.go
# command-line-arguments
/usr/bin/ld.gold: error: linker does not include stack split support required by $WORK/b001/_pkg1_.a(_cgo_defun.o)
collect2: error: ld returned 1 exit status
# go build -compiler=gccgo -gccgoflags="-fuse-ld=lld" cgo.go
# command-line-arguments
ld.lld: error: Mixing split-stack objects requires a definition of __morestack_non_split
ld.lld: error: Mixing split-stack objects requires a definition of __morestack_non_split
collect2: error: ld returned 1 exit status

I found some split-stack checks in the code.

Position 1:

In src/cmd/go/internal/work/exec.go#L2816 :

	if cfg.BuildToolchainName == "gccgo" {
		if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") {
			cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
		}
		cgoflags = append(cgoflags, "-gccgo")
		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
		}
	}

The BuildToolchain.compiler() is /usr/gcc-12.1.0-install/bin/gccgo, so here is check whether gccgo support -fsplit-stack.

# /usr/gcc-12.1.0-install/bin/gccgo -fsplit-stack -c -x c - -o /dev/null
cc1: error: ‘-fsplit-stack’ is not supported by this compiler configuration

So, gccgo does not support -fsplit-stack in my env.

Position 2:

In src/cmd/go/internal/work/gccgo.go#L569:

compiler := envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
	if b.gccSupportsFlag(compiler, "-fsplit-stack") {
		defs = append(defs, "-fsplit-stack")
	}

The variable compiler[0] is ${CC}, in my env, it was /usr/llvm/bin/clang. so here is check whether clang support -fsplit-stack.

# /usr/llvm/bin/clang -fsplit-stack -c -x c - -o /dev/null

No errors, which means that clang supports -fsplit-stack in my env.

Therefore, from the above results, I guess:
The gccgo compile go code in non-split-stack mode.
And the clang compile c code in split-stack mode.
Finally, the gold or lld linker reports an error when linking the two object files.

I see the comments in gollvm :

  # For amd64, as gcc, clang, ld and ld.gold all support -fsplit-stack, so all
  # going well. For arm64, the situation is very complicated, none of gcc, ld
  # and ld.gold support this option, but clang does. When using clang compiler
  # and ld linker, the test passes, but in fact ld does not support stack
  # splitting. So here we do this test with ld.gold linker.
  # FIXME: update here once one day there is a linker that supports '-fsplit-stack'
  # on arm64.

The preceding test results comply with the description here.

So, in aarch64, I can't use gccgo with clang and gold (or lld).

I have two ideas for a fix.

① If it is detected that the gccgo does not support split-stack, ${CC} does not check whether it supports split-stack and directly uses the non-split-stack mode. On the other hand, if it is checked that ${CC} does not support split-stack, then gccgo is also directly in non-split-stack mode.

② Modify the current split-stack checking method, which does not take the linker into account.

If a linker is used, ${CC} may detect that split-stack is not supported so that it is consistent with gccgo.

What do you think?

What did you expect to see?

When use clang, gold (or lld) in aarch64, gccgo compile and run cgo successfully in split-stack or non-split-stack mode.

What did you see instead?

gold or lld reports an error.

@gopherbot gopherbot added this to the Gccgo milestone Aug 10, 2022
@thanm thanm added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Aug 10, 2022
@thanm
Copy link
Contributor

thanm commented Aug 10, 2022

@ianlancetaylor

@thanm
Copy link
Contributor

thanm commented Aug 10, 2022

Option 1 sounds reasonable to me.

@And-ZJ
Copy link
Contributor Author

And-ZJ commented Aug 11, 2022

Add -fno-split-stack in -gccgoflags is also got same error:

go build -a -compiler=gccgo -gccgoflags="-fno-split-stack -fuse-ld=gold" cgo.go
go build -a -compiler=gccgo -gccgoflags="-fno-split-stack -fuse-ld=lld" cgo.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants