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

Segmentation fault by default due to a wrong dynamic linker on KissLinux #21963

Open
Ogromny opened this issue Nov 11, 2024 · 5 comments
Open
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@Ogromny
Copy link
Contributor

Ogromny commented Nov 11, 2024

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

On KissLinux:

main.zig

const c = @cImport({
    @cInclude("stdio.h");
});

pub fn main() !void {
    _ = c.puts("hello");
}

build.zig

const std = @import("std");

pub fn build(b: *std.Build) void {
    const exe = b.addExecutable(.{
        .name = "hello",
        .root_source_file = b.path("main.zig"),
        .target = b.host,
        .optimize = .Debug,
    });
    exe.linkLibC();
    b.installArtifact(exe);
}

image

gdb output
image

After digging a little bit I realized that the linking stage was failing but still outputs the executable:
image

By taking the exact build command and removing the listen=- argument and adding --dynamic-linker /usr/lib/ld-musl-x86_64.so.1 the executable get successfully linked and works as expected
image

image

What can be the cause of this issue ?

Expected Behavior

The executable gets linked successfully

@Ogromny Ogromny added the bug Observed behavior contradicts documented or intended behavior label Nov 11, 2024
@alexrp
Copy link
Member

alexrp commented Nov 11, 2024

Please try this with a nightly build from https://ziglang.org/download as there have been multiple changes to std.Target.DynamicLinker in master.

@Ogromny
Copy link
Contributor Author

Ogromny commented Nov 11, 2024

Please try this with a nightly build from https://ziglang.org/download as there have been multiple changes to std.Target.DynamicLinker in master.

Unfortunately I get the same issue with the latest nightly build
image

@BratishkaErik
Copy link
Contributor

I guess it's similar reason as in #21941 (comment) :

Yes, because it checks /usr/bin/env or its interpreter (/usr/bin/coreutils, /bin/sh) to find out libc, and if you compile it statically, it would assume that whole system is static -> musl needed.

In kiss-chroot-24.06.14-2:

$ file usr/bin/env
usr/bin/env: symbolic link to busybox

$ file usr/bin/busybox
usr/bin/busybox: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

$ file usr/bin/x86_64-pc-linux-musl-gcc
usr/bin/x86_64-pc-linux-musl-gcc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, stripped

So if you start zig build-exe --show-builtin:

pub const abi = std.Target.Abi.musl;
// ...
pub const os = std.Target.Os{
    .tag = .linux,
    .version_range = .{ .linux = .{
        .range = .{
            .min = .{
                .major = 6,
                .minor = 11,
                .patch = 5,
            },
            .max = .{
                .major = 6,
                .minor = 11,
                .patch = 5,
            },
        },
        .glibc = .{
            .major = 2,
            .minor = 28,
            .patch = 0,
        },
    }},
};
pub const target: std.Target = .{
    .cpu = cpu,
    .os = os,
    .abi = abi,
    .ofmt = object_format,
    .dynamic_linker = std.Target.DynamicLinker.none,
};

But if I replace env with x86_64-pc-linux-musl-gcc, this part changes:

pub const target: std.Target = .{
    .cpu = cpu,
    .os = os,
    .abi = abi,
    .ofmt = object_format,
    .dynamic_linker = std.Target.DynamicLinker.init("/lib/ld-musl-x86_64.so.1"),
};

I assume result above is what you want?

@Ogromny
Copy link
Contributor Author

Ogromny commented Nov 17, 2024

I guess it's similar reason as in #21941 (comment) :

Yes, because it checks /usr/bin/env or its interpreter (/usr/bin/coreutils, /bin/sh) to find out libc, and if you compile it statically, it would assume that whole system is static -> musl needed.

In kiss-chroot-24.06.14-2:

$ file usr/bin/env
usr/bin/env: symbolic link to busybox

$ file usr/bin/busybox
usr/bin/busybox: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

$ file usr/bin/x86_64-pc-linux-musl-gcc
usr/bin/x86_64-pc-linux-musl-gcc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, stripped

So if you start zig build-exe --show-builtin:

pub const abi = std.Target.Abi.musl;
// ...
pub const os = std.Target.Os{
    .tag = .linux,
    .version_range = .{ .linux = .{
        .range = .{
            .min = .{
                .major = 6,
                .minor = 11,
                .patch = 5,
            },
            .max = .{
                .major = 6,
                .minor = 11,
                .patch = 5,
            },
        },
        .glibc = .{
            .major = 2,
            .minor = 28,
            .patch = 0,
        },
    }},
};
pub const target: std.Target = .{
    .cpu = cpu,
    .os = os,
    .abi = abi,
    .ofmt = object_format,
    .dynamic_linker = std.Target.DynamicLinker.none,
};

But if I replace env with x86_64-pc-linux-musl-gcc, this part changes:

pub const target: std.Target = .{
    .cpu = cpu,
    .os = os,
    .abi = abi,
    .ofmt = object_format,
    .dynamic_linker = std.Target.DynamicLinker.init("/lib/ld-musl-x86_64.so.1"),
};

I assume result above is what you want?

Yes, this is exactly what I want, a workaround for this issue is to simply manually set the dynamic_linker as you shown in the build.zig like this:

const std = @import("std");

pub fn build(b: *std.Build) void {
    b.host.query.dynamic_linker = std.Target.DynamicLinker.init("/usr/lib/ld-musl-x86_64.so.1");
    const exe = b.addExecutable(.{
        .name = "hello",
        .root_source_file = b.path("main.zig"),
        .target = b.host,
        .optimize = .Debug,
    });
    exe.linkLibC();
    b.installArtifact(exe);
}

@BratishkaErik
Copy link
Contributor

Yes, this is exactly what I want, a workaround for this issue is to simply manually set the dynamic_linker as you shown in the build.zig like this:

As an easier alternative, you can pass zig build -Ddynamic-linker=/usr/lib/... in projects that use b.standardTargetOptions in their build.zig, same way as you passed --dynamic-linker /usr/lib/ld-musl-x86_64.so.1 in zig build-exe

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
Projects
None yet
Development

No branches or pull requests

3 participants