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

Does this issue reproduce with the latest release?

Untestable as GCC 8 has code generation issues (that are being fixed right now). It's extremely likely that this issue still affects GCC 8 as I am unaware of any attempts to fix this bug, and unable to find any commits that would lead me to believe it is fixed.

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

Adélie Linux on ppc64 (big endian) using musl (ELFv2 ABI)

What did you do?

$ go version
$ go help

etc.

What did you expect to see?

Actual output from Go.

What did you see instead?

An Abort trap and a panic during panic.

This is because GCC Go is hard-coded to generate ELFv1 ABI code on big-endian PPC64. This is inaccurate. musl libc uses ELFv2 ABI code on big-endian PPC64. GCC Go should probably use the option from ./configure, --with-abi, to determine which ABI to use on PPC64.

Golang Go isn't usable due to #19074, so our only hope is really GCC Go. I've been trying to figure out where, exactly, gccgo emits its code so that I could fix this issue myself. However, I have been unsuccessful. I've already ported many other large software projects to ELFv2, so a pointer to where the code is that needs to be fixed would, more than likely, allow me to complete this port myself. If upstream GCC Go isn't interested in taking this upstream, I would be willing to distribute it to the community myself for those of us who need this support.

This comment has been minimized.

The gccgo frontend doesn't care at all about ABIs. It is most likely that this is a problem with the GCC backend. If so, it presumably also happens with C code. I recommend that you try a C program. If that fails, then open a bug report on the GCC bug tracker at https://gcc.gnu.org/bugzilla and close this one. If it really is gccgo-specific, add a comment here. Thanks.

This comment has been minimized.

gcc works fine and emits ELFv2 code. go crashes and segfaults. It works correctly on every other musl platform, except PPC64. When I investigated it, I noticed it was jumping to what looked like an ELFv1 function descriptor. Whether this was generated dynamically by the Go runtime, or there is some issue with assembly/linking during build, I cannot fully determine.

This comment has been minimized.

In the sense that I meant it, the program runs, it just crashes. This is not a pedantic objection. It strongly suggests that the problem is not the --with-abi configure option, but rather some bad interaction between the MUSL library and libgo.

This comment has been minimized.

The issue is that musl uses SIG34 internally, the same way glibc uses SIG32 and SIG33. Adding " || i == 34" to line 114 fixes this, and presents a different trace:

awilcox on gwyn [pts/11 Tue 12 14:48] ~: gcc8/bin/gccgo -g -o hello hello.go
awilcox on gwyn [pts/11 Tue 12 14:48] ~: LD_LIBRARY_PATH=gcc8/lib64 ./hello
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=1 addr=125464 pc=4532106540]
runtime stack:
main
../../../libgo/runtime/go-main.c:43
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
main
:0
goroutine 1 [running]:
fatal error: runtime: mcall function returned
panic during panic
goroutine 1 [running]:
runtime.dopanic
../../../libgo/go/runtime/panic.go:909
runtime.startpanic
../../../libgo/go/runtime/panic.go:869
runtime.throw
../../../libgo/go/runtime/panic.go:818
runtime.throw
../../../libgo/go/runtime/panic.go:812
runtime_throw
../../../libgo/runtime/panic.c:13
runtime.mcall
../../../libgo/runtime/proc.c:358
runtime.systemstack
../../../libgo/go/runtime/stubs.go:66
runtime.main
../../../libgo/go/runtime/proc.go:172

This comment has been minimized.

swapcontext is not a system call. It is implemented entirely by the C library. Perhaps there is some problem with the musl implementation, or at any rate some disagreement between its implementation and what libgo expects.

This comment has been minimized.

I will note that GCC Go works fine using SYS_swapcontext on 32-bit PowerPC; even on a 64-bit host, running the 32-bit code in compat mode works perfectly fine. This is why I am curious if there is a subtle issue in the 64-bit syscall.

This comment has been minimized.

Thanks, that is interesting. I was not aware that swapcontext is a system call for 32-bit PPC. It looks like on 64-bit PPC glibc does it in user space, but on 32-bit it does a system call. I wonder why.

Does strace -f show any interesting difference between the swapcontext call when using glibc or when using musl?

This comment has been minimized.

I don't actually know of any current 32-bit PPC distributions that use glibc. I can install Debian Jessie or Gentoo on to my Power G4 (32-bit PPC workstation), but with my current work schedule that would probably not be doable for a few days.

64-bit glibc does, indeed, use user-space code instead of a system call. For that reason, swapcontext is not in the output of strace of a GCC Go-generated binary compiled against glibc.

This comment has been minimized.

edited

It is indeed related to the kernel ucontext syscalls. When using user-mode ucontext syscalls, GCC Go seems to work perfectly fine on 64-bit PowerPC.

I've found a few errors in GCC 8 Go that prevent compilation on PowerPC (32 and 64) during this; how does one file merge requests for GCC Go? Do I submit them on GCC Bugzilla, or is there a way to do it here? Thank you.

This comment has been minimized.

I'm sorry but I am not very familiar with how gccgo was set up to work with the runtime. I think your problem is because you are using musl and not glibc. I understand that gccgo needs to use header files when calling glibc functions but I don't know how those header files compare when using musl. If it works on Linux with glibc but not on musl then it seems that's where the problem must be?

The syscall definition in go/runtime/stubs.go is invalid; it declares syscall as taking exactly six parameters. The call is variadic and therefore has different ABI properties. This causes the syscall itself to overwrite the stack guard and cause this crash. Defining syscall as taking eight parameters (which "accidentally" causes it to have the same ABI properties as a variadic call) will make the futex call stop crashing (but raises segfaults in other components of the runtime).

This is, unfortunately, necessary. Right now Go is breaking the PowerPC ABI with its definition of syscall. I am very inexperienced with programming in Go, but reading the documentation on unsafe it appears that changing the signature of futex so ts is uintptr, and casting as uintptr(unsafe.Pointer(&ts)) may be the correct solution.

This comment has been minimized.

golang/gofrontend@f3fb9bf is the reason GCC 6.4.0 Go works and GCC 8.3.0 Go does not. Before this change, runtime.futex was implemented in C.

We definitely want to work with you to upstream a fix for this issue. However, it may be possible to attempt to revert this commit in our GCC package if you are not interested in supporting PPC64/musl.