zig icon indicating copy to clipboard operation
zig copied to clipboard

`-lc` doesn't link `c_nonshared`

Open Vexu opened this issue 3 years ago • 13 comments

$ cat a.c
extern char __libc_single_threaded;
int main(void) {
    return __libc_single_threaded;
}
$ clang a.c
$ zig build-exe a.c -lc
ld.lld: error: undefined symbol: __libc_single_threaded
>>> referenced by a.c:3
>>>               /home/vexu/.cache/zig/o/00d791557252b46f5ed6668a930dc12a/a.o:(main)
error: LLDReportedFailure

Not sure how this works on other targets but on Arch Linux it means that building stage2 with system LLVM requires this patch:

diff --git a/build.zig b/build.zig
index 5896ab1a8..fb821ccf4 100644
--- a/build.zig
+++ b/build.zig
@@ -550,6 +550,7 @@ fn addCmakeCfgOptionsToExe(
                 else => |e| return e,
             };
             exe.linkSystemLibrary("unwind");
+            exe.linkSystemLibrary("c_nonshared");
         } else if (exe.target.isFreeBSD()) {
             try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
             exe.linkSystemLibrary("pthread");

Vexu avatar Mar 12 '22 16:03 Vexu

Arch uses glibc 2.35.

Looking through recent glibc changes related to c_nonshared I found https://github.com/bminor/glibc/commit/1a2f44a848663036c8a14671fe0faa3fed0b2a25. I wonder if this means that linking pthread previously implied c_nonshared, but it doesn't any more.

daurnimator avatar Apr 26 '22 09:04 daurnimator

The proper fix is probably adding -lc_nonshared to libcFullLinkFlags() in src/target.zig if targeting glibc. I would like to understand exactly what's happening here though before doing that.

ifreund avatar Apr 26 '22 09:04 ifreund

At least for me a default build of glibc contains libc_nonshared.a, but srcglibc.zig` does not contain it in the library list:

// The order of the elements in this array defines the linking order.
pub const libs = [_]Lib{
    .{ .name = "m", .sover = 6 },
    .{ .name = "pthread", .sover = 0 },
    .{ .name = "c", .sover = 6 },
    .{ .name = "dl", .sover = 2 },
    .{ .name = "rt", .sover = 1 },
    .{ .name = "ld", .sover = 2 },
    .{ .name = "util", .sover = 1 },
};

Nevertheless, libc_nonshared.a is generated during building stage1.

How is Zig picking up the correct paths to the libcs etc in .cache? rg glibc inside the build folder of stage1 shows no results. Is the path picked up from calculating/combining some hashes?

matu3ba avatar May 13 '22 09:05 matu3ba

Note that zig is perfectly capable of providing libc_nonshared.a... but in the case of native builds we don't do it because we want to actually integrate with system libc. So we're stuck figuring out what the various systems want from us.

andrewrk avatar May 13 '22 21:05 andrewrk

On my glibc 2.32 void linux system /usr/lib/libc.so appears to be a linker script which pulls in libc_nonshared.a:

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib64/libc.so.6 /usr/lib64/libc_nonshared.a  AS_NEEDED ( /usr/lib64/ld-linux-x86-64.so.2 ) )

This might help explain things, in particular why I wasn't seeing any reference to libc_nonshared.a in gcc -v output on my system.

ifreund avatar May 13 '22 22:05 ifreund

Ok, on my glibc 2.35 gentoo system cat /usr/lib/libc.so:

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a  AS_NEEDED ( /lib/ld-linux.so.2 ) )

cat /usr/lib64/libc.so:

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a  AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )

BratishkaErik avatar May 14 '22 08:05 BratishkaErik

On Arch its similar cat /usr/lib/libc.so

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib/libc.so.6 /usr/lib/libc_nonshared.a  AS_NEEDED ( /usr/lib/ld-linux-x86-64.so.2 ) )

cat /usr/lib64/libc.so

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib/libc.so.6 /usr/lib/libc_nonshared.a  AS_NEEDED ( /usr/lib/ld-linux-x86-64.so.2 ) )

file /usr/lib/ld-linux.so.2 symlinking to /usr/lib32/ld-linux.so.2 should not make a difference in this context.

matu3ba avatar May 15 '22 07:05 matu3ba

$ cat a.c
extern char __libc_single_threaded;
int main(void) {
    return __libc_single_threaded;
}
$ clang a.c
$ zig build-exe a.c -lc
ld.lld: error: undefined symbol: __libc_single_threaded
>>> referenced by a.c:3
>>>               /home/vexu/.cache/zig/o/00d791557252b46f5ed6668a930dc12a/a.o:(main)
error: LLDReportedFailure

Ah, and __libc_single_threaded was introduced in glibc 2.32

BratishkaErik avatar Jun 04 '22 16:06 BratishkaErik

On my system, Zig is in fact providing libc_nonshared.a, but the symbol is still missing:

$ ./zig-linux-x86_64-0.9.1/zig build-exe test.c -lc --verbose-link
ld.lld -error-limit=0 -O0 -z stack-size=16777216 --gc-sections -m elf_x86_64 -o test /home/topolarity/.cache/zig/o/3bb4baaa7fdbd4d420aa2c0ea0b25896/Scrt1.o /home/topolarity/.cache/zig/o/f01eecd9f532c366e29902dc433e6bbc/crti.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 /home/topolarity/.cache/zig/o/4f097214eb5219ae4350051529af36b2/test.o /home/topolarity/.cache/zig/o/8e947370e0e9a95237b40481a6c38c41/libcompiler_rt.a --as-needed /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libm.so.6 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libpthread.so.0 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libc.so.6 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libdl.so.2 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/librt.so.1 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libld.so.2 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libutil.so.1 /home/topolarity/.cache/zig/o/fa5988d449df15a0a124339ef2635cc7/libc_nonshared.a /home/topolarity/.cache/zig/o/b569a0eace5a24dad59f9ea9da18f67d/crtn.o
ld.lld: error: undefined symbol: __libc_single_threaded
>>> referenced by test.c:3
>>>               /home/topolarity/.cache/zig/o/4f097214eb5219ae4350051529af36b2/test.o:(main)
error: LLDReportedFailure
$

If I request a system library so that Zig integrates with system libc, the example actually works:

$ ./zig-linux-x86_64-0.9.1/zig build-exe test.c -lc -lz --verbose-link
ld.lld -error-limit=0 -O0 -z stack-size=16777216 --gc-sections -m elf_x86_64 -o test /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib/crti.o -rpath /lib64 -rpath /lib -rpath /usr/lib64 -rpath /usr/lib -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 -L /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib -dynamic-linker /lib64/ld-linux-x86-64.so.2 /home/topolarity/.cache/zig/o/93bdf25300a52e9361dec6260fcb51e3/test.o /home/topolarity/.cache/zig/o/8e947370e0e9a95237b40481a6c38c41/libcompiler_rt.a --as-needed -lz -lm -lpthread -lc -ldl -lrt -lutil /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib/crtn.o
$

topolarity avatar Jul 17 '22 22:07 topolarity

On my system, Zig is in fact providing libc_nonshared.a, but the symbol is still missing:

$ ./zig-linux-x86_64-0.9.1/zig build-exe test.c -lc --verbose-link
ld.lld -error-limit=0 -O0 -z stack-size=16777216 --gc-sections -m elf_x86_64 -o test /home/topolarity/.cache/zig/o/3bb4baaa7fdbd4d420aa2c0ea0b25896/Scrt1.o /home/topolarity/.cache/zig/o/f01eecd9f532c366e29902dc433e6bbc/crti.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 /home/topolarity/.cache/zig/o/4f097214eb5219ae4350051529af36b2/test.o /home/topolarity/.cache/zig/o/8e947370e0e9a95237b40481a6c38c41/libcompiler_rt.a --as-needed /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libm.so.6 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libpthread.so.0 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libc.so.6 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libdl.so.2 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/librt.so.1 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libld.so.2 /home/topolarity/.cache/zig/o/b61716bae4d350e69e284aa7d351fe5d/libutil.so.1 /home/topolarity/.cache/zig/o/fa5988d449df15a0a124339ef2635cc7/libc_nonshared.a /home/topolarity/.cache/zig/o/b569a0eace5a24dad59f9ea9da18f67d/crtn.o
ld.lld: error: undefined symbol: __libc_single_threaded
>>> referenced by test.c:3
>>>               /home/topolarity/.cache/zig/o/4f097214eb5219ae4350051529af36b2/test.o:(main)
error: LLDReportedFailure
$

If I request a system library so that Zig integrates with system libc, the example actually works:

$ ./zig-linux-x86_64-0.9.1/zig build-exe test.c -lc -lz --verbose-link
ld.lld -error-limit=0 -O0 -z stack-size=16777216 --gc-sections -m elf_x86_64 -o test /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib/crti.o -rpath /lib64 -rpath /lib -rpath /usr/lib64 -rpath /usr/lib -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 -L /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib -dynamic-linker /lib64/ld-linux-x86-64.so.2 /home/topolarity/.cache/zig/o/93bdf25300a52e9361dec6260fcb51e3/test.o /home/topolarity/.cache/zig/o/8e947370e0e9a95237b40481a6c38c41/libcompiler_rt.a --as-needed -lz -lm -lpthread -lc -ldl -lrt -lutil /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../lib/crtn.o
$

Can you please share output of ./zig-linux-x86_64-0.9.1/zig build-exe --show-builtin?

BratishkaErik avatar Jul 27 '22 18:07 BratishkaErik

On my glibc 2.32 void linux system /usr/lib/libc.so appears to be a linker script which pulls in libc_nonshared.a:

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib64/libc.so.6 /usr/lib64/libc_nonshared.a  AS_NEEDED ( /usr/lib64/ld-linux-x86-64.so.2 ) )

This might help explain things, in particular why I wasn't seeing any reference to libc_nonshared.a in gcc -v output on my system.

I guess this will be fixed when https://github.com/ziglang/zig/issues/6469 will be fixed:

./zig targets | jq .native.triple: "x86_64-linux.5.18.14...5.18.14-gnu.2.19" ldd --version: ldd (Gentoo 2.35-r8 p9) 2.35 ./zig build-exe a.c -lc:

LLD Link... ld.lld: error: undefined symbol: __libc_single_threaded
>>> referenced by a.c:3 (/home/bratishkaerik/zig/build/a.c:3)
>>>               /home/bratishkaerik/.cache/zig/o/ba6cf5a0f60a803a3277d1158d1d817f/a.o:(main)

./zig build-exe a.c -lc -target x86_64-linux.5.18.14...5.18.14-gnu.2.32 (and higher, like 2.34): no error ./zig build-exe a.c -lc -target x86_64-linux.5.18.14...5.18.14-gnu.2.35:

error: zig does not yet provide glibc version 2.35, the max provided version is 2.34
error: unable to build glibc shared objects: InvalidTargetGLibCVersion

BratishkaErik avatar Jul 27 '22 18:07 BratishkaErik

Can you please share output of ./zig-linux-x86_64-0.9.1/zig build-exe --show-builtin?

Indeed, the wrong version of glibc is detected:

pub const os = std.Target.Os{
    .tag = .linux,
    .version_range = .{ .linux = .{
        .range = .{
            .min = .{
                .major = 5,
                .minor = 10,
                .patch = 102,
            },
            .max = .{
                .major = 5,
                .minor = 10,
                .patch = 102,
            },
        },
        .glibc = .{
            .major = 2,
            .minor = 19,
            .patch = 0,
        },
    }},
};

topolarity avatar Jul 27 '22 19:07 topolarity

that's tracked separately in 6469

nektro avatar Jul 27 '22 22:07 nektro

Could I get someone affected by this issue to check whether #12788 solves it?

andrewrk avatar Sep 09 '22 01:09 andrewrk

Duplicate of #6469 since the example works as expected with -target native-native-gnu.2.34.

Vexu avatar Sep 09 '22 16:09 Vexu