From bf31c9505cab00ec9ec80c845dac5571d52f6100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 6 Oct 2024 22:47:46 +0200 Subject: [PATCH 1/5] test: Add some missing android, haiku, illumos, solaris triples to llvm_targets. --- test/llvm_targets.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig index fe62369311..15ff356fd3 100644 --- a/test/llvm_targets.zig +++ b/test/llvm_targets.zig @@ -249,10 +249,12 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .s390x, .os_tag = .zos, .abi = .none }, .{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .sparc, .os_tag = .illumos, .abi = .none }, .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu }, .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none }, .{ .cpu_arch = .sparc, .os_tag = .netbsd, .abi = .none }, .{ .cpu_arch = .sparc, .os_tag = .rtems, .abi = .none }, + .{ .cpu_arch = .sparc, .os_tag = .solaris, .abi = .none }, .{ .cpu_arch = .sparc64, .os_tag = .freebsd, .abi = .none }, .{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none }, @@ -269,6 +271,9 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .thumb, .os_tag = .freebsd, .abi = .eabihf }, .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabi }, .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabihf }, + .{ .cpu_arch = .thumb, .os_tag = .haiku, .abi = .eabi }, + .{ .cpu_arch = .thumb, .os_tag = .haiku, .abi = .eabihf }, + .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .androideabi }, .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabi }, .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabihf }, .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .musleabi }, @@ -314,6 +319,7 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .haiku, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .hurd, .abi = .gnu }, + .{ .cpu_arch = .x86, .os_tag = .illumos, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .android }, .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .gnu }, .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .musl }, @@ -322,6 +328,7 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .x86, .os_tag = .netbsd, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .openbsd, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .rtems, .abi = .none }, + .{ .cpu_arch = .x86, .os_tag = .solaris, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none }, .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu }, .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .itanium }, From f02d25d883cb5e9d9487e25ed9241c6c13bc1f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Oct 2024 00:16:27 +0200 Subject: [PATCH 2/5] std.Target: Implement DynamicLinker.kind() function. This helps callers of DynamicLinker.standard() make informed decisions about the usefulness of the returned value. --- lib/std/Target.zig | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/lib/std/Target.zig b/lib/std/Target.zig index def304bc6c..32b8525c08 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -2009,6 +2009,75 @@ pub const DynamicLinker = struct { return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]); } + pub const Kind = enum { + /// No dynamic linker. + none, + /// Dynamic linker path is determined by the arch/OS components. + arch_os, + /// Dynamic linker path is determined by the arch/OS/ABI components. + arch_os_abi, + }; + + pub fn kind(os: Os.Tag) Kind { + return switch (os) { + .fuchsia, + + .haiku, + .serenity, + + .dragonfly, + .freebsd, + .netbsd, + .openbsd, + + .bridgeos, + .driverkit, + .ios, + .macos, + .tvos, + .visionos, + .watchos, + + .illumos, + .solaris, + => .arch_os, + .hurd, + .linux, + => .arch_os_abi, + .freestanding, + .other, + + .contiki, + .elfiamcu, + .hermit, + + .aix, + .plan9, + .rtems, + .zos, + + .uefi, + .windows, + + .emscripten, + .wasi, + + .amdhsa, + .amdpal, + .cuda, + .mesa3d, + .nvcl, + .opencl, + .opengl, + .vulkan, + + .ps3, + .ps4, + .ps5, + => .none, + }; + } + pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker { return switch (os.tag) { .fuchsia => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename. From 27c85e5969f01853b2437d56ddc7a7eee9bf35d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Oct 2024 00:21:02 +0200 Subject: [PATCH 3/5] std.Target: Remove hasDynamicLinker() in favor of DynamicLinker.kind(). hasDynamicLinker() was just kind of lying in the case of Darwin platforms for the benefit of std.zig.system.detectAbiAndDynamicLinker(). A better name would have been hasElfDynamicLinker() or something. It also got the answer wrong for a bunch of platforms that don't actually use ELF. Anyway, this was clearly the wrong layer to do this at, so remove this function and instead use DynamicLinker.kind() + an isDarwin() check in detectAbiAndDynamicLinker(). --- lib/std/Target.zig | 24 ------------------------ lib/std/zig/system.zig | 5 +++-- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 32b8525c08..1d037d864e 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -1939,30 +1939,6 @@ pub inline fn floatAbi(target: Target) FloatAbi { return target.abi.floatAbi(); } -pub inline fn hasDynamicLinker(target: Target) bool { - if (target.cpu.arch.isWasm()) { - return false; - } - switch (target.os.tag) { - .freestanding, - .ios, - .tvos, - .watchos, - .macos, - .visionos, - .uefi, - .windows, - .emscripten, - .opencl, - .opengl, - .vulkan, - .plan9, - .other, - => return false, - else => return true, - } -} - pub const DynamicLinker = struct { /// Contains the memory used to store the dynamic linker path. This field /// should not be used directly. See `get` and `set`. This field exists so diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index d1967877b3..a33200b50c 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -963,14 +963,15 @@ fn detectAbiAndDynamicLinker( os: Target.Os, query: Target.Query, ) DetectError!Target { - const native_target_has_ld = comptime builtin.target.hasDynamicLinker(); + const native_target_has_ld = comptime Target.DynamicLinker.kind(builtin.os.tag) != .none; const is_linux = builtin.target.os.tag == .linux; const is_solarish = builtin.target.os.tag.isSolarish(); + const is_darwin = builtin.target.os.tag.isDarwin(); const have_all_info = query.dynamic_linker.get() != null and query.abi != null and (!is_linux or query.abi.?.isGnu()); const os_is_non_native = query.os_tag != null; // The Solaris/illumos environment is always the same. - if (!native_target_has_ld or have_all_info or os_is_non_native or is_solarish) { + if (!native_target_has_ld or have_all_info or os_is_non_native or is_solarish or is_darwin) { return defaultAbiAndDynamicLinker(cpu, os, query); } if (query.abi) |abi| { From 8818dc62131979cb29efe7a9f2a2ebd17583cd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Oct 2024 00:29:57 +0200 Subject: [PATCH 4/5] std.zig.system: Fix detectAbiAndDynamicLinker() for non-Linux/Hurd ELF hosts. Since we exclude Abi.none from the list of ABIs to be tested, it means that Abi.gnu, which happens to be the first in the list, always gets picked for hosts where the dynamic linker path does not depend on the ABI component of the triple. Such hosts include all the BSDs, Haiku, Serenity, Solaris, etc. To fix this, use DynamicLinker.kind() to determine whether this whole exercise even makes sense. If it doesn't, as is the case on every OS other than Linux and Hurd, we'll just fall back to Abi.default() which will try to pick a sensible default based on the arch and OS components. This detection logic still has plenty of room for improvement, but is at least a notable step up from confusingly detecting Abi.gnu ~everywhere. Closes #9089. --- lib/std/zig/system.zig | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index a33200b50c..b96cf9b276 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -996,26 +996,33 @@ fn detectAbiAndDynamicLinker( }; var ld_info_list_buffer: [all_abis.len]LdInfo = undefined; var ld_info_list_len: usize = 0; - const ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch); - for (all_abis) |abi| { - // This may be a nonsensical parameter. We detect this with - // error.UnknownDynamicLinkerPath and skip adding it to `ld_info_list`. - const target: Target = .{ - .cpu = cpu, - .os = os, - .abi = abi, - .ofmt = ofmt, - }; - const ld = target.standardDynamicLinkerPath(); - if (ld.get() == null) continue; + switch (Target.DynamicLinker.kind(os.tag)) { + // The OS has no dynamic linker. Leave the list empty and rely on `Abi.default()` to pick + // something sensible in `abiAndDynamicLinkerFromFile()`. + .none => {}, + // The OS has a system-wide dynamic linker. Unfortunately, this implies that there's no + // useful ABI information that we can glean from it merely being present. That means the + // best we can do for this case (for now) is also `Abi.default()`. + .arch_os => {}, + // The OS can have different dynamic linker paths depending on libc/ABI. In this case, we + // need to gather all the valid arch/OS/ABI combinations. `abiAndDynamicLinkerFromFile()` + // will then look for a dynamic linker with a matching path on the system and pick the ABI + // we associated it with here. + .arch_os_abi => for (all_abis) |abi| { + const ld = Target.DynamicLinker.standard(cpu, os, abi); - ld_info_list_buffer[ld_info_list_len] = .{ - .ld = ld, - .abi = abi, - }; - ld_info_list_len += 1; + // Does the generated target triple actually have a standard dynamic linker path? + if (ld.get() == null) continue; + + ld_info_list_buffer[ld_info_list_len] = .{ + .ld = ld, + .abi = abi, + }; + ld_info_list_len += 1; + }, } + const ld_info_list = ld_info_list_buffer[0..ld_info_list_len]; // Best case scenario: the executable is dynamically linked, and we can iterate From 059f18855f18f9dd76f74031381e04dd131da528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 7 Oct 2024 00:52:02 +0200 Subject: [PATCH 5/5] std.Target: Make DynamicLinker.standard() much stricter. Its semantics are now documented in terms of DynamicLinker.kind(os.tag). The idea here is two-fold: * The term "standard" actually means something; we shouldn't return a valid dynamic linker path for a triple for which it hasn't *actually* been standardized. That's just incorrect. For example, previously, this function would happily return a path for x86_64-linux-androideabi, csky-macos-gnu, or aarch64-hurd-msvc, and other such obvious nonsense. * Callers that use the return value from this function to do host probing (such as std.zig.system.detectAbiAndDynamicLinker()) can now do so with greater confidence because DynamicLinker.standard() will eagerly reject nonsensical target triples. --- lib/std/Target.zig | 438 +++++++++++++++++++++++++++------------------ 1 file changed, 259 insertions(+), 179 deletions(-) diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 1d037d864e..ec08879990 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -2054,209 +2054,237 @@ pub const DynamicLinker = struct { }; } + /// The strictness of this function depends on the value of `kind(os.tag)`: + /// + /// * `.none`: Ignores all arguments and just returns `none`. + /// * `.arch_os`: Ignores `abi` and returns the dynamic linker matching `cpu` and `os`. + /// * `.arch_os_abi`: Returns the dynamic linker matching `cpu`, `os`, and `abi`. + /// + /// In the case of `.arch_os` in particular, callers should be aware that a valid dynamic linker + /// being returned only means that the `cpu` + `os` combination represents a platform that + /// actually exists and which has an established dynamic linker path that does not change with + /// the ABI; it does not necessarily mean that `abi` makes any sense at all for that platform. + /// The responsibility for determining whether `abi` is valid in this case rests with the + /// caller. `Abi.default()` can be used to pick a best-effort default ABI for such platforms. pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker { return switch (os.tag) { - .fuchsia => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename. + .fuchsia => switch (cpu.arch) { + .aarch64, + .riscv64, + .x86_64, + => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename. + else => none, + }, - .haiku => init("/system/runtime_loader"), + .haiku => switch (cpu.arch) { + .arm, + .thumb, + .aarch64, + .m68k, + .powerpc, + .riscv64, + .sparc64, + .x86, + .x86_64, + => init("/system/runtime_loader"), + else => none, + }, .hurd => switch (cpu.arch) { .aarch64, .aarch64_be, => |arch| initFmt("/lib/ld-{s}{s}.so.1", .{ @tagName(arch), - if (abi == .gnuilp32) "_ilp32" else "", + switch (abi) { + .gnu => "", + .gnuilp32 => "_ilp32", + else => return none, + }, }), - .x86 => init("/lib/ld.so.1"), - .x86_64 => initFmt("/lib/ld-{s}.so.1", .{if (abi == .gnux32) "x32" else "x86-64"}), + .x86 => if (abi == .gnu) init("/lib/ld.so.1") else none, + .x86_64 => initFmt("/lib/ld-{s}.so.1", .{switch (abi) { + .gnu => "x86-64", + .gnux32 => "x32", + else => return none, + }}), - // These are unsupported by Hurd/glibc. - .amdgcn, - .arc, - .arm, - .armeb, - .thumb, - .thumbeb, - .avr, - .bpfel, - .bpfeb, - .csky, - .hexagon, - .kalimba, - .lanai, - .loongarch32, - .loongarch64, - .m68k, - .mips, - .mipsel, - .mips64, - .mips64el, - .msp430, - .nvptx, - .nvptx64, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .propeller1, - .propeller2, - .riscv32, - .riscv64, - .s390x, - .sparc, - .sparc64, - .spirv, - .spirv32, - .spirv64, - .spu_2, - .ve, - .wasm32, - .wasm64, - .xcore, - .xtensa, - => none, + else => none, }, .linux => if (abi.isAndroid()) - initFmt("/system/bin/linker{s}", .{if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else ""}) + switch (cpu.arch) { + .arm, + .thumb, + => if (abi == .androideabi) init("/system/bin/linker") else none, + + .aarch64, + .riscv64, + .x86, + .x86_64, + => if (abi == .android) initFmt("/system/bin/linker{s}", .{ + if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "", + }) else none, + + else => none, + } else if (abi.isMusl()) switch (cpu.arch) { .arm, .armeb, .thumb, .thumbeb, + => |arch| initFmt("/lib/ld-musl-arm{s}{s}.so.1", .{ + if (arch == .armeb or arch == .thumbeb) "eb" else "", + switch (abi) { + .musleabi => "", + .musleabihf => "hf", + else => return none, + }, + }), + .aarch64, .aarch64_be, - .loongarch64, + .loongarch64, // TODO: `-sp` and `-sf` ABI support in LLVM 20. .m68k, - .powerpc, .powerpc64, .powerpc64le, - .riscv32, - .riscv64, .s390x, - .x86, - .x86_64, - => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{ - switch (arch) { - .thumb => "arm", - .thumbeb => "armeb", - .x86 => "i386", - .x86_64 => if (abi == .muslx32) "x32" else "x86_64", - else => @tagName(arch), - }, - switch (arch) { - .arm, .armeb, .thumb, .thumbeb => if (abi.floatAbi() == .hard) "hf" else "", - .aarch64, .aarch64_be => if (abi == .gnuilp32) "_ilp32" else "", - .riscv32, .riscv64 => if (std.Target.riscv.featureSetHas(cpu.features, .d)) - "" - else if (std.Target.riscv.featureSetHas(cpu.features, .f)) - "-sp" - else - "-sf", - else => if (abi.floatAbi() == .soft) "-sf" else "", - }, - }), + => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}.so.1", .{@tagName(arch)}) else none, - // The naming scheme for MIPS is a bit irregular. .mips, .mipsel, - .mips64, - .mips64el, - => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}{s}.so.1", .{ - if (arch.isMIPS64()) "64" else "", // TODO: `n32` ABI support in LLVM 20. - if (mips.featureSetHas(cpu.features, if (arch.isMIPS64()) .mips64r6 else .mips32r6)) "r6" else "", - if (arch.endian() == .little) "el" else "", - if (abi.floatAbi() == .soft) "-sf" else "", + => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{ + if (mips.featureSetHas(cpu.features, .mips32r6)) "r6" else "", + if (arch == .mipsel) "el" else "", + switch (abi) { + .musleabi => "-sf", + .musleabihf => "", + else => return none, + }, }), - // These are unsupported by musl. - .amdgcn, - .arc, - .avr, - .csky, - .bpfel, - .bpfeb, - .hexagon, - .kalimba, - .lanai, - .loongarch32, - .msp430, - .nvptx, - .nvptx64, - .powerpcle, - .propeller1, - .propeller2, - .sparc, - .sparc64, - .spirv, - .spirv32, - .spirv64, - .spu_2, - .ve, - .wasm32, - .wasm64, - .xcore, - .xtensa, - => none, + .mips64, + .mips64el, + => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{ + // TODO: `n32` ABI support in LLVM 20. + switch (abi) { + .musl => "64", + else => return none, + }, + if (mips.featureSetHas(cpu.features, .mips64r6)) "r6" else "", + if (arch == .mips64el) "el" else "", + }), + + .powerpc => initFmt("/lib/ld-musl-powerpc{s}.so.1", .{switch (abi) { + .musleabi => "-sf", + .musleabihf => "", + else => return none, + }}), + + .riscv32, + .riscv64, + => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}{s}.so.1", .{ + @tagName(arch), + if (riscv.featureSetHas(cpu.features, .d)) + "" + else if (riscv.featureSetHas(cpu.features, .f)) + "-sp" + else + "-sf", + }) else none, + + .x86 => if (abi == .musl) init("/lib/ld-musl-i386.so.1") else none, + .x86_64 => initFmt("/lib/ld-musl-{s}.so.1", .{switch (abi) { + .musl => "x86_64", + .muslx32 => "x32", + else => return none, + }}), + + else => none, } else if (abi.isGnu()) switch (cpu.arch) { // TODO: `eb` architecture support. // TODO: `700` ABI support. - .arc => init("/lib/ld-linux-arc.so.2"), + .arc => if (abi == .gnu) init("/lib/ld-linux-arc.so.2") else none, // TODO: OABI support (`/lib/ld-linux.so.2`). .arm, .armeb, .thumb, .thumbeb, - => initFmt("/lib/ld-linux{s}.so.3", .{if (abi.floatAbi() == .hard) "-armhf" else ""}), + => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi) { + .gnueabi => "", + .gnueabihf => "-armhf", + else => return none, + }}), .aarch64, .aarch64_be, => |arch| initFmt("/lib/ld-linux-{s}{s}.so.1", .{ @tagName(arch), - if (abi == .gnuilp32) "_ilp32" else "", + switch (abi) { + .gnu => "", + .gnuilp32 => "_ilp32", + else => return none, + }, }), // TODO: `-be` architecture support. - .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{if (abi.floatAbi() == .hard) "-hf" else ""}), - - .loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) { - .gnuf32 => "lp64f", - .gnusf => "lp64s", - else => "lp64d", + .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{switch (abi) { + .gnueabi => "", + .gnueabihf => "-hf", + else => return none, }}), - .m68k => init("/lib/ld.so.1"), + .loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) { + .gnu => "lp64d", + .gnuf32 => "lp64f", + .gnusf => "lp64s", + else => return none, + }}), + + .m68k => if (abi == .gnu) init("/lib/ld.so.1") else none, .mips, .mipsel, + => switch (abi) { + .gnueabi, + .gnueabihf, + => initFmt("/lib/ld{s}.so.1", .{ + if (mips.featureSetHas(cpu.features, .nan2008)) "-linux-mipsn8" else "", + }), + else => none, + }, + .mips64, .mips64el, => initFmt("/lib{s}/ld{s}.so.1", .{ switch (abi) { - .gnuabin32 => "32", .gnuabi64 => "64", - else => "", + .gnuabin32 => "32", + else => return none, }, if (mips.featureSetHas(cpu.features, .nan2008)) "-linux-mipsn8" else "", }), - .powerpc => init("/lib/ld.so.1"), - // TODO: ELFv2 ABI opt-in support. - .powerpc64 => init("/lib64/ld64.so.1"), - .powerpc64le => init("/lib64/ld64.so.2"), + .powerpc => switch (abi) { + .gnueabi, + .gnueabihf, + => init("/lib/ld.so.1"), + else => none, + }, + // TODO: ELFv2 ABI (`/lib64/ld64.so.2`) opt-in support. + .powerpc64 => if (abi == .gnu) init("/lib64/ld64.so.1") else none, + .powerpc64le => if (abi == .gnu) init("/lib64/ld64.so.2") else none, .riscv32, .riscv64, - => |arch| initFmt("/lib/ld-linux-{s}-{s}{s}.so.1", .{ - @tagName(arch), + => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}{s}.so.1", .{ switch (arch) { - .riscv32 => "ilp32", - .riscv64 => "lp64", + .riscv32 => "riscv32-ilp32", + .riscv64 => "riscv64-lp64", else => unreachable, }, if (riscv.featureSetHas(cpu.features, .d)) @@ -2265,78 +2293,130 @@ pub const DynamicLinker = struct { "f" else "", - }), + }) else none, - .s390x => init("/lib/ld64.so.1"), + .s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none, - .sparc => init("/lib/ld-linux.so.2"), - .sparc64 => init("/lib64/ld-linux.so.2"), + .sparc => if (abi == .gnu) init("/lib/ld-linux.so.2") else none, + .sparc64 => if (abi == .gnu) init("/lib64/ld-linux.so.2") else none, - .x86 => init("/lib/ld-linux.so.2"), - .x86_64 => init(if (abi == .gnux32) "/libx32/ld-linux-x32.so.2" else "/lib64/ld-linux-x86-64.so.2"), + .x86 => if (abi == .gnu) init("/lib/ld-linux.so.2") else none, + .x86_64 => switch (abi) { + .gnu => init("/lib64/ld-linux-x86-64.so.2"), + .gnux32 => init("/libx32/ld-linux-x32.so.2"), + else => none, + }, - .xtensa => init("/lib/ld.so.1"), + .xtensa => if (abi == .gnu) init("/lib/ld.so.1") else none, - // These are unsupported by glibc. - .amdgcn, - .avr, - .bpfeb, - .bpfel, - .hexagon, - .kalimba, - .lanai, - .loongarch32, - .msp430, - .nvptx, - .nvptx64, - .powerpcle, - .propeller1, - .propeller2, - .spirv, - .spirv32, - .spirv64, - .spu_2, - .ve, - .wasm32, - .wasm64, - .xcore, - => none, + else => none, } else none, // Not a known Linux libc. - .serenity => init("/usr/lib/Loader.so"), + .serenity => switch (cpu.arch) { + .aarch64, + .riscv64, + .x86_64, + => init("/usr/lib/Loader.so"), + else => none, + }, - .dragonfly => initFmt("{s}/libexec/ld-elf.so.2", .{ + .dragonfly => if (cpu.arch == .x86_64) initFmt("{s}/libexec/ld-elf.so.2", .{ if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false) "" else "/usr", - }), + }) else none, - .freebsd => initFmt("{s}/libexec/ld-elf.so.1", .{ - if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false) - "" - else - "/usr", - }), + .freebsd => switch (cpu.arch) { + .arm, + .armeb, + .thumb, + .thumbeb, + .aarch64, + .mips, + .mipsel, + .mips64, + .mips64el, + .powerpc, + .powerpc64, + .powerpc64le, + .riscv64, + .sparc64, + .x86, + .x86_64, + => initFmt("{s}/libexec/ld-elf.so.1", .{ + if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false) + "" + else + "/usr", + }), + else => none, + }, - .netbsd => init("/libexec/ld.elf_so"), + .netbsd => switch (cpu.arch) { + .arm, + .armeb, + .thumb, + .thumbeb, + .aarch64, + .aarch64_be, + .m68k, + .mips, + .mipsel, + .mips64, + .mips64el, + .powerpc, + .riscv64, + .sparc, + .sparc64, + .x86, + .x86_64, + => init("/libexec/ld.elf_so"), + else => none, + }, - .openbsd => init("/usr/libexec/ld.so"), + .openbsd => switch (cpu.arch) { + .arm, + .thumb, + .aarch64, + .mips64, + .mips64el, + .powerpc, + .powerpc64, + .riscv64, + .sparc64, + .x86, + .x86_64, + => init("/usr/libexec/ld.so"), + else => none, + }, - .bridgeos, + .bridgeos => if (cpu.arch == .aarch64) init("/usr/lib/dyld") else none, .driverkit, .ios, .macos, .tvos, .visionos, .watchos, - => init("/usr/lib/dyld"), + => switch (cpu.arch) { + .aarch64, + .x86_64, + => init("/usr/lib/dyld"), + else => none, + }, .illumos, .solaris, - => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64/" else ""}), + => switch (cpu.arch) { + .sparc, + .sparc64, + .x86, + .x86_64, + => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, .none) == 64) "64/" else ""}), + else => none, + }, // Operating systems in this list have been verified as not having a standard // dynamic linker path.