1

I'm trying to build a Go executable with shared libraries. In Ubuntu, which uses GNU libc, it works. But when I try to use the same procedure on Alpine (Docker image golang:alpine, or 1.14.1-alpine3.11), which uses MUSL libc, the generated libstd.so is broken. Afterwards, if I try to compile the executable, the compilation fails.

This is the procedure:

$ docker run -it golang:alpine sh
/go # apk add --update alpine-sdk
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
(1/38) Installing fakeroot (1.24-r0)
(2/38) Installing sudo (1.8.31-r0)
(3/38) Installing libcap (2.27-r0)
(4/38) Installing pax-utils (1.2.4-r0)
(5/38) Installing openssl (1.1.1d-r3)
(6/38) Installing libattr (2.4.48-r0)
(7/38) Installing attr (2.4.48-r0)
(8/38) Installing libacl (2.2.53-r0)
(9/38) Installing tar (1.32-r1)
(10/38) Installing pkgconf (1.6.3-r0)
(11/38) Installing patch (2.7.6-r6)
(12/38) Installing libgcc (9.2.0-r4)
(13/38) Installing libstdc++ (9.2.0-r4)
(14/38) Installing lzip (1.21-r0)
(15/38) Installing nghttp2-libs (1.40.0-r0)
(16/38) Installing libcurl (7.67.0-r0)
(17/38) Installing curl (7.67.0-r0)
(18/38) Installing abuild (3.5.0-r0)
Executing abuild-3.5.0-r0.pre-install
(19/38) Installing binutils (2.33.1-r0)
(20/38) Installing libmagic (5.37-r1)
(21/38) Installing file (5.37-r1)
(22/38) Installing gmp (6.1.2-r1)
(23/38) Installing isl (0.18-r0)
(24/38) Installing libgomp (9.2.0-r4)
(25/38) Installing libatomic (9.2.0-r4)
(26/38) Installing mpfr4 (4.0.2-r1)
(27/38) Installing mpc1 (1.1.0-r1)
(28/38) Installing gcc (9.2.0-r4)
(29/38) Installing musl-dev (1.1.24-r2)
(30/38) Installing libc-dev (0.7.2-r0)
(31/38) Installing g++ (9.2.0-r4)
(32/38) Installing make (4.2.1-r2)
(33/38) Installing fortify-headers (1.1-r0)
(34/38) Installing build-base (0.5-r1)
(35/38) Installing expat (2.2.9-r1)
(36/38) Installing pcre2 (10.34-r1)
(37/38) Installing git (2.24.1-r0)
(38/38) Installing alpine-sdk (1.0-r0)
Executing busybox-1.31.1-r9.trigger
OK: 196 MiB in 53 packages
/go # go install -a -buildmode=shared -linkshared std
/go # ldd /usr/local/go/pkg/linux_amd64_dynlink/libstd.so 
    /lib/ld-musl-x86_64.so.1 (0x7f689af41000)
    libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f689af41000)
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_malloc: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_realloc: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_free: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: main.main: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_stack_end: symbol not found
/go # go version
go version go1.14.1 linux/amd64
/go # go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
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 -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build202809585=/tmp/go-build -gno-record-gcc-switches"
/go # 

It works as expected when I do the same procedure with the same Golang version, but other distribution that has GNU libc:

$ docker run -it golang:buster sh
# go install -a -buildmode=shared -linkshared std
# ldd /usr/local/go/pkg/linux_amd64_dynlink/libstd.so
    linux-vdso.so.1 (0x00007ffe54bea000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f12f79a3000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f12f7982000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f12f77c1000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f12fa0d2000)
# go version
go version go1.14.1 linux/amd64
# go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
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 -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build609530787=/tmp/go-build -gno-record-gcc-switches"
# 

Am I missing some detail? Does Golang or Alpine have a bug?

4

1 回答 1

1

似乎 Go 运行时有一些明确的 GNU libc 依赖项,如链接错误所示:

Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_malloc: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_realloc: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_free: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: main.main: symbol not found
Error relocating /usr/local/go/pkg/linux_amd64_dynlink/libstd.so: __libc_stack_end: symbol not found

在这种情况下,轻量级 glibc 兼容性(安装libc6-compat软件包)可能不会,因为它主要添加存根,并且仍然缺少一些 glibc 功能。

试图找到有问题的 Go 模块,在 Go 构建缓存中选择go install -a -buildmode=shared -linkshared std(在 下的目标文件.cache/go-build,使用 寻找 glibc 依赖grep -R libc项),一个大的目标文件脱颖而出。列出对象符号并nm显示它是消耗所需符号的符号:

        U __libc_free
        U __libc_malloc
        U __libc_realloc
        U __libc_stack_end

那个对象原来是race.go

谷歌搜索显示 Alpine libc 兼容性确实是一个已知的种族问题,记录在这里:
https ://github.com/golang/go/issues/14481

幸运的是,该票提到了几个建议的解决方法,例如从源代码构建 compiler-rt。

于 2020-04-02T18:53:02.913 回答