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

cmd/cgo, cmd/link: with zig as CC/CXX, Go linker does not put libc onto the linker line, causing undefined symbol errors #52690

Open
andrewrk opened this issue May 3, 2022 · 23 comments · May be fixed by #52815
Labels
help wanted NeedsFix
Milestone

Comments

@andrewrk
Copy link

@andrewrk andrewrk commented May 3, 2022

Corresponding Zig issue: ziglang/zig#11398

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

$ go version
go version go1.18.1 linux/amd64

Does this issue reproduce with the latest release?

I only tested with go1.18.1.

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/andy/.cache/go-build"
GOENV="/home/andy/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/andy/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/andy/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/nix/store/qyc0w8vsikzmbdy97gb68l2ri1jzqp9v-go-1.18.1/share/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/nix/store/qyc0w8vsikzmbdy97gb68l2ri1jzqp9v-go-1.18.1/share/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.18.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
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=/run/user/1000/go-build3829224601=/tmp/go-build -gno-record-gcc-switches"

What did you do?

go.mod:

module test

go 1.18

foo.go:

package test

func foo() {}

foo_test.go:

package test

import (
	"testing"
)

func TestFoo(t *testing.T) {
	foo()
}

Then use zig cc as the C toolchain for go test with race detection:

CGO_ENABLED=1 CC="zig cc" go test -race test

Zig Version 0.10.0-dev.2052+3cfde183f

What did you expect to see?

This should work, as it does without -race.

What did you see instead?

We get errors from the Go linker:

# test.test
runtime/race(.text): relocation target getuid not defined
runtime/race(.text): relocation target pthread_self not defined
runtime/race(.text): relocation target sleep not defined
runtime/race(.text): relocation target usleep not defined
runtime/race(.text): relocation target abort not defined
runtime/race(.text): relocation target isatty not defined
runtime/race(.text): relocation target pthread_attr_getstack not defined
runtime/race(.text): relocation target sigaction not defined
runtime/race(.text): relocation target getrusage not defined
runtime/race(.text): relocation target syslog not defined
runtime/race(.text): relocation target confstr not defined
runtime/race(.text): relocation target getrlimit not defined
runtime/race(.text): relocation target pipe not defined
runtime/race(.text): relocation target sched_getaffinity not defined
runtime/race(.text): relocation target __sched_cpucount not defined
runtime/race(.text): relocation target pthread_attr_init not defined
runtime/race(.text): relocation target pthread_getattr_np not defined
runtime/race(.text): relocation target pthread_attr_destroy not defined
runtime/race(.text): relocation target exit not defined
runtime/race(.text): relocation target sysconf not defined
runtime/race(.text): relocation target setrlimit not defined
/home/kmicklas/go/pkg/tool/linux_amd64/link: too many errors
FAIL	test [build failed]
FAIL

Notes

Related issue: #44695

It appears that cgo has asked the C compiler to compile C source files which contain dependencies on libc symbols, however the Go linker is not actually putting libc onto the linker line, causing these undefined symbol errors.

It does compile and run successfully using -linkmode external, however, I don't see why it shouldn't work with the Go linker as well, given that zig cc produces standard ELF object files (same as Clang and GCC).

It looks to me like the fix is simple: the Go linker needs to put libc onto the linker line when it is linking objects that contain libc dependencies.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 3, 2022

With compilers like GCC and clang, the compiler links against the C library by default. Does zig cc not work that way? What happens if I write zig cc -o hello hello.o?

@andrewrk
Copy link
Author

@andrewrk andrewrk commented May 3, 2022

zig cc does work this way. In your example code, zig cc is being used as the linker, and in fact as noted above, with -linkmode external this issue is not present because zig cc is being used as the linker. However, the issue occurs because Go is using Go as the linker and not putting libc on the linker line.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 3, 2022

Thanks. The Go linker never links directly against the C library. This normally works because the Go build decides that getuid and friends come from the libc.so shared C library. Does zig cc link statically by default?

@andrewrk
Copy link
Author

@andrewrk andrewrk commented May 3, 2022

zig cc follows the same static/dynamic linking rules as clang and gcc; it shares the exact same command line API. On glibc-based systems, GCC, Clang, and zig cc all link dynamically against libc.so by default:

andy@ark ~/tmp> gcc -o hello hello.c
andy@ark ~/tmp> ldd hello
	linux-vdso.so.1 (0x00007ffc9f3df000)
	libc.so.6 => /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib/libc.so.6 (0x00007f13b9dec000)
	/nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib/ld-linux-x86-64.so.2 => /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib64/ld-linux-x86-64.so.2 (0x00007f13b9fc3000)
andy@ark ~/tmp> clang -o hello hello.c
andy@ark ~/tmp> ldd hello
	linux-vdso.so.1 (0x00007ffd177ab000)
	libc.so.6 => /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib/libc.so.6 (0x00007fc1ef774000)
	/nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib/ld-linux-x86-64.so.2 => /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib64/ld-linux-x86-64.so.2 (0x00007fc1ef94b000)
andy@ark ~/tmp> zig cc -o hello hello.c
andy@ark ~/tmp> ldd hello
	linux-vdso.so.1 (0x00007fff1d5f7000)
	libc.so.6 => /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib/libc.so.6 (0x00007ff3ec3ae000)
	/nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib/ld-linux-x86-64.so.2 => /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123/lib64/ld-linux-x86-64.so.2 (0x00007ff3ec585000)

A typical linker line for any C compiler will look something like this:

ld -m elf_x86_64 -o hello Scrt1.o crti.o hello.o libcompiler_rt.a libm.so.6 libpthread.so.0 libc.so.6 libdl.so.2 librt.so.1 libld.so.2 libutil.so.1 libc_nonshared.a crtn.o

In this example, hello.o contains libc dependencies, but it is the linker which satisfies them by putting libc on the linker line, as you can see.

I'm not sure what you mean when you say the Go linker never links directly against the C library. Indeed, getuid and friends come from the libc.so shared C library, as you can see above, but in this issue, the Go linker is omitting libc.so from the list of objects to link, causing the undefined symbol errors.

We can simulate this same problem with any C compiler by passing -nostdlib, causing the linker driver to omit libc.so from the linker line, as Go is doing:

andy@ark ~/tmp> clang -o hello hello.c -nostdlib
/nix/store/b987cpz6k72fkp05ycbhvk635y46m3cc-binutils-2.35.2/bin/ld: /tmp/hello-d74816.o: in function `main':
hello.c:(.text+0x15): undefined reference to `printf'
clang-7: error: linker command failed with exit code 1 (use -v to see invocation)

Ultimately, the Go toolchain is compiling C source files into object files which contain libc dependencies. If any C compiler is used to then link these together, everything works fine, because C compilers put libc onto the linker line. However, when the Go linker is used, which is the default, it does not satisfy its own dependencies.

I think one thing that would shed some light on this issue would be seeing, side by side, the Go linker line when CC=clang is used vs CC="zig cc". I spent a couple hours trying to obtain this information but did not figure out how to do it.

@zikaeroh
Copy link
Contributor

@zikaeroh zikaeroh commented May 3, 2022

I think what you're looking for is -ldflags="-linkmode=external -v", which prints a "host link" log line with arguments for me. If you also pass -x to go build, you'll also get all of the commands that go ran to build (including the flags passed to cmd/link), if you want to see even more of the process.

(I'm pretty sure this is the same as #44695, but whichever gets the most traction works for me 😄)

@zikaeroh
Copy link
Contributor

@zikaeroh zikaeroh commented May 3, 2022

With gcc as the linker:

# some.tld/go44695
HEADER = -H5 -T0x401000 -R0x1000
host link: "gcc" "-m64" "-o" "/tmp/go-build298697425/b001/exe/a.out" "-rdynamic" "-Wl,--compress-debug-sections=zlib-gnu" "/tmp/go-link-1343527236/go.o" "/tmp/go-link-1343527236/000000.o" "/tmp/go-link-1343527236/000001.o" "/tmp/go-link-1343527236/000002.o" "/tmp/go-link-1343527236/000003.o" "/tmp/go-link-1343527236/000004.o" "/tmp/go-link-1343527236/000005.o" "/tmp/go-link-1343527236/000006.o" "/tmp/go-link-1343527236/000007.o" "/tmp/go-link-1343527236/000008.o" "/tmp/go-link-1343527236/000009.o" "/tmp/go-link-1343527236/000010.o" "/tmp/go-link-1343527236/000011.o" "/tmp/go-link-1343527236/000012.o" "/tmp/go-link-1343527236/000013.o" "/tmp/go-link-1343527236/000014.o" "/tmp/go-link-1343527236/000015.o" "/tmp/go-link-1343527236/000016.o" "/tmp/go-link-1343527236/000017.o" "-g" "-O2" "-g" "-O2" "-lpthread" "-no-pie"
174990 symbols, 42726 reachable
	67777 package symbols, 70621 hashed symbols, 29608 non-package symbols, 6984 external symbols
139482 liveness data

clang as the linker:

# some.tld/go44695
HEADER = -H5 -T0x401000 -R0x1000
host link: "clang" "-m64" "-o" "/tmp/go-build328077678/b001/exe/a.out" "-rdynamic" "-Qunused-arguments" "-Wl,--compress-debug-sections=zlib-gnu" "/tmp/go-link-2078635705/go.o" "/tmp/go-link-2078635705/000000.o" "/tmp/go-link-2078635705/000001.o" "/tmp/go-link-2078635705/000002.o" "/tmp/go-link-2078635705/000003.o" "/tmp/go-link-2078635705/000004.o" "/tmp/go-link-2078635705/000005.o" "/tmp/go-link-2078635705/000006.o" "/tmp/go-link-2078635705/000007.o" "/tmp/go-link-2078635705/000008.o" "/tmp/go-link-2078635705/000009.o" "/tmp/go-link-2078635705/000010.o" "/tmp/go-link-2078635705/000011.o" "/tmp/go-link-2078635705/000012.o" "/tmp/go-link-2078635705/000013.o" "/tmp/go-link-2078635705/000014.o" "/tmp/go-link-2078635705/000015.o" "/tmp/go-link-2078635705/000016.o" "/tmp/go-link-2078635705/000017.o" "-g" "-O2" "-g" "-O2" "-lpthread" "-no-pie"
174990 symbols, 42726 reachable
	67777 package symbols, 70621 hashed symbols, 29608 non-package symbols, 6984 external symbols
139482 liveness data

zig cc as the linker:

# some.tld/go44695
HEADER = -H5 -T0x401000 -R0x1000
host link: "zig" "cc" "-m64" "-o" "/tmp/go-build1740275156/b001/exe/a.out" "-rdynamic" "/tmp/go-link-2842320631/go.o" "/tmp/go-link-2842320631/000000.o" "/tmp/go-link-2842320631/000001.o" "/tmp/go-link-2842320631/000002.o" "/tmp/go-link-2842320631/000003.o" "/tmp/go-link-2842320631/000004.o" "/tmp/go-link-2842320631/000005.o" "/tmp/go-link-2842320631/000006.o" "/tmp/go-link-2842320631/000007.o" "/tmp/go-link-2842320631/000008.o" "/tmp/go-link-2842320631/000009.o" "/tmp/go-link-2842320631/000010.o" "/tmp/go-link-2842320631/000011.o" "/tmp/go-link-2842320631/000012.o" "/tmp/go-link-2842320631/000013.o" "/tmp/go-link-2842320631/000014.o" "/tmp/go-link-2842320631/000015.o" "/tmp/go-link-2842320631/000016.o" "/tmp/go-link-2842320631/000017.o" "-g" "-O2" "-g" "-O2" "-lpthread"
174943 symbols, 42726 reachable
	67777 package symbols, 70621 hashed symbols, 29608 non-package symbols, 6937 external symbols
139482 liveness data

The flags are nearly identical, and none mention libc in any way.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 3, 2022

I'm not sure what you mean when you say the Go linker never links directly against the C library.

I mean literally that. The Go linker never opens the C library.

Indeed, getuid and friends come from the libc.so shared C library, as you can see above, but in this issue, the Go linker is omitting libc.so from the list of objects to link, causing the undefined symbol errors.

In the GCC case, the cgo tool is run against runtime/cgo and runtime/race. This happens when building those packages, not at link time. Among other things, cgo runs a C link to produce a temporary executable. It examines that executable for references to symbols defined in shared libraries. It passes a list of those symbols and the corresponding shared libraries to the Go linker. The Go linker uses that to build a dynamic symbol table that tells the dynamic linker (ld.so) how to satisfy those symbol references.

Somehow that is failing when using zig cc but I don't know how.

@motiejus
Copy link

@motiejus motiejus commented May 4, 2022

Data point: the _cgo_.o intermediate object files are very different across clang-13 and zig cc.

I am comparing workdirs of CC="zig cc" vs CC="clang-13" with this script:

#!/bin/bash
set -xeuo pipefail

_collect() {
    local slug="${CC/ /-}"
    local workdir="work-${slug}"
    local logfile="${slug}.log"
    rm -fr ~/.cache/go-build "$workdir"
    env CGO_ENABLED=1 CC="$CC" \
        GOMAXPROCS=1 \
        go test -ldflags="-v" -work -x -race test >& "$logfile" || :

    # contains line WORK=...
    . <(head -1 "$logfile")
    mv "$WORK" "$workdir"
}

CC="zig cc" _collect
CC="clang-13" _collect

This is how go builds the object for runtime/cgo, to $WORK/b079/_cgo_.o

TERM='dumb' zig cc -I /usr/local/go/src/runtime/race -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=$WORK/b079=/tmp/go-build -gno-record-gcc-switches -o $WORK/b079/_cgo_.o $WORK/b079/_cgo_main.o $WORK/b079/_x001.o $WORK/b079/_x002.o /usr/local/go/src/runtime/race/race_linux_amd64.syso -g -O2

(ditto for clang-13)

TERM='dumb' clang-13 -I /usr/local/go/src/runtime/race -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=$WORK/b079=/tmp/go-build -gno-record-gcc-switches -o $WORK/b079/_cgo_.o $WORK/b079/_cgo_main.o $WORK/b079/_x001.o $WORK/b079/_x002.o /usr/local/go/src/runtime/race/race_linux_amd64.syso -g -O2

Result: the zig-cc one is very small, and contains just a couple of symbols, and no references to libc ones:

motiejus ~/x/race $ nm work-zig-cc/b079/_cgo_.o
00000000002014d0 T _cgo_allocate
00000000002014e0 T _cgo_panic
00000000002014f0 T _cgo_reginit
00000000002014b0 T _cgo_release_context
00000000002014c0 T _cgo_topofstack
00000000002014a0 T _cgo_wait_runtime_init_done
0000000000201490 T crosscall2
00000000002025a8 d _DYNAMIC
000000000020159c t _fini
00000000002036c8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000201584 t _init
0000000000201450 t __init_array_end
0000000000201450 t __init_array_start
0000000000201580 T __libc_csu_fini
0000000000201500 T __libc_csu_init
                 U __libc_start_main
0000000000201480 T main
0000000000201450 T _start

The clang-13 is much bigger, and contains references to libc:

motiejus ~/x/race $ nm work-clang-13/b079/_cgo_.o | wc -l
910
motiejus ~/x/race $ nm work-clang-13/b079/_cgo_.o | grep GLIBC
                 U abort@GLIBC_2.2.5
                 U confstr@GLIBC_2.2.5
                 U dl_iterate_phdr@GLIBC_2.2.5
                 U __errno_location@GLIBC_2.2.5
                 U exit@GLIBC_2.2.5
                 U getrlimit@GLIBC_2.2.5
                 U getrusage@GLIBC_2.2.5
                 U getuid@GLIBC_2.2.5
                 U isatty@GLIBC_2.2.5
                 U __libc_start_main@GLIBC_2.2.5
                 U pipe@GLIBC_2.2.5
                 U pthread_attr_destroy@GLIBC_2.2.5
                 U pthread_attr_getstack@GLIBC_2.2.5
                 U pthread_attr_init@GLIBC_2.2.5
                 U pthread_getattr_np@GLIBC_2.2.5
                 U pthread_self@GLIBC_2.2.5
                 U __sched_cpucount@GLIBC_2.6
                 U sched_getaffinity@GLIBC_2.3.4
                 U sched_yield@GLIBC_2.2.5
                 U setrlimit@GLIBC_2.2.5
                 U sigaction@GLIBC_2.2.5
                 U sleep@GLIBC_2.2.5
                 U sysconf@GLIBC_2.2.5
                 U syslog@GLIBC_2.2.5
                 U usleep@GLIBC_2.2.5

Digging ...

@andrewrk
Copy link
Author

@andrewrk andrewrk commented May 4, 2022

Thanks for the clues everyone.

cgo runs a C link to produce a temporary executable. It examines that executable for references to symbols defined in shared libraries. It passes a list of those symbols and the corresponding shared libraries to the Go linker. The Go linker uses that to build a dynamic symbol table that tells the dynamic linker (ld.so) how to satisfy those symbol references.

Aha, I think we have almost gotten to the bottom of this. This strategy means that the temporary executable needs to be exemplary in terms of linking to libc. If, for instance, the temporary executable happened to have advanced linker optimizations enabled, garbage collecting unused libc dependencies, then Go's strategy of using it as an example of how to link to libc would not work.

In order to avoid this situation, Go would need to make sure this temporary executable had libc function calls to all the needed symbols.

One way to test this hypothesis would be with the following patch to Zig:

--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1691,9 +1691,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
                 argv.appendAssumeCapacity(arg);
             }
 
-            if (!as_needed) {
-                argv.appendAssumeCapacity("--as-needed");
-                as_needed = true;
+            if (as_needed) {
+                argv.appendAssumeCapacity("--no-as-needed");
+                as_needed = false;
             }
 
             // libc++ dep

However, I want to stress that using --as-needed for libc symbols is a perfectly legal optimization for Zig to make, and a proper solution would mean Go including actual symbol dependencies on the libc functions that are needed when creating the temporary executable. In other words the C source code for the temporary executable needs to have dummy calls to getuid, pthread_self, sleep, and every other libc function that cgo/race code wants to call.

@motiejus
Copy link

@motiejus motiejus commented May 4, 2022

The patch doesn't help: the linker flag gets added, but the resulting intermediate _cgo_.o still lacks the glibc symbols.

I've extracted the zig cc command, added -v, purged zig cache. Here is the resulting zig cc -v output of combining that file:

motiejus ~/x/race $ TERM='dumb' /home/motiejus/code/zig/build/zig cc -v -I /usr/local/go/src/runtime/race -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=$WORK/b079=/tmp/go-build -gno-record-gcc-switches -o $WORK/b079/_cgo_.o $WORK/b079/_cgo_main.o $WORK/b079/_x001.o
 $WORK/b079/_x002.o /usr/local/go/src/runtime/race/race_linux_amd64.syso -g -O2
ld.lld -r -error-limit=0 -O3 -s -m elf_x86_64 -static -o /home/motiejus/.cache/zig/o/91b96c8f38a568cc8b1b3e8332fe1b2a/crti.o /home/motiejus/.cache/zig/o/58045fff5ef1b611af2c16ef4e58f359/crti.o
ld.lld -r -error-limit=0 -O3 -s -m elf_x86_64 -static -o /home/motiejus/.cache/zig/o/2b6be64219df30475dcacb8367694020/crtn.o /home/motiejus/.cache/zig/o/870e26b625ee1c9772895a1fddf09d67/crtn.o
ld.lld -r -error-limit=0 -O3 -s -m elf_x86_64 -static -o /home/motiejus/.cache/zig/o/fd5a6c8e022865ea653050e7d424be3c/Scrt1.o /home/motiejus/.cache/zig/o/57fe1256d14eae680970384f17905956/start-2.33.o /home/motiejus/.cache/zig/o/8c85e058308f477ec91b8985d8f4c424/abi-note.o
ar rcs /home/motiejus/.cache/zig/o/80c22cbf6b3eaf4d8a98165e54c56362/libc_nonshared.a /home/motiejus/.cache/zig/o/6da1183bf34802781be50f033c0dc8fb/atexit.o /home/motiejus/.cache/zig/o/14366b018930963137551512b6ff7f9b/at_quick_exit.o /home/motiejus/.cache/zig/o/0435e34094e802b6b9094600fb40a8d4/pthread_atfork.o /home/motiejus/.cache/zig/o/a938a0cc359416b5242ccf11dbf4e8b7/stack_chk_fail_local.o /home/motiejus/.cache/zig/o/05e0c9400de4e9b9a2fd9cad643eaf46/errno.o /home/motiejus/.cache/zig/o/3f3b2fa88360c6f2709304ed414a1e64/elf-init-2.33.o /home/motiejus/.cache/zig/o/9073bc2189d97a928cec22d11aa1c2ec/stat.o /home/motiejus/.cache/zig/o/243b9ef98c561938c663e48cb9fe37e6/fstat.o /home/motiejus/.cache/zig/o/c62b463acc22fc8f3f9a6aebedc1a4cf/lstat.o /home/motiejus/.cache/zig/o/9ed7e253d0c0850dfc125b598ae93543/stat64.o /home/motiejus/.cache/zig/o/b1a9086ecf04276c9d0ed9b4164e89f3/fstat64.o /home/motiejus/.cache/zig/o/3ce5f80df2ed924c693130bf03643317/lstat64.o /home/motiejus/.cache/zig/o/c2b6fbcf844186e09efce31992786903/fstatat.o /home/motiejus/.cache/zig/o/17bcf947c9f2a5fabd7aebbceab88732/fstatat64.o /home/motiejus/.cache/zig/o/97412572c8facabb00517c70006680fb/mknodat.o /home/motiejus/.cache/zig/o/5eead55743586901ad12776a208ab1c2/mknod.o /home/motiejus/.cache/zig/o/ed013cfd3317240de811014a8bfaee60/stat_t64_cp.o
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libm.so.6 -soname libm.so.6 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/314cdab16cda146564952d0189798c1f/m.o --as-needed --no-as-needed --allow-shlib-undefined
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libpthread.so.0 -soname libpthread.so.0 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/f2c227c87fe510e09281643a20d61673/pthread.o --as-needed --no-as-needed --allow-shlib-undefined
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libc.so.6 -soname libc.so.6 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/0d9f96c191fd716d028af63e0afbafa8/c.o --as-needed --no-as-needed --allow-shlib-undefined
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libdl.so.2 -soname libdl.so.2 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/a0a3c156409f43b4977c043cf49b555d/dl.o --as-needed --no-as-needed --allow-shlib-undefined
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/librt.so.1 -soname librt.so.1 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/6248fb0c9383e8ffeb5e393255e6990d/rt.o --as-needed --no-as-needed --allow-shlib-undefined
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libld.so.2 -soname ld-linux-x86-64.so.2 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/7e0596190876301e19191e76f01ae3a3/ld.o --as-needed --no-as-needed --allow-shlib-undefined
ld.lld -error-limit=0 -O3 --gc-sections -s -m elf_x86_64 -shared -o /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libutil.so.1 -soname libutil.so.1 -version-script /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/all.map /home/motiejus/.cache/zig/o/77380b63a792d807811009994ee4fadf/util.o --as-needed --no-as-needed --allow-shlib-undefined
ar rcs /home/motiejus/.cache/zig/o/cff27c0f8922543f0abbb2040c54353e/libcompiler_rt.a /home/motiejus/.cache/zig/o/cff27c0f8922543f0abbb2040c54353e/compiler_rt.o
ld.lld -error-limit=0 -O3 -z stack-size=16777216 --gc-sections --eh-frame-hdr -m elf_x86_64 -o /home/motiejus/.cache/zig/o/b4138bfd013b47c91024e05b06a68ea5/_cgo_.o /home/motiejus/.cache/zig/o/fd5a6c8e022865ea653050e7d424be3c/Scrt1.o /home/motiejus/.cache/zig/o/91b96c8f38a568cc8b1b3e8332fe1b2a/crti.o -L /usr/local/lib64 -L /usr/local/lib -L /usr/lib/x86_64-linux-gnu -L /lib64 -L /lib -L /usr/lib64 -L /usr/lib -L /lib/x86_64-linux-gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 /tmp/go-build2893123627/b079/_cgo_main.o /tmp/go-build2893123627/b079/_x001.o /tmp/go-build2893123627/b079/_x002.o /usr/local/go/src/runtime/race/race_linux_amd64.syso /home/motiejus/.cache/zig/o/cff27c0f8922543f0abbb2040c54353e/libcompiler_rt.a --as-needed --no-as-needed /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libm.so.6 /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libpthread.so.0 /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libc.so.6 /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libdl.so.2 /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/librt.so.1 /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libld.so.2 /home/motiejus/.cache/zig/o/3a1193ad8830067188265e81a8a1b846/libutil.so.1 /home/motiejus/.cache/zig/o/80c22cbf6b3eaf4d8a98165e54c56362/libc_nonshared.a /home/motiejus/.cache/zig/o/2b6be64219df30475dcacb8367694020/crtn.o

Verbose clang-13 linker:

motiejus ~/x/race $ TERM='dumb' clang-13 -v -I /usr/local/go/src/runtime/race -fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=$WORK/b079=/tmp/go-build -gno-record-gcc-switches -o $WORK/b079/_cgo_.o $WORK/b079/_cgo_main.o $WORK/b079/_x001.o $WORK/b079/_x002.o /usr/local/go/src/runtime/race/race_linux_amd64.syso -g -O2
Debian clang version 13.0.1-++20220126092033+75e33f71c2da-1~exp1~20220126212112.63
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Candidate multilib: .;@m64
Selected multilib: .;@m64
 "/usr/bin/ld" --hash-style=both --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o /tmp/go-build3943283512/b079/_cgo_.o /lib/x86_64-linux-gnu/crt1.o /lib/x86_64-linux-gnu/crti.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtbegin.o -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/lib/llvm-13/bin/../lib -L/lib -L/usr/lib /tmp/go-build3943283512/b079/_cgo_main.o /tmp/go-build3943283512/b079/_x001.o /tmp/go-build3943283512/b079/_x002.o /usr/local/go/src/runtime/race/race_linux_amd64.syso -lgcc --as-needed -lgcc_s --no-as-needed -lpthread -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtend.o /lib/x86_64-linux-gnu/crtn.o

However, I want to stress that using --as-needed for libc symbols is a perfectly legal optimization for Zig to make,

I think it will be fair to talk more about this when we get to the bottom of the problem (and a workaround). :)

@motiejus
Copy link

@motiejus motiejus commented May 4, 2022

It's --gc-sections:

$ CGO_ENABLED=1 CC="zig cc -Wl,--no-gc-sections" go test  -race
testing
PASS
ok      test    0.018s

@motiejus
Copy link

@motiejus motiejus commented May 4, 2022

Adding --print-unused-sections to the linker line prints:

removing unused section /home/motiejus/.cache/zig/o/466e75650350030c221ee851caa5092f/Scrt1.o:(.data)                                                                                                                                                                                                                                                                                                                                                                                                                           
removing unused section /home/motiejus/.cache/zig/o/94127ccfce64f0a53722b58cfee94ed6/crti.o:(.text)                                                                                                                                                                                                                                                                                                                                                                                                                            
removing unused section /tmp/go-build565131511/b079/_x001.o:(.text)                                                                                                                                                                                                                                                            
removing unused section /tmp/go-build565131511/b079/_x002.o:(.text)                                                                                                                                                                                                                                                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text)                                                                                                                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data)                                                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.bss)                                                                                                                                                                                                                                            
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer10DDCallback6UnwindEv)                                                                                                                                                                                            
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer10DDCallback6UnwindEv)                                                                                                                                                                                                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer10DDCallback9UniqueTidEv)                                                                                                                                                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer10DDCallback9UniqueTidEv)                                                                                                                                                                                                                                                                                                                                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector20CreatePhysicalThreadEv)                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector20CreatePhysicalThreadEv)                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector21DestroyPhysicalThreadEPNS_16DDPhysicalThreadE)                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector21DestroyPhysicalThreadEPNS_16DDPhysicalThreadE)                                                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector19CreateLogicalThreadEy)                                                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector19CreateLogicalThreadEy)                                                                                                                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector20DestroyLogicalThreadEPNS_15DDLogicalThreadE)                                                                                                                                                                                                        
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector20DestroyLogicalThreadEPNS_15DDLogicalThreadE)                                                                                                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector9MutexInitEPNS_10DDCallbackEPNS_7DDMutexE)                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector9MutexInitEPNS_10DDCallbackEPNS_7DDMutexE)                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector15MutexBeforeLockEPNS_10DDCallbackEPNS_7DDMutexEb)                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector15MutexBeforeLockEPNS_10DDCallbackEPNS_7DDMutexEb)                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector14MutexAfterLockEPNS_10DDCallbackEPNS_7DDMutexEbb)                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector14MutexAfterLockEPNS_10DDCallbackEPNS_7DDMutexEbb)                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector17MutexBeforeUnlockEPNS_10DDCallbackEPNS_7DDMutexEb)                                                                                                                                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector17MutexBeforeUnlockEPNS_10DDCallbackEPNS_7DDMutexEb)                                                                                                                                                                                                           
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector12MutexDestroyEPNS_10DDCallbackEPNS_7DDMutexE)                                                                                                                                                                                                        
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector12MutexDestroyEPNS_10DDCallbackEPNS_7DDMutexE)                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer9DDetector9GetReportEPNS_10DDCallbackE)                                                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer9DDetector9GetReportEPNS_10DDCallbackE)                                                                                                                                                                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase6OnDeadEv)                                                                                                                                                                                                                                   
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase6OnDeadEv)                                                                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase8OnJoinedEPv)                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase8OnJoinedEPv)                                                                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase10OnFinishedEv)                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase10OnFinishedEv)                                                                                                                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase9OnStartedEPv)                                                                                                                                                                                                                                                                                            
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase9OnStartedEPv)                                                                                                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase9OnCreatedEPv)                                                                                                                                                                                                                                                                                            
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase9OnCreatedEPv)                                                                                                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase7OnResetEv)                                                                                                                                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase7OnResetEv)                                                                                                                                                                                                                                                                                                        
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17ThreadContextBase10OnDetachedEPv)                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17ThreadContextBase10OnDetachedEPv)                                                                                                                                                                                                                                                                                                   
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer15FlagHandlerBase5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer15FlagHandlerBase5ParseEPKc)                                                                                                                                                                                                                                                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer15FlagHandlerBase6FormatEPcm)                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer15FlagHandlerBase6FormatEPcm)                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerIPKcE5ParseES2_)                                                                                                                                                                                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerIPKcE5ParseES2_)                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely)                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN6__tsan8Callback9UniqueTidEv)                                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN6__tsan8Callback9UniqueTidEv)                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer14SymbolizerTool14LateInitializeEv)                                                                                                                                                                                                                                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer14SymbolizerTool14LateInitializeEv)                                                                                                                                                                                                                                                                                                   
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.rodata.str1.1)                                                                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.rodata.str1.8)                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN6__tsan12MemoryAccessEPNS_11ThreadStateEmmibb)                                                                                                                                                                                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN6__tsan12MemoryAccessEPNS_11ThreadStateEmmibb)                                                                                                                                                                                                                                                                                                                                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN6__tsan16MemoryAccessImplEPNS_11ThreadStateEmibbPyNS_6ShadowE)                                                                                                                                                                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN6__tsan16MemoryAccessImplEPNS_11ThreadStateEmibbPyNS_6ShadowE)                                                                                                                                                                                                                        
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN6__tsan9FuncEntryEPNS_11ThreadStateEm)                                                                                                                                                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN6__tsan9FuncEntryEPNS_11ThreadStateEm)                                                                                                                                                                                                                                                                                                                                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN6__tsan8FuncExitEPNS_11ThreadStateE)                                                                                                                                                                                                                                                                                                                                                                                           
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN6__tsan8FuncExitEPNS_11ThreadStateE)                                                                                                                                                                                                                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.rodata)                                                                                                                                                                                                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer15StaticSpinMutex8LockSlowEv)                                                                                                                                                                                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer15StaticSpinMutex8LockSlowEv)                                                                                                                                                                                                                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerIbE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerIbE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerINS_16HandleSignalModeEE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerINS_16HandleSignalModeEE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                           
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerIiE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerIiE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerImE5ParseEPKc)                                                                                                                                                                                                                                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerImE5ParseEPKc)                                                                                                                                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerIiE6FormatEPcm)                                                                                                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerIiE6FormatEPcm)                                                                                                                                                                                                                                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerIPKcE6FormatEPcm)                                                                                                                                                                                                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerIPKcE6FormatEPcm)                                                                                                                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerIbE6FormatEPcm)                                                                                                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerIbE6FormatEPcm)                                                                                                                                                                                                                                                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer18FlagHandlerInclude6FormatEPcm)                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer18FlagHandlerInclude6FormatEPcm)                                                                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerImE6FormatEPcm)                                                                                                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerImE6FormatEPcm)                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer11FlagHandlerINS_16HandleSignalModeEE6FormatEPcm)                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer11FlagHandlerINS_16HandleSignalModeEE6FormatEPcm)                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZNK11__sanitizer20SuspendedThreadsList11GetThreadIDEm)                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZNK11__sanitizer20SuspendedThreadsList11GetThreadIDEm)                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZNK11__sanitizer20SuspendedThreadsList11ThreadCountEv)                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZNK11__sanitizer20SuspendedThreadsList11ThreadCountEv)                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZNK11__sanitizer20SuspendedThreadsList17GetRegistersAndSPEmPNS_18InternalMmapVectorImEEPm)                                                                                                                                                                                                                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZNK11__sanitizer20SuspendedThreadsList17GetRegistersAndSPEmPNS_18InternalMmapVectorImEEPm)                                                                                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer18FlagHandlerInclude5ParseEPKc)                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer18FlagHandlerInclude5ParseEPKc)                                                                                  
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer14StackDepotBaseINS_14StackDepotNodeELi1ELi20EE3PutENS_10StackTraceEPb)                                                                                                                                                                                                                                                                                                                                           
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer14StackDepotBaseINS_14StackDepotNodeELi1ELi20EE3PutENS_10StackTraceEPb)                                                                                                                                                                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer20SizeClassAllocator32INS_4AP32EE16PopulateFreeListEPNS_14AllocatorStatsEPNS_30SizeClassAllocator32LocalCacheIS2_EEPNS2_13SizeClassInfoEm)                                                                                                                                                                                                                                                                        
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer20SizeClassAllocator32INS_4AP32EE16PopulateFreeListEPNS_14AllocatorStatsEPNS_30SizeClassAllocator32LocalCacheIS2_EEPNS2_13SizeClassInfoEm)                                                                                                                                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer20SizeClassAllocator32INS_4AP32EE13AllocateBatchEPNS_14AllocatorStatsEPNS_30SizeClassAllocator32LocalCacheIS2_EEm)                                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer20SizeClassAllocator32INS_4AP32EE13AllocateBatchEPNS_14AllocatorStatsEPNS_30SizeClassAllocator32LocalCacheIS2_EEm)                                                                                                                                                                                                                                                                                                         
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer30SizeClassAllocator32LocalCacheINS_20SizeClassAllocator32INS_4AP32EEEE6RefillEPNS4_8PerClassEPS3_m)                                                                                                                                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer30SizeClassAllocator32LocalCacheINS_20SizeClassAllocator32INS_4AP32EEEE6RefillEPNS4_8PerClassEPS3_m)                                                                                                                                                                                                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer30SizeClassAllocator32LocalCacheINS_20SizeClassAllocator32INS_4AP32EEEE5DrainEPNS4_8PerClassEPS3_m)                                                                                                                                                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer30SizeClassAllocator32LocalCacheINS_20SizeClassAllocator32INS_4AP32EEEE5DrainEPNS4_8PerClassEPS3_m)                                                                                                                                                                                                                                                                                                                        
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer17CombinedAllocatorINS_20SizeClassAllocator32INS_4AP32EEENS_32LargeMmapAllocatorPtrArrayStaticEE10ReallocateEPNS_30SizeClassAllocator32LocalCacheIS3_EEPvmm)                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer17CombinedAllocatorINS_20SizeClassAllocator32INS_4AP32EEENS_32LargeMmapAllocatorPtrArrayStaticEE10ReallocateEPNS_30SizeClassAllocator32LocalCacheIS3_EEPvmm)                                                                                                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN6__tsan8Callback6UnwindEv)                                                                                                                                                                                                                                                                                                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN6__tsan8Callback6UnwindEv)                                                                                                                                                                                                                                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text.unlikely._ZN11__sanitizer6VectorIN6__tsan10RacyStacksEE8PushBackERKS2_)                                                                                                                                                                                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.text._ZN11__sanitizer6VectorIN6__tsan10RacyStacksEE8PushBackERKS2_)                                                                                                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer10DDCallbackE)                                                                                                                                                                                                                                                                                                                                                                                                    
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer9DDetectorE)                                                                                                                                                                                                                                                                                                                                                                                                      
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer17ThreadContextBaseE)                                                                                                                                                                                                                                                                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer15FlagHandlerBaseE)                                                                                                                                                                                                                                                                                                                                                                                               
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer11FlagHandlerIbEE)                                                                                                                                                                                                                                                                                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer11FlagHandlerINS_16HandleSignalModeEEE)                                                                                                                                                                                                                                                                                                                                                                           
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer11FlagHandlerIPKcEE)                                                                                                                                                                                                                                                                                                                                                                                              
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer11FlagHandlerIiEE)                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer11FlagHandlerImEE)                                                                                                                                
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN6__tsan8CallbackE)                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN6__tsan13ThreadContextE)                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer2DDE)                                                                                                                                             
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer18FlagHandlerIncludeE)                                                                                                                            
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer20SuspendedThreadsListE)                                                                                                                          
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.ro._ZTVN11__sanitizer25SuspendedThreadsListLinuxE)                                                                                                                     
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel)                                                                                                                                                                       
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.data.rel.local)                                                                                                                                                                 
removing unused section /usr/local/go/src/runtime/race/race_linux_amd64.syso:(.rodata.cst16)                                                                                                                                                                   
removing unused section /home/motiejus/.cache/zig/o/09f3f90c2c8cb45a9ea08e615d2440aa/crtn.o:(.text)                                                                                                                                                            

motiejus added a commit to motiejus/zig that referenced this issue May 4, 2022
When building object files, `zig cc` will instruct lld to remove unused
sections via `--gc-sections`. This is problematic for cgo. Briefly, go
builds cgo executables as follows*:

1. build `_cgo_.o`, which links (on linux_amd64 systems) to
   `/usr/local/go/src/runtime/race/race_linux_amd64.syso`.
2. That `.syso` contains references to symbols from libc.

If the actual Go program uses at least one libc symbol, it will link
correctly. However, if Go is building a cgo executable, but without any
C code, the sections from `.syso` file will be garbage-collected,
leaving a `_cgo_.o` without any references to libc.

I assume the `gc_sections` is an optimization. If yes, then it makes
sense for the final executable, but not for the intermediate object. If
not, please correct me.

Quoting @andrewrk in [1]:

> The C source code for the temporary executable needs to have dummy
> calls to getuid, pthread_self, sleep, and every other libc function
> that cgo/race code wants to call.

I agree in this case. However, while we could potentially fix it for go,
I don't know how many other systems do that, which compilcates use of
`zig cc` for other projects. If we consider `zig cc` a drop-in clang
replacement (except for `-fsanitize=undefined`, which I tend to agree
with), then it should not be optimizing the intermediate object files.

I assume this was added as an optimization. If that's correct, let's
optimize the final executable, but not the intermediate objects.

Fixes ziglang#11398
Fixes golang/go#44695
Fixes golang/go#52690

[*]: Empirically observed with `CGO_ENABLED=1 go test -race -x -v`

[1]: golang/go#52690 (comment)
motiejus added a commit to motiejus/zig that referenced this issue May 4, 2022
When building object files, `zig cc` will instruct lld to remove unused
sections via `--gc-sections`. This is problematic cgo builds that don't
explicitly use C code. Briefly, go builds cgo executables as follows*:

1. build `_cgo_.o`, which links (on linux_amd64 systems) to
   `/usr/local/go/src/runtime/race/race_linux_amd64.syso`.
2. That `.syso` contains references to symbols from libc.

If the user program uses at least one libc symbol, it will link
correctly. However, if Go is building a cgo executable, but without C
code, the sections from `.syso` file will be garbage-collected, leaving
a `_cgo_.o` without any references to libc, causing the final linking
step to not link libc.

Until now, this could be worked around by `-linkmode external` flag to
`go build`. This causes Go to link the final executable using the
external linker (which implicitly links libc). However, that flag brings
in a whole different world of worms.

I assume the `gc_sections` is an optimization; I tried to re-add
`--gc-sections` to the final executable, but that didn't go well. I know
removing such an optimization may be contentious, so let's start the
discussion here. Quoting @andrewrk in [1] (it was about `--as-needed`,
but the point remains the same):

> The C source code for the temporary executable needs to have dummy
> calls to getuid, pthread_self, sleep, and every other libc function
> that cgo/race code wants to call.

I agree this is how it *should* work. However, while we could fix it for
go, I don't know how many other systems rely on that, and we'll never
know we've fixed the last one. The point is, GCC/Clang does not optimize
sections by default, and downstream tools rely on that. If we want to
consider `zig cc` a drop-in clang replacement (except for
`-fsanitize=undefined`, which I tend to agree with), then it should not
be optimizing the intermediate object files. Or at least have a very
prominent fine-print that this is happening, with ways to work around
it.

Fixes ziglang#11398
Fixes golang/go#44695
Fixes golang/go#52690

[*]: Empirically observed with `CGO_ENABLED=1 go test -race -x -v`

[1]: golang/go#52690 (comment)
@dr2chase dr2chase added this to the Backlog milestone May 4, 2022
@dr2chase dr2chase added the NeedsInvestigation label May 4, 2022
motiejus added a commit to motiejus/zig that referenced this issue May 5, 2022
When building object files, `zig cc` will instruct lld to remove unused
sections via `--gc-sections`. This is problematic cgo builds that don't
explicitly use C code. Briefly, go builds cgo executables as follows*:

1. build `_cgo_.o`, which links (on linux_amd64 systems) to
   `/usr/local/go/src/runtime/race/race_linux_amd64.syso`.
2. That `.syso` contains references to symbols from libc.

If the user program uses at least one libc symbol, it will link
correctly. However, if Go is building a cgo executable, but without C
code, the sections from `.syso` file will be garbage-collected, leaving
a `_cgo_.o` without any references to libc, causing the final linking
step to not link libc.

Until now, this could be worked around by `-linkmode external` flag to
`go build`. This causes Go to link the final executable using the
external linker (which implicitly links libc). However, that flag brings
in a whole different world of worms.

I assume the `gc_sections` is an optimization; I tried to re-add
`--gc-sections` to the final executable, but that didn't go well. I know
removing such an optimization may be contentious, so let's start the
discussion here. Quoting @andrewrk in [1] (it was about `--as-needed`,
but the point remains the same):

> The C source code for the temporary executable needs to have dummy
> calls to getuid, pthread_self, sleep, and every other libc function
> that cgo/race code wants to call.

I agree this is how it *should* work. However, while we could fix it for
go, I don't know how many other systems rely on that, and we'll never
know we've fixed the last one. The point is, GCC/Clang does not optimize
sections by default, and downstream tools rely on that. If we want to
consider `zig cc` a drop-in clang replacement (except for
`-fsanitize=undefined`, which I tend to agree with), then it should not
be optimizing the intermediate object files. Or at least have a very
prominent fine-print that this is happening, with ways to work around
it.

Fixes ziglang#11398
Fixes golang/go#44695
Fixes golang/go#52690

[*]: Empirically observed with `CGO_ENABLED=1 go test -race -x -v`

[1]: golang/go#52690 (comment)
uhthomas pushed a commit to gmirror/bazel-zig-cc that referenced this issue May 5, 2022
`zig cc` emits `--gc-sections` for the linker, which is incompatbile
with what CGo thinks about linking.

This commit adds a workaround: it will add `--no-gc-sections` to the
linking step if the command is not specified (falling back to the
default behavior of gcc/clang).

Related: golang/go#52690
@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 6, 2022

It would be fine with me if somebody wants to send a cgo patch that passes -Wl,--no-gc-sections, with a fallback if that option is not supported.

@ianlancetaylor ianlancetaylor added help wanted NeedsFix and removed NeedsInvestigation labels May 6, 2022
@andrewrk
Copy link
Author

@andrewrk andrewrk commented May 7, 2022

I think that would work fine but, any reason not to take my suggestion of having the C source code for the temporary executable make a call to any libc function? Seems like that would be more technically robust and avoid introducing logic for detecting available linker options.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 7, 2022

In general we would need to call the function with the correct argument types, as compilers know about an increasing number of functions and will complain if they are misused. That might be kind of painful. But if someone can make that work, then, sure, that is fine with me.

@motiejus
Copy link

@motiejus motiejus commented May 7, 2022

How about assigning the function addresses to a void * and making sure assignments are not optimized out? That does not necessitate knowing their argument types.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 7, 2022

Worth a try.

@kristoff-it
Copy link

@kristoff-it kristoff-it commented May 8, 2022

All you have to do is use one symbol referenced by the dynamic symbol table, adding print("hi go") in main will be enough to prevent the table from being potentially removed by optimizing compilers.

@motiejus
Copy link

@motiejus motiejus commented May 9, 2022

All you have to do is use one symbol referenced by the dynamic symbol table, adding print("hi go") in main will be enough to prevent the table from being potentially removed by optimizing compilers.

I spent some time today looking at this, it is not that straightforward. Semantically we don't know which symbol is necessary, so adding a dependency "print" (or alike) in the text section is a yet another hack.

This was mentioned somehere, but adding import "C" makes it work:

@@ -1,5 +1,6 @@
 package main
 
 import _ "runtime/cgo"
+import "C"
 
 func main() {}

But I was not not able to drill into exactly why. End-of-day status: when import "C" is present, cgo does an extra step: creates $WORK/b001/_cgo_.o, and uses that file later in the link steps. If the line is absent, this step is missing (and, looking at the output, the steps diverge from there).

For reference, here is the man page of GNU ld:

       --gc-sections
       --no-gc-sections
           Enable garbage collection of unused input sections.  It is ignored
           on targets that do not support this option.  The default behaviour
           (of not performing this garbage collection) can be restored by
           specifying --no-gc-sections on the command line.  Note that
           garbage collection for COFF and PE format targets is supported,
           but the implementation is currently considered to be experimental.

           --gc-sections decides which input sections are used by examining
           symbols and relocations.  The section containing the entry symbol
           and all sections containing symbols undefined on the command-line
           will be kept, as will sections containing symbols referenced by
           dynamic objects.  Note that when building shared libraries, the
           linker must assume that any visible symbol is referenced.  Once
           this initial set of sections has been determined, the linker
           recursively marks as used any section referenced by their
           relocations.  See --entry, --undefined, and --gc-keep-exported.

           This option can be set when doing a partial link (enabled with
           option -r).  In this case the root of symbols kept must be
           explicitly specified either by one of the options --entry,
           --undefined, or --gc-keep-exported or by a "ENTRY" command in the
           linker script.

llvm ld is much more brief:

     --gc-sections
             Enable garbage collection of unused sections.

My comment:

  1. --gc-sections is, at least according to GNU ld, not the default. I can see the point of zig making smaller shared objects by default, but perhaps let the caller decide when is it final?
  2. --gc-keep-exported doesn't seem to be available in llvm's ld, but sounds like it should work. But since it's not in ld, too bad.

Question to @ianlancetaylor

It would be fine with me if somebody wants to send a cgo patch that passes -Wl,--no-gc-sections, with a fallback if that option is not supported.

Does the fallback mean "if the linker barks, remove the flag"?

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 9, 2022

It would be fine with me if somebody wants to send a cgo patch that passes -Wl,--no-gc-sections, with a fallback if that option is not supported.

Does the fallback mean "if the linker barks, remove the flag"?

Yes. If the linker fails complainig about --no-gc-sections, rerun the link without that flag.

@kristoff-it
Copy link

@kristoff-it kristoff-it commented May 10, 2022

I spent some time today looking at this, it is not that straightforward. Semantically we don't know which symbol is necessary, so adding a dependency "print" (or alike) in the text section is a yet another hack.

I've looked into it a bit more and yes, you're right. The current failing case is when building runtime/cgo, which could be fixed by hardcoding the behavior, but in the more general case (ie any other cgo package) would require to do the same for any C file that cgo happens to deal with. In light of that, the flag approach does seem the most reasonable choice.

motiejus added a commit to motiejus/go that referenced this issue May 10, 2022
zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Minimal example:

*main.go*
```
package main
import _ "runtime/cgo"
func main() {}
```

Run (works after the patch, doesn't work before):

```
CGO_ENABLED=1 CC="zig cc" go build main.go
```

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.896+e620b692c

Fixes golang#52690
motiejus added a commit to motiejus/go that referenced this issue May 10, 2022
zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Minimal example:

**main.go**
```
package main
import _ "runtime/cgo"
func main() {}
```

Run (works after the patch, doesn't work before):

```
CGO_ENABLED=1 CC="zig cc" go build main.go
```

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.896+e620b692c

Fixes golang#52690
motiejus added a commit to motiejus/go that referenced this issue May 10, 2022
zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Minimal example:

**main.go**
```
package main
import _ "runtime/cgo"
func main() {}
```

Run (works after the patch, doesn't work before):

```
CGO_ENABLED=1 CC="zig cc" go build main.go
```

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.896+e620b692c

Fixes golang#52690
motiejus added a commit to motiejus/go that referenced this issue May 10, 2022
This change adds `--no-gc-sections` to the external linker if the flag
is understood.

zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Minimal example:

**main.go**
```
package main
import _ "runtime/cgo"
func main() {}
```

Run (works after the patch, doesn't work before):

```
CGO_ENABLED=1 CC="zig cc" go build main.go
```

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.896+e620b692c

Fixes golang#52690
@motiejus motiejus linked a pull request May 10, 2022 that will close this issue
@gopherbot
Copy link

@gopherbot gopherbot commented May 10, 2022

Change https://go.dev/cl/405414 mentions this issue: cmd/cgo: use --no-gc-sections if available

motiejus added a commit to motiejus/go that referenced this issue May 18, 2022
This change adds `--no-gc-sections` to the external linker if the flag
is understood.

zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Minimal example:

**main.go**
```
package main
import _ "runtime/cgo"
func main() {}
```

Run (works after the patch, doesn't work before):

```
CC="zig cc" go build main.go
```

Among the existing code, `src/runtime/testdata/testprognet` fails too:
```
src/runtime/testdata/testprognet$ CC="zig cc" go build .
net(.text): relocation target __errno_location not defined
net(.text): relocation target getaddrinfo not defined
net(.text): relocation target freeaddrinfo not defined
net(.text): relocation target gai_strerror not defined
runtime/cgo(.text): relocation target stderr not defined
runtime/cgo(.text): relocation target fwrite not defined
runtime/cgo(.text): relocation target vfprintf not defined
runtime/cgo(.text): relocation target fputc not defined
runtime/cgo(.text): relocation target abort not defined
runtime/cgo(.text): relocation target pthread_create not defined
runtime/cgo(.text): relocation target nanosleep not defined
runtime/cgo(.text): relocation target pthread_detach not defined
runtime/cgo(.text): relocation target stderr not defined
runtime/cgo(.text): relocation target strerror not defined
runtime/cgo(.text): relocation target fprintf not defined
runtime/cgo(.text): relocation target abort not defined
runtime/cgo(.text): relocation target pthread_mutex_lock not defined
runtime/cgo(.text): relocation target pthread_cond_wait not defined
runtime/cgo(.text): relocation target pthread_mutex_unlock not defined
runtime/cgo(.text): relocation target pthread_cond_broadcast not defined
runtime/cgo(.text): relocation target malloc not defined
```

With the patch both examples build as expected.

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.2252+a4369918b

Fixes golang#52690
motiejus added a commit to motiejus/go that referenced this issue May 19, 2022
zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Add `-Wl,--no-gc-sections` to make it work with zig cc. Minimal
example:

**main.go**

    package main
    import _ "runtime/cgo"
    func main() {}

Run (works after the patch, doesn't work before):

    CC="zig cc" go build main.go

Among the existing code, `src/runtime/testdata/testprognet` fails to
build:

    src/runtime/testdata/testprognet$ CC="zig cc" go build .
    net(.text): relocation target __errno_location not defined
    net(.text): relocation target getaddrinfo not defined
    net(.text): relocation target freeaddrinfo not defined
    net(.text): relocation target gai_strerror not defined
    runtime/cgo(.text): relocation target stderr not defined
    runtime/cgo(.text): relocation target fwrite not defined
    runtime/cgo(.text): relocation target vfprintf not defined
    runtime/cgo(.text): relocation target fputc not defined
    runtime/cgo(.text): relocation target abort not defined
    runtime/cgo(.text): relocation target pthread_create not defined
    runtime/cgo(.text): relocation target nanosleep not defined
    runtime/cgo(.text): relocation target pthread_detach not defined
    runtime/cgo(.text): relocation target stderr not defined
    runtime/cgo(.text): relocation target strerror not defined
    runtime/cgo(.text): relocation target fprintf not defined
    runtime/cgo(.text): relocation target abort not defined
    runtime/cgo(.text): relocation target pthread_mutex_lock not defined
    runtime/cgo(.text): relocation target pthread_cond_wait not defined
    runtime/cgo(.text): relocation target pthread_mutex_unlock not defined
    runtime/cgo(.text): relocation target pthread_cond_broadcast not defined
    runtime/cgo(.text): relocation target malloc not defined

With the patch both examples build as expected.

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.2252+a4369918b

Fixes golang#52690
motiejus added a commit to motiejus/go that referenced this issue May 19, 2022
zig cc passes `--gc-sections` to the underlying linker, which then
causes undefined symbol errors when compiling with cgo but without C
code. Add `-Wl,--no-gc-sections` to make it work with zig cc. Minimal
example:

**main.go**

    package main
    import _ "runtime/cgo"
    func main() {}

Run (works after the patch, doesn't work before):

    CC="zig cc" go build main.go

Among the existing code, `src/runtime/testdata/testprognet` fails to
build:

    src/runtime/testdata/testprognet$ CC="zig cc" go build .
    net(.text): relocation target __errno_location not defined
    net(.text): relocation target getaddrinfo not defined
    net(.text): relocation target freeaddrinfo not defined
    net(.text): relocation target gai_strerror not defined
    runtime/cgo(.text): relocation target stderr not defined
    runtime/cgo(.text): relocation target fwrite not defined
    runtime/cgo(.text): relocation target vfprintf not defined
    runtime/cgo(.text): relocation target fputc not defined
    runtime/cgo(.text): relocation target abort not defined
    runtime/cgo(.text): relocation target pthread_create not defined
    runtime/cgo(.text): relocation target nanosleep not defined
    runtime/cgo(.text): relocation target pthread_detach not defined
    runtime/cgo(.text): relocation target stderr not defined
    runtime/cgo(.text): relocation target strerror not defined
    runtime/cgo(.text): relocation target fprintf not defined
    runtime/cgo(.text): relocation target abort not defined
    runtime/cgo(.text): relocation target pthread_mutex_lock not defined
    runtime/cgo(.text): relocation target pthread_cond_wait not defined
    runtime/cgo(.text): relocation target pthread_mutex_unlock not defined
    runtime/cgo(.text): relocation target pthread_cond_broadcast not defined
    runtime/cgo(.text): relocation target malloc not defined

With the patch both examples build as expected.

@ianlancetaylor suggested:

> It would be fine with me if somebody wants to send a cgo patch that
passes -Wl,--no-gc-sections, with a fallback if that option is not
supported.

... and this is what we are doing. Tested with zig
0.10.0-dev.2252+a4369918b

Fixes golang#52690
motiejus added a commit to motiejus/go that referenced this issue May 19, 2022
As of 742dcba `go build` can accept
`$CC` with spaces and quotes, which lets us easily use `zig cc` as the C
compiler, or easily pass extra compiler parameters:

```
CC="zig cc" go build <...>
CC="clang-13 -v" go build <...>
CC="zig cc -Wl,--print-gc-sections" go build <...>
```

However, the same does not apply for building go itself:

```
$ CC="zig cc" ./make.bash
Building Go cmd/dist using /usr/local/go. (go1.18.2 linux/amd64)
go tool dist: cannot invoke C compiler "zig cc": exec: "zig cc": executable file not found in $PATH

Go needs a system C compiler for use with cgo.
To set a C compiler, set CC=the-compiler.
To disable cgo, set CGO_ENABLED=0.
```

With this change Go can be built directly with `zig cc` (the linker arg
will disappear with golang#52815 and/or golang#52690):

```
$ CC="zig cc -Wl,--no-gc-sections" ./make.bash
Building Go cmd/dist using /usr/local/go. (go1.18.2 linux/amd64)
Building Go toolchain1 using /usr/local/go.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for linux/amd64.
---
Installed Go for linux/amd64 in /home/motiejus/code/go
Installed commands in /home/motiejus/code/go/bin
$ ../bin/go version
go version devel go1.19-811f1913a8 Thu May 19 09:44:49 2022 +0300 linux/amd64
```

Fixes golang#52990
@gopherbot
Copy link

@gopherbot gopherbot commented May 19, 2022

Change https://go.dev/cl/407216 mentions this issue: cmd/dist: support spaces and quotes in CC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted NeedsFix
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants