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

-lc doesn't link c_nonshared #11137

Closed
Vexu opened this issue Mar 12, 2022 · 15 comments
Closed

-lc doesn't link c_nonshared #11137

Vexu opened this issue Mar 12, 2022 · 15 comments
Labels
bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness. os-linux
Milestone

Comments

@Vexu
Copy link
Member

Vexu commented Mar 12, 2022

$ 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 Vexu added the frontend Tokenization, parsing, AstGen, Sema, and Liveness. label Mar 12, 2022
@Vexu Vexu added this to the 0.10.0 milestone Mar 12, 2022
@andrewrk andrewrk added bug Observed behavior contradicts documented or intended behavior os-linux labels Mar 13, 2022
mewmew added a commit to mewpull/zig that referenced this issue Apr 26, 2022
Prior to this commit, building on Arch Linux would result in
the following linker error:

	undefined symbol: __libc_single_threaded

Updates ziglang#11137.
@daurnimator
Copy link
Contributor

Arch uses glibc 2.35.

Looking through recent glibc changes related to c_nonshared I found bminor/glibc@1a2f44a. I wonder if this means that linking pthread previously implied c_nonshared, but it doesn't any more.

@ifreund
Copy link
Member

ifreund commented Apr 26, 2022

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.

@matu3ba
Copy link
Contributor

matu3ba commented May 13, 2022

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?

@andrewrk
Copy link
Member

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.

@ifreund
Copy link
Member

ifreund commented May 13, 2022

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.

@BratishkaErik
Copy link
Contributor

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 ) )

@matu3ba
Copy link
Contributor

matu3ba commented May 15, 2022

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.

Techcable added a commit to Techcable/zig that referenced this issue Jun 2, 2022
DONT INCLUDE THIS IN THE FINAL PR.

This is just for convenience as I switch back and forth from my two
laptops.
@BratishkaErik
Copy link
Contributor

$ 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

@topolarity
Copy link
Contributor

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
$

@BratishkaErik
Copy link
Contributor

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
Copy link
Contributor

BratishkaErik commented Jul 27, 2022

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 #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

@topolarity
Copy link
Contributor

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,
        },
    }},
};

@nektro
Copy link
Contributor

nektro commented Jul 27, 2022

that's tracked separately in 6469

andrewrk added a commit that referenced this issue Sep 9, 2022
Previously, this code would fail to detect glibc version because it
relied on libc.so.6 being a symlink which revealed the answer. On modern
distros, this is no longer the case.

This new strategy finds the path to libc.so.6 from /usr/bin/env, then
inspects the .dynstr section of libc.so.6, looking for symbols that
start with "GLIBC_2.". It then parses those as semantic versions and
takes the maximum value as the system-native glibc version.

closes #6469
   see #11137
closes #12567
@andrewrk
Copy link
Member

andrewrk commented Sep 9, 2022

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

andrewrk added a commit that referenced this issue Sep 9, 2022
Previously, this code would fail to detect glibc version because it
relied on libc.so.6 being a symlink which revealed the answer. On modern
distros, this is no longer the case.

This new strategy finds the path to libc.so.6 from /usr/bin/env, then
inspects the .dynstr section of libc.so.6, looking for symbols that
start with "GLIBC_2.". It then parses those as semantic versions and
takes the maximum value as the system-native glibc version.

closes #6469
   see #11137
closes #12567
andrewrk added a commit that referenced this issue Sep 9, 2022
Previously, this code would fail to detect glibc version because it
relied on libc.so.6 being a symlink which revealed the answer. On modern
distros, this is no longer the case.

This new strategy finds the path to libc.so.6 from /usr/bin/env, then
inspects the .dynstr section of libc.so.6, looking for symbols that
start with "GLIBC_2.". It then parses those as semantic versions and
takes the maximum value as the system-native glibc version.

closes #6469
   see #11137
closes #12567
@Vexu
Copy link
Member Author

Vexu commented Sep 9, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness. os-linux
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants