zig icon indicating copy to clipboard operation
zig copied to clipboard

Undefined reference to pthread_mutex_trylock when using libc

Open hvenev opened this issue 5 years ago • 10 comments

$ cat atest.zig
const std = @import("std");
pub fn main() void {
    var mtx = std.Thread.Mutex {};
    _ = mtx.tryAcquire();
}
$ zig build-exe --libc <(zig libc) -lc -lpthread ./atest.zig
ld.lld: error: undefined symbol: pthread_mutex_trylock
>>> referenced by Mutex.zig:198 (/usr/lib/zig/std/Thread/Mutex.zig:198)
>>>               ./zig-cache/o/7b8d8fca250dcd6cd96d73f316c15033/atest.o:(std.Thread.Mutex.PthreadMutex.tryAcquire)
error: LLDReportedFailure
$ nm /usr/lib64/libc.so.6 | grep pthread_mutex_trylock
$ nm /usr/lib64/libpthread.so.0 | grep pthread_mutex_trylock
000000000000bf51 t .annobin___GI___pthread_mutex_trylock.end
000000000000b900 t .annobin___GI___pthread_mutex_trylock.start
000000000000b900 t .annobin_pthread_mutex_trylock.c
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.exit
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.hot
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.startup
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.unlikely
000000000000bf51 t .annobin_pthread_mutex_trylock.c_end
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.exit
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.hot
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.startup
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.unlikely
000000000000b900 t __GI___pthread_mutex_trylock
000000000000b900 T __pthread_mutex_trylock
000000000000b900 W pthread_mutex_trylock

hvenev avatar Jan 16 '21 14:01 hvenev

There's a small but significant difference between musl and glibc, the former ships a single libc.so while the latter ships much more than a single .so object. is_libc_lib_name detects -lc -lpthread and discards them, the code in src/link/Elf.zig already knows what to link, the compiler understands you want the libc to be linked.

linkWithLLD in src/link/Elf.zig is, on the other hand, unaware of any other libc component beside lc and lm! The linker error you see is caused by this problem as -lpthread is never relayed to the linker :\

LemonBoy avatar Jan 16 '21 16:01 LemonBoy

Keep in mind that this problem shows up only when --libc is specified. You can compile your code as: zig build-exe -target native-linux-gnu -lc -lpthread /tmp/foo.zig or, if your system uses glibc, with zig build-exe -lc -lpthread /tmp/foo.zig

LemonBoy avatar Jan 16 '21 16:01 LemonBoy

Keep in mind that this problem shows up only when --libc is specified. You can compile your code as: zig build-exe -target native-linux-gnu -lc -lpthread /tmp/foo.zig or, if your system uses glibc, with zig build-exe -lc -lpthread /tmp/foo.zig

If I don't specify --libc, zig tries to access its glibc fork, which is a thing I want to avoid. In particular, I don't want to have to make sure that zig's glibc fork is ABI-compatible with the one on my system.

hvenev avatar Jan 16 '21 16:01 hvenev

If I don't specify --libc, zig tries to access its glibc fork, which is a thing I want to avoid.

There's no glibc fork. We only build fake .so files containing the correctly-versioned symbol names, that is to appease the linker and bake the correct library requirements into the resulting ELF file.

LemonBoy avatar Jan 16 '21 16:01 LemonBoy

If I don't specify --libc, zig tries to access its glibc fork, which is a thing I want to avoid.

There's no glibc fork.

OK, not a fork, but a bundled modified copy.

We only build fake .so files containing the correctly-versioned symbol names, that is to appease the linker and bake the correct library requirements into the resulting ELF file.

How do I use the system libc instead?

By the way, I managed to link the binary by providing a symlink to libpthread.so under a different name and linking that.

hvenev avatar Jan 16 '21 16:01 hvenev

OK, not a fork, but a bundled modified copy.

There's no bundled modified copy, the handful of .c files are only needed to provide some symbols that are not exported by libc.so.

How do I use the system libc instead?

zig build-exe -lc -lpthread /tmp/foo.zig

LemonBoy avatar Jan 16 '21 16:01 LemonBoy

OK, not a fork, but a bundled modified copy.

There's no bundled modified copy, the handful of .c files are only needed to provide some symbols that are not exported by libc.so.

OK, let's call it a bundled copy of a particular release of glibc with some files deleted.

How do I use the system libc instead?

zig build-exe -lc -lpthread /tmp/foo.zig

That uses crti.S from zig's bundled copy of glibc. I'd like to use the system crti.o.

hvenev avatar Jan 16 '21 16:01 hvenev

That uses crti.S from zig's bundled copy of glibc. I'd like to use the system crti.o.

Then it's: zig build-exe --libc <(zig libc) -lc -lpthread ./atest.zig

LemonBoy avatar Jan 16 '21 17:01 LemonBoy

That uses crti.S from zig's bundled copy of glibc. I'd like to use the system crti.o.

Then it's: zig build-exe --libc <(zig libc) -lc -lpthread ./atest.zig

which fails because -lpthread is ignored.

Here's an idea: if --libc is given, we don't remove the -l arguments, and we don't add -lc -lm. I will test it and I will submit a pull request if it works.

hvenev avatar Jan 16 '21 17:01 hvenev

I think https://github.com/ziglang/zig/pull/7870 is a better idea.

hvenev avatar Jan 24 '21 13:01 hvenev