Skip to content

cmd/compile: -buildmode=c-archive produces code not suitable for use in a shared object on arm64 #62556

@nmeum

Description

@nmeum

tl;dr On aarch64, Go 1.21 seems to emit code that is not suitable for use in a C/C++ shared library with -buildmode=c-archive on aarch64. I believe this to be a Go 1.21 regression as this was explicitly mentioned as a supported feature in commit d92a360. The root cause seems to be a R_AARCH64_ADR_PREL_PG_HI21 relocation for the crosscall2 symbol.

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

$ go version
go version go1.21.1 linux/arm64

Does this issue reproduce with the latest release?

Yes.

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

go env Output
$ go env
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/home/soeren/.cache/go-build'
GOENV='/home/soeren/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS='-buildmode=pie -modcacherw -trimpath -buildvcs=false'
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/soeren/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/soeren/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_arm64'
GOVCS=''
GOVERSION='go1.21.1'
GCCGO='gccgo'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2174769471=/tmp/go-build -gno-record-gcc-switches

What did you do?

I maintain the Go package for Alpine Linux (which uses musl libc) with the release of Go 1.21.1 we rebuild all of our packaged Go software for the CVE fixes in the standard library. While doing so, we noticed that the package fcitx5-bamboo failed to build from source on aarch64 (on all other architecture it build fine). The error message was:

/usr/lib/gcc/aarch64-alpine-linux-musl/13.1.1/../../../../aarch64-alpine-linux-musl/bin/ld: bamboo/bamboo-core.a(go.o): relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol `crosscall2' which may bind externally can not be used when making a shared object; recompile with -fPIC
bamboo/bamboo-core.a(go.o): in function `runtime/cgo.set_crosscall2.abi0':
go.go:(.text+0x8f228): dangerous relocation: unsupported relocation
collect2: error: ld returned 1 exit status
ninja: subcommand failed

The package previously compiled fine with Go 1.20.6 on aarch64.

Closer investigation revealed that the fcitx5-bamboo build system does the following:

  1. It compiles a few Go source files to a C archive (bamboo-core.a) using go -buildmode=c-archive.
  2. It compiles some C++ code and links it together with the c-archive, emitted by the Go compiler in the previous step, to a shared library using g++ -shared.

Naturally, the error message above is emitted by g++ not by the Go compiler. However, as per a prior discussion on golang-dev and commit d92a360, I believe that files produced by go build -buildmode=c-archive are supposed to be suitable for use in a shared library which the file emitted here (bamboo-core.a) is not. If my assumption is correct, then I believe this to be a regression introduced in Go 1.21, i.e. a bug in the Go compiler. The issue in this regard seems to be a R_AARCH64_ADR_PREL_PG_HI21 relocation emitted for crosscall2:

$ readelf -W -a bamboo/bamboo-core.a | grep ' crosscall2' | grep R_AARCH64_ADR_PREL_PG_HI21
000000000008f228  00000c0000000113 R_AARCH64_ADR_PREL_PG_HI21 000000000008f240 crosscall2 + 0

I am not familiar enough with aarch64 internals and relocations in general in order to determine why this code requires a R_AARCH64_ADR_PREL_PG_HI21 relocation and why this relocation is not suitable for use in a shared library.

To reproduce this run the following commands on aarch64:

$ git clone https://github.com/fcitx/fcitx5-bamboo
$ cd fcitx5-bamboo
$ git checkout 56cd63fac51a1da334903b06875d71a6ce0971de
$ git submodule update --init
$ cd bamboo/
$ go build -o bamboo-core.a -buildmode=c-archive *.go
$ readelf -W -a bamboo-core.a | grep ' crosscall2' | grep R_AARCH64_ADR_PREL_PG_HI21
000000000008f228  00000c0000000113 R_AARCH64_ADR_PREL_PG_HI21 000000000008f240 crosscall2 + 0

This should print the R_AARCH64_ADR_PREL_PG_HI21 relocation, or at least it does on Alpine Linux Edge aarch64. Again, I am not sure why this relocation is not suitable for use in a shared library. If you want to re-produce the g++ error message follow the upstream build instructions. Unfortunately, I did not manage to come up with a minimal example yet.

Full build log for our failing aarch64 Alpine Linux Edge build: fcitx5-bamboo-go-1.21.1-alpine-linux-edge-aarch64.txt

What did you expect to see?

Successful linking of the c-archive emitted by go build -buildmode=c-archive to a shared library with g++ -shared.

What did you see instead?

The g++ error message regarding a R_AARCH64_ADR_PREL_PG_HI21 relocation.

Metadata

Metadata

Assignees

Labels

FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.arch-arm64compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions