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.
This commit is contained in:
Alex Rønne Petersen 2024-10-07 00:52:02 +02:00
parent 8818dc6213
commit 059f18855f
No known key found for this signature in database

View File

@ -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.