ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.46k stars 2.52k forks source link

undefined reference __tls_get_addr while linking #20625

Open lamgea opened 3 months ago

lamgea commented 3 months ago

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

In the newly created Zig package (created with zig init):

  1. Referencing the add function in root.zig from main.zig either by extern fn or @import.
  2. Change the library to be dynamically linked and link the library in the build script.

A compilation error will be thrown when trying to build: ld.lld: undefined reference due to --no-allow-shlib-undefined: __tls_get_addr

It seem to be specific to Linux. I tried cross compiling to Windows and it worked fine. Related issue in earlier version: #4748

Additionally, append .single_threaded = true to the build option of the library could make it build, but it will give a seg fault when running.

Expected Behavior

It should build and run without errors.

zhylmzr commented 3 months ago

I was unable to reproduce this issue by cross-compiling to Linux:

zig1 » zig build -Dtarget=x86_64-linux

zig1 » file zig-out/bin/zig1
zig-out/bin/zig1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, with debug_info, not stripped

zig1 » zig version
0.13.0
// build.zig
const lib = b.addSharedLibrary(.{
    .name = "zig1",
    .root_source_file = b.path("src/root.zig"),
    .target = target,
    .optimize = optimize,
});

const exe = b.addExecutable(.{
    .name = "zig1",
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});

exe.linkLibrary(lib);
// main.zig
const std = @import("std");

extern fn add(a: i32, b: i32) i32;

pub fn main() !void {
    std.debug.print("hello {}", .{add(1, 2)});
}
// root.zig
export fn add(a: i32, b: i32) i32 {
    return a + b;
}
lamgea commented 3 months ago

@zhylmzr Strange, by explicit about target the binary builds. But it will still run into segfault. I also reproduced it on Ubuntu image in docker.

zhylmzr commented 3 months ago

Yes, although the build will not fail when cross-compiling, but a segfault will occur at runtime.

After checking the symbol table again, the temporary solution is as follows:

// build.zig
const lib = b.addSharedLibrary(.{
    .name = "bug1",
    .root_source_file = b.path("src/root.zig"),
    .target = target,
    .optimize = optimize,
    .sanitize_thread = true, // <-- add this line
});
lib.linkLibC(); // <-- add this line
lamgea commented 3 months ago

@zhylmzr Thanks for that. I tested it, and it seems like I only need to link libc to get this working.