Skip to content

cmd/link: internal link issue with outline atomics feature on arm64 #39466

@shawndx

Description

@shawndx

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

$ go version
tip

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/xiaji01/.cache/go-build"
GOENV="/home/xiaji01/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/xiaji01/.go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/xiaji01/.go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/xiaji01/util/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/xiaji01/util/go/pkg/tool/linux_arm64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build044102122=/tmp/go-build -gno-record-gcc-switches"

What did you do?

GCC-9.4 introduced the outline atomics support for arm64 and the feature was made default since GCC-10.1. Go's internal linking mode doesn't work well with the feature, here is what have been spotted so far and a sample case, further analysis is ongoing.

With GCC-10.1 and default CGO flags, or GCC-9.4+with an additional "-moutline-atomics" flag, the sample case runs into a link issue with '-linkmode=internal', internal linking tries to resolve undefined external references in libgcc.a, while the problematic variable __aarch64_have_lse_atomic and its init function don't get resolved.

$ go build -ldflags='-linkmode=internal'
libgcc(.text): unknown symbol __aarch64_have_lse_atomics

lse.c

int test_cas_atomic_int (int *ptr, int *expected, int desired)
{
  return __atomic_compare_exchange_n (ptr, expected, desired, 0, 0, 0);
}

mult.c

#include <stdlib.h>
#include <stdio.h>

extern int test_cas_atomic_int (int *ptr, int *expected, int desired);

int test_cgo(int a, int b) {
  int old = a;
  int new = b;

  printf("before: old = %d, new = %d\n", old, new);
  test_cas_atomic_int(&old, &old, new);
  printf("after: old = %d, new = %d\n", old, new);
  return new * old + old;
}

mult.go

package main

/*
extern int test_cgo(int a, int b);
*/
import "C"
import (
 "fmt"
)

func main() {
 a := 3
 b := 5
 c := C.test_cgo(C.int(a), C.int(b))
 fmt.Println("test_cgo:", int(c))
}

What did you expect to see?

Trying to apply GCC-10 and its new LSE features to CGO part, expect they work smoothly.

What did you see instead?

Internal linking doesn't work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions