diff options
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/build.zig | 12 | ||||
| -rw-r--r-- | lib/std/target.zig | 92 | ||||
| -rw-r--r-- | lib/std/zig/cross_target.zig | 17 | ||||
| -rw-r--r-- | lib/std/zig/system.zig | 77 |
4 files changed, 108 insertions, 90 deletions
diff --git a/lib/std/build.zig b/lib/std/build.zig index 7852828f7c..3ca59ae4cb 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1177,8 +1177,6 @@ pub const LibExeObjStep = struct { /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`. glibc_multi_install_dir: ?[]const u8 = null, - dynamic_linker: ?[]const u8 = null, - /// Position Independent Code force_pic: ?bool = null, @@ -1978,6 +1976,11 @@ pub const LibExeObjStep = struct { } try zig_args.append(mcpu_buffer.toSliceConst()); } + + if (self.target.dynamic_linker.get()) |dynamic_linker| { + try zig_args.append("--dynamic-linker"); + try zig_args.append(dynamic_linker); + } } if (self.linker_script) |linker_script| { @@ -1985,11 +1988,6 @@ pub const LibExeObjStep = struct { zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable; } - if (self.dynamic_linker) |dynamic_linker| { - try zig_args.append("--dynamic-linker"); - try zig_args.append(dynamic_linker); - } - if (self.version_script) |version_script| { try zig_args.append("--version-script"); try zig_args.append(builder.pathFromRoot(version_script)); diff --git a/lib/std/target.zig b/lib/std/target.zig index 6ecb679f29..3054c60467 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1099,16 +1099,52 @@ pub const Target = struct { } } + 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 that this API requires no allocator. + buffer: [255]u8 = undefined, + + /// Used to construct the dynamic linker path. This field should not be used + /// directly. See `get` and `set`. + max_byte: ?u8 = null, + + /// Asserts that the length is less than or equal to 255 bytes. + pub fn init(dl_or_null: ?[]const u8) DynamicLinker { + var result: DynamicLinker = undefined; + result.set(dl_or_null); + return result; + } + + /// The returned memory has the same lifetime as the `DynamicLinker`. + pub fn get(self: *const DynamicLinker) ?[]const u8 { + const m: usize = self.max_byte orelse return null; + return self.buffer[0 .. m + 1]; + } + + /// Asserts that the length is less than or equal to 255 bytes. + pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void { + if (dl_or_null) |dl| { + mem.copy(u8, &self.buffer, dl); + self.max_byte = @intCast(u8, dl.len - 1); + } else { + self.max_byte = null; + } + } + }; + /// The result will be a byte index *pointing at the final byte*. In other words, length minus one. /// A return value of `null` means the concept of a dynamic linker is not meaningful for that target. - pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?u8 { + pub fn standardDynamicLinkerPath(self: Target) DynamicLinker { + var result: DynamicLinker = .{}; const S = struct { - fn print(b: *[255]u8, comptime fmt: []const u8, args: var) u8 { - return @intCast(u8, (std.fmt.bufPrint(b, fmt, args) catch unreachable).len - 1); + fn print(r: *DynamicLinker, comptime fmt: []const u8, args: var) DynamicLinker { + r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1); + return r.*; } - fn copy(b: *[255]u8, s: []const u8) u8 { - mem.copy(u8, b, s); - return @intCast(u8, s.len - 1); + fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker { + mem.copy(u8, &r.buffer, s); + r.max_byte = @intCast(u8, s.len - 1); + return r.*; } }; const print = S.print; @@ -1116,7 +1152,7 @@ pub const Target = struct { if (self.isAndroid()) { const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else ""; - return print(buffer, "/system/bin/linker{}", .{suffix}); + return print(&result, "/system/bin/linker{}", .{suffix}); } if (self.isMusl()) { @@ -1130,28 +1166,28 @@ pub const Target = struct { else => |arch| @tagName(arch), }; const arch_suffix = if (is_arm and self.getFloatAbi() == .hard) "hf" else ""; - return print(buffer, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix }); + return print(&result, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix }); } switch (self.os.tag) { - .freebsd => return copy(buffer, "/libexec/ld-elf.so.1"), - .netbsd => return copy(buffer, "/libexec/ld.elf_so"), - .dragonfly => return copy(buffer, "/libexec/ld-elf.so.2"), + .freebsd => return copy(&result, "/libexec/ld-elf.so.1"), + .netbsd => return copy(&result, "/libexec/ld.elf_so"), + .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"), .linux => switch (self.cpu.arch) { .i386, .sparc, .sparcel, - => return copy(buffer, "/lib/ld-linux.so.2"), + => return copy(&result, "/lib/ld-linux.so.2"), - .aarch64 => return copy(buffer, "/lib/ld-linux-aarch64.so.1"), - .aarch64_be => return copy(buffer, "/lib/ld-linux-aarch64_be.so.1"), - .aarch64_32 => return copy(buffer, "/lib/ld-linux-aarch64_32.so.1"), + .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"), + .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"), + .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"), .arm, .armeb, .thumb, .thumbeb, - => return copy(buffer, switch (self.getFloatAbi()) { + => return copy(&result, switch (self.getFloatAbi()) { .hard => "/lib/ld-linux-armhf.so.3", else => "/lib/ld-linux.so.3", }), @@ -1168,20 +1204,20 @@ pub const Target = struct { }; const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008); const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1"; - return print(buffer, "/lib{}/{}", .{ lib_suffix, loader }); + return print(&result, "/lib{}/{}", .{ lib_suffix, loader }); }, - .powerpc => return copy(buffer, "/lib/ld.so.1"), - .powerpc64, .powerpc64le => return copy(buffer, "/lib64/ld64.so.2"), - .s390x => return copy(buffer, "/lib64/ld64.so.1"), - .sparcv9 => return copy(buffer, "/lib64/ld-linux.so.2"), - .x86_64 => return copy(buffer, switch (self.abi) { + .powerpc => return copy(&result, "/lib/ld.so.1"), + .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"), + .s390x => return copy(&result, "/lib64/ld64.so.1"), + .sparcv9 => return copy(&result, "/lib64/ld-linux.so.2"), + .x86_64 => return copy(&result, switch (self.abi) { .gnux32 => "/libx32/ld-linux-x32.so.2", else => "/lib64/ld-linux-x86-64.so.2", }), - .riscv32 => return copy(buffer, "/lib/ld-linux-riscv32-ilp32.so.1"), - .riscv64 => return copy(buffer, "/lib/ld-linux-riscv64-lp64.so.1"), + .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"), + .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"), // Architectures in this list have been verified as not having a standard // dynamic linker path. @@ -1191,7 +1227,7 @@ pub const Target = struct { .bpfeb, .nvptx, .nvptx64, - => return null, + => return result, // TODO go over each item in this list and either move it to the above list, or // implement the standard dynamic linker path code for it. @@ -1217,7 +1253,7 @@ pub const Target = struct { .lanai, .renderscript32, .renderscript64, - => return null, + => return result, }, // Operating systems in this list have been verified as not having a standard @@ -1232,7 +1268,7 @@ pub const Target = struct { .emscripten, .wasi, .other, - => return null, + => return result, // TODO go over each item in this list and either move it to the above list, or // implement the standard dynamic linker path code for it. @@ -1259,7 +1295,7 @@ pub const Target = struct { .amdpal, .hermit, .hurd, - => return null, + => return result, } } }; diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig index c7fd1f0464..212bc8eb9a 100644 --- a/lib/std/zig/cross_target.zig +++ b/lib/std/zig/cross_target.zig @@ -40,6 +40,10 @@ pub const CrossTarget = struct { /// If `isGnuLibC()` is `false`, this must be `null` and is ignored. glibc_version: ?SemVer = null, + /// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path + /// based on the `os_tag`. + dynamic_linker: DynamicLinker = DynamicLinker{}, + pub const OsVersion = union(enum) { none: void, semver: SemVer, @@ -48,6 +52,8 @@ pub const CrossTarget = struct { pub const SemVer = std.builtin.Version; + pub const DynamicLinker = Target.DynamicLinker; + pub fn fromTarget(target: Target) CrossTarget { var result: CrossTarget = .{ .cpu_arch = target.cpu.arch, @@ -170,6 +176,10 @@ pub const CrossTarget = struct { /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline". cpu_features: ?[]const u8 = null, + /// Absolute path to dynamic linker, to override the default, which is either a natively + /// detected path, or a standard path. + dynamic_linker: ?[]const u8 = null, + /// If this is provided, the function will populate some information about parsing failures, /// so that user-friendly error messages can be delivered. diagnostics: ?*Diagnostics = null, @@ -199,8 +209,9 @@ pub const CrossTarget = struct { var dummy_diags: ParseOptions.Diagnostics = undefined; const diags = args.diagnostics orelse &dummy_diags; - // Start with everything initialized to default values. - var result: CrossTarget = .{}; + var result: CrossTarget = .{ + .dynamic_linker = DynamicLinker.init(args.dynamic_linker), + }; var it = mem.separate(args.arch_os_abi, "-"); const arch_name = it.next().?; @@ -446,7 +457,7 @@ pub const CrossTarget = struct { return self.cpu_arch == null and self.cpu_model == null and self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty() and self.os_tag == null and self.os_version_min == null and self.os_version_max == null and - self.abi == null; + self.abi == null and self.dynamic_linker.get() == null; } pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![:0]u8 { diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index ffae5c6015..44ff9af674 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -168,14 +168,9 @@ pub const NativePaths = struct { pub const NativeTargetInfo = struct { target: Target, - /// Contains the memory used to store the dynamic linker path. This field should - /// not be used directly. See `dynamicLinker` and `setDynamicLinker`. This field - /// exists so that this API requires no allocator. - dynamic_linker_buffer: [255]u8 = undefined, + dynamic_linker: DynamicLinker = DynamicLinker{}, - /// Used to construct the dynamic linker path. This field should not be used - /// directly. See `dynamicLinker` and `setDynamicLinker`. - dynamic_linker_max: ?u8 = null, + pub const DynamicLinker = Target.DynamicLinker; pub const DetectError = error{ OutOfMemory, @@ -220,21 +215,6 @@ pub const NativeTargetInfo = struct { return detectAbiAndDynamicLinker(allocator, cpu, os); } - /// The returned memory has the same lifetime as the `NativeTargetInfo`. - pub fn dynamicLinker(self: *const NativeTargetInfo) ?[]const u8 { - const m: usize = self.dynamic_linker_max orelse return null; - return self.dynamic_linker_buffer[0 .. m + 1]; - } - - pub fn setDynamicLinker(self: *NativeTargetInfo, dl_or_null: ?[]const u8) void { - if (dl_or_null) |dl| { - mem.copy(u8, &self.dynamic_linker_buffer, dl); - self.dynamic_linker_max = @intCast(u8, dl.len - 1); - } else { - self.dynamic_linker_max = null; - } - } - /// First we attempt to use the executable's own binary. If it is dynamically /// linked, then it should answer both the C ABI question and the dynamic linker question. /// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then @@ -273,15 +253,14 @@ pub const NativeTargetInfo = struct { .os = os, .abi = abi, }; - const ld_info = &ld_info_list_buffer[ld_info_list_len]; - ld_info_list_len += 1; + const ld = target.standardDynamicLinkerPath(); + if (ld.get() == null) continue; - ld_info.* = .{ - .ld_path_buffer = undefined, - .ld_path_max = undefined, + ld_info_list_buffer[ld_info_list_len] = .{ + .ld = ld, .abi = abi, }; - ld_info.ld_path_max = target.standardDynamicLinkerPath(&ld_info.ld_path_buffer) orelse continue; + ld_info_list_len += 1; } const ld_info_list = ld_info_list_buffer[0..ld_info_list_len]; @@ -298,7 +277,7 @@ pub const NativeTargetInfo = struct { // This is O(N^M) but typical case here is N=2 and M=10. find_ld: for (lib_paths) |lib_path| { for (ld_info_list) |ld_info| { - const standard_ld_basename = fs.path.basename(ld_info.ldPath()); + const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) { found_ld_info = ld_info; found_ld_path = lib_path; @@ -329,8 +308,8 @@ pub const NativeTargetInfo = struct { .os = os_adjusted, .abi = found_ld_info.abi, }, + .dynamic_linker = DynamicLinker.init(found_ld_path), }; - result.setDynamicLinker(found_ld_path); return result; } @@ -472,18 +451,18 @@ pub const NativeTargetInfo = struct { elf.PT_INTERP => { const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); - if (p_filesz > result.dynamic_linker_buffer.len) return error.NameTooLong; - _ = try preadFull(env_file, result.dynamic_linker_buffer[0..p_filesz], p_offset, p_filesz); + if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; + _ = try preadFull(env_file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); // PT_INTERP includes a null byte in p_filesz. const len = p_filesz - 1; - // dynamic_linker_max is "max", not "len". - // We know it will fit in u8 because we check against dynamic_linker_buffer.len above. - result.dynamic_linker_max = @intCast(u8, len - 1); + // dynamic_linker.max_byte is "max", not "len". + // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. + result.dynamic_linker.max_byte = @intCast(u8, len - 1); // Use it to determine ABI. - const full_ld_path = result.dynamic_linker_buffer[0..len]; + const full_ld_path = result.dynamic_linker.buffer[0..len]; for (ld_info_list) |ld_info| { - const standard_ld_basename = fs.path.basename(ld_info.ldPath()); + const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { result.target.abi = ld_info.abi; break; @@ -679,26 +658,20 @@ pub const NativeTargetInfo = struct { } fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { - var result: NativeTargetInfo = .{ - .target = .{ - .cpu = cpu, - .os = os, - .abi = Target.Abi.default(cpu.arch, os), - }, + const target: Target = .{ + .cpu = cpu, + .os = os, + .abi = Target.Abi.default(cpu.arch, os), + }; + return NativeTargetInfo{ + .target = target, + .dynamic_linker = target.standardDynamicLinkerPath(), }; - result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer); - return result; } const LdInfo = struct { - ld_path_buffer: [255]u8, - ld_path_max: u8, + ld: DynamicLinker, abi: Target.Abi, - - pub fn ldPath(self: *const LdInfo) []const u8 { - const m: usize = self.ld_path_max; - return self.ld_path_buffer[0 .. m + 1]; - } }; fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { |
