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.