authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-17 15:23:59-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-17 15:23:59-05:00
log2f9c5c0644dd516ec0d96f33333a35e6b4deea91
tree852e7d7273da760a3a36ea551343f5e01bfe8f5a
parentc784c52819e505620fb1fcb48e59a48c6d8f487e
signature Commit is signed but in an unrecognized format.

self-host dynamic linker detection


17 files changed, 430 insertions(+), 532 deletions(-)

lib/std/os.zig+18-14
......@@ -2974,18 +2974,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
29742974}
29752975
29762976pub fn dl_iterate_phdr(
2977 comptime T: type,
2978 callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32,
2979 data: ?*T,
2980) isize {
2977 context: var,
2978 comptime Error: type,
2979 comptime callback: fn (info: *dl_phdr_info, size: usize, context: @TypeOf(context)) Error!void,
2980) Error!void {
2981 const Context = @TypeOf(context);
2982
29812983 if (builtin.object_format != .elf)
29822984 @compileError("dl_iterate_phdr is not available for this target");
29832985
29842986 if (builtin.link_libc) {
2985 return system.dl_iterate_phdr(
2986 @ptrCast(std.c.dl_iterate_phdr_callback, callback),
2987 @ptrCast(?*c_void, data),
2988 );
2987 switch (system.dl_iterate_phdr(struct {
2988 fn callbackC(info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int {
2989 const context_ptr = @ptrCast(*const Context, @alignCast(@alignOf(*const Context), data));
2990 callback(info, size, context_ptr.*) catch |err| return @errorToInt(err);
2991 return 0;
2992 }
2993 }.callbackC, @intToPtr(?*c_void, @ptrToInt(&context)))) {
2994 0 => return,
2995 else => |err| return @errSetCast(Error, @intToError(@intCast(u16, err))), // TODO don't hardcode u16
2996 }
29892997 }
29902998
29912999 const elf_base = std.process.getBaseAddress();
......@@ -3007,11 +3015,10 @@ pub fn dl_iterate_phdr(
30073015 .dlpi_phnum = ehdr.e_phnum,
30083016 };
30093017
3010 return callback(&info, @sizeOf(dl_phdr_info), data);
3018 return callback(&info, @sizeOf(dl_phdr_info), context);
30113019 }
30123020
30133021 // Last return value from the callback function
3014 var last_r: isize = 0;
30153022 while (it.next()) |entry| {
30163023 var dlpi_phdr: [*]elf.Phdr = undefined;
30173024 var dlpi_phnum: u16 = undefined;
......@@ -3033,11 +3040,8 @@ pub fn dl_iterate_phdr(
30333040 .dlpi_phnum = dlpi_phnum,
30343041 };
30353042
3036 last_r = callback(&info, @sizeOf(dl_phdr_info), data);
3037 if (last_r != 0) break;
3043 try callback(&info, @sizeOf(dl_phdr_info), context);
30383044 }
3039
3040 return last_r;
30413045}
30423046
30433047pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
lib/std/process.zig+56
......@@ -613,3 +613,59 @@ pub fn getBaseAddress() usize {
613613 else => @compileError("Unsupported OS"),
614614 }
615615}
616
617/// Caller owns the result value and each inner slice.
618pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
619 switch (builtin.link_mode) {
620 .Static => return &[_][:0]u8{},
621 .Dynamic => {},
622 }
623 const List = std.ArrayList([:0]u8);
624 switch (builtin.os) {
625 .linux,
626 .freebsd,
627 .netbsd,
628 .dragonfly,
629 => {
630 var paths = List.init(allocator);
631 errdefer {
632 const slice = paths.toOwnedSlice();
633 for (slice) |item| {
634 allocator.free(item);
635 }
636 allocator.free(slice);
637 }
638 try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct {
639 fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void {
640 const name = info.dlpi_name orelse return;
641 if (name[0] == '/') {
642 const item = try mem.dupeZ(list.allocator, u8, mem.toSliceConst(u8, name));
643 errdefer list.allocator.free(item);
644 try list.append(item);
645 }
646 }
647 }.callback);
648 return paths.toOwnedSlice();
649 },
650 .macosx, .ios, .watchos, .tvos => {
651 var paths = List.init(allocator);
652 errdefer {
653 const slice = paths.toOwnedSlice();
654 for (slice) |item| {
655 allocator.free(item);
656 }
657 allocator.free(slice);
658 }
659 const img_count = std.c._dyld_image_count();
660 var i: u32 = 0;
661 while (i < img_count) : (i += 1) {
662 const name = std.c._dyld_get_image_name(i);
663 const item = try mem.dupeZ(allocator, u8, mem.toSliceConst(u8, name));
664 errdefer allocator.free(item);
665 try paths.append(item);
666 }
667 return paths.toOwnedSlice();
668 },
669 else => return error.UnimplementedSelfExeSharedPaths,
670 }
671}
lib/std/target.zig+137
......@@ -1037,6 +1037,13 @@ pub const Target = union(enum) {
10371037 };
10381038 }
10391039
1040 pub fn isAndroid(self: Target) bool {
1041 return switch (self.getAbi()) {
1042 .android => true,
1043 else => false,
1044 };
1045 }
1046
10401047 pub fn isDragonFlyBSD(self: Target) bool {
10411048 return switch (self.getOs()) {
10421049 .dragonfly => true,
......@@ -1196,6 +1203,136 @@ pub const Target = union(enum) {
11961203
11971204 return .unavailable;
11981205 }
1206
1207 pub const FloatAbi = enum {
1208 hard,
1209 soft,
1210 soft_fp,
1211 };
1212
1213 pub fn getFloatAbi(self: Target) FloatAbi {
1214 return switch (self.getAbi()) {
1215 .gnueabihf,
1216 .eabihf,
1217 .musleabihf,
1218 => .hard,
1219 else => .soft,
1220 };
1221 }
1222
1223 /// Caller owns returned memory.
1224 pub fn getStandardDynamicLinkerPath(
1225 self: Target,
1226 allocator: *mem.Allocator,
1227 ) error{
1228 OutOfMemory,
1229 UnknownDynamicLinkerPath,
1230 }![:0]u8 {
1231 const a = allocator;
1232 if (self.isAndroid()) {
1233 return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
1234 "/system/bin/linker64"
1235 else
1236 "/system/bin/linker");
1237 }
1238
1239 if (self.isMusl()) {
1240 var result = try std.Buffer.init(allocator, "/lib/ld-musl-");
1241 defer result.deinit();
1242
1243 var is_arm = false;
1244 switch (self.getArch()) {
1245 .arm, .thumb => {
1246 try result.append("arm");
1247 is_arm = true;
1248 },
1249 .armeb, .thumbeb => {
1250 try result.append("armeb");
1251 is_arm = true;
1252 },
1253 else => |arch| try result.append(@tagName(arch)),
1254 }
1255 if (is_arm and self.getFloatAbi() == .hard) {
1256 try result.append("hf");
1257 }
1258 try result.append(".so.1");
1259 return result.toOwnedSlice();
1260 }
1261
1262 switch (self.getOs()) {
1263 .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
1264 .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
1265 .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
1266 .linux => switch (self.getArch()) {
1267 .i386,
1268 .sparc,
1269 .sparcel,
1270 => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),
1271
1272 .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),
1273 .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),
1274 .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),
1275
1276 .arm,
1277 .armeb,
1278 .thumb,
1279 .thumbeb,
1280 => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {
1281 .hard => "/lib/ld-linux-armhf.so.3",
1282 else => "/lib/ld-linux.so.3",
1283 }),
1284
1285 .mips,
1286 .mipsel,
1287 .mips64,
1288 .mips64el,
1289 => return error.UnknownDynamicLinkerPath,
1290
1291 .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
1292 .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
1293 .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
1294 .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
1295 .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {
1296 .gnux32 => "/libx32/ld-linux-x32.so.2",
1297 else => "/lib64/ld-linux-x86-64.so.2",
1298 }),
1299
1300 .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),
1301 .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),
1302
1303 .arc,
1304 .avr,
1305 .bpfel,
1306 .bpfeb,
1307 .hexagon,
1308 .msp430,
1309 .r600,
1310 .amdgcn,
1311 .tce,
1312 .tcele,
1313 .xcore,
1314 .nvptx,
1315 .nvptx64,
1316 .le32,
1317 .le64,
1318 .amdil,
1319 .amdil64,
1320 .hsail,
1321 .hsail64,
1322 .spir,
1323 .spir64,
1324 .kalimba,
1325 .shave,
1326 .lanai,
1327 .wasm32,
1328 .wasm64,
1329 .renderscript32,
1330 .renderscript64,
1331 => return error.UnknownDynamicLinkerPath,
1332 },
1333 else => return error.UnknownDynamicLinkerPath,
1334 }
1335 }
11991336};
12001337
12011338test "parseCpuFeatureSet" {
src-self-hosted/introspect.zig+8
......@@ -6,6 +6,14 @@ const fs = std.fs;
66
77const warn = std.debug.warn;
88
9pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 {
10 if (target == .Native) {
11 return @import("libc_installation.zig").detectNativeDynamicLinker(allocator);
12 } else {
13 return target.getStandardDynamicLinkerPath(allocator);
14 }
15}
16
917/// Caller must free result
1018pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
1119 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
src-self-hosted/libc_installation.zig+38-1
......@@ -492,7 +492,7 @@ pub const LibCInstallation = struct {
492492const default_cc_exe = if (is_windows) "cc.exe" else "cc";
493493
494494/// caller owns returned memory
495pub fn ccPrintFileName(
495fn ccPrintFileName(
496496 allocator: *Allocator,
497497 o_file: []const u8,
498498 want_dirname: enum { full_path, only_dir },
......@@ -535,6 +535,43 @@ pub fn ccPrintFileName(
535535 }
536536}
537537
538/// Caller owns returned memory.
539pub fn detectNativeDynamicLinker(allocator: *Allocator) ![:0]u8 {
540 const standard_ld_path = try std.Target.current.getStandardDynamicLinkerPath(allocator);
541 var standard_ld_path_resource: ?[:0]u8 = standard_ld_path; // Set to null to avoid freeing it.
542 defer if (standard_ld_path_resource) |s| allocator.free(s);
543
544 const standard_ld_basename = fs.path.basename(standard_ld_path);
545
546 {
547 // Best case scenario: the current executable is dynamically linked, and we can iterate
548 // over our own shared objects and find a dynamic linker.
549 const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
550 defer allocator.free(lib_paths);
551
552 for (lib_paths) |lib_path| {
553 if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
554 return std.mem.dupeZ(allocator, u8, lib_path);
555 }
556 }
557 }
558
559 // If Zig is statically linked, such as via distributed binary static builds, the above
560 // trick won't work. What are we left with? Try to run the system C compiler and get
561 // it to tell us the dynamic linker path.
562 return ccPrintFileName(allocator, standard_ld_basename, .full_path) catch |err| switch (err) {
563 error.OutOfMemory => return error.OutOfMemory,
564 error.LibCRuntimeNotFound,
565 error.CCompilerExitCode,
566 error.CCompilerCrashed,
567 error.UnableToSpawnCCompiler,
568 => {
569 standard_ld_path_resource = null; // Prevent freeing standard_ld_path.
570 return standard_ld_path;
571 },
572 };
573}
574
538575const Search = struct {
539576 path: []const u8,
540577 version: []const u8,
src-self-hosted/stage2.zig+90-13
......@@ -109,6 +109,7 @@ const Error = extern enum {
109109 LibCKernel32LibNotFound,
110110 UnsupportedArchitecture,
111111 WindowsSdkNotFound,
112 UnknownDynamicLinkerPath,
112113};
113114
114115const FILE = std.c.FILE;
......@@ -1012,24 +1013,100 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file:
10121013}
10131014
10141015// ABI warning
1015export fn stage2_libc_cc_print_file_name(
1016 out_ptr: *[*:0]u8,
1017 out_len: *usize,
1018 o_file: [*:0]const u8,
1019 want_dirname: bool,
1020) Error {
1021 const result = @import("libc_installation.zig").ccPrintFileName(
1016const Stage2Target = extern struct {
1017 arch: c_int,
1018 sub_arch: c_int,
1019 vendor: c_int,
1020 os: c_int,
1021 abi: c_int,
1022 glibc_version: ?*Stage2GLibCVersion, // null means default
1023 cpu_features: *Stage2CpuFeatures,
1024 is_native: bool,
1025};
1026
1027// ABI warning
1028const Stage2GLibCVersion = extern struct {
1029 major: u32,
1030 minor: u32,
1031 patch: u32,
1032};
1033
1034// ABI warning
1035export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error {
1036 const target: Target = if (in_target.is_native) .Native else .{
1037 .Cross = .{
1038 .arch = switch (enumInt(@TagType(Target.Arch), in_target.arch)) {
1039 .arm => .{ .arm = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
1040 .armeb => .{ .armeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
1041 .thumb => .{ .thumb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
1042 .thumbeb => .{ .thumbeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
1043
1044 .aarch64 => .{ .aarch64 = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
1045 .aarch64_be => .{ .aarch64_be = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
1046 .aarch64_32 => .{ .aarch64_32 = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
1047
1048 .kalimba => .{ .kalimba = enumInt(Target.Arch.Kalimba, in_target.sub_arch) },
1049
1050 .arc => .arc,
1051 .avr => .avr,
1052 .bpfel => .bpfel,
1053 .bpfeb => .bpfeb,
1054 .hexagon => .hexagon,
1055 .mips => .mips,
1056 .mipsel => .mipsel,
1057 .mips64 => .mips64,
1058 .mips64el => .mips64el,
1059 .msp430 => .msp430,
1060 .powerpc => .powerpc,
1061 .powerpc64 => .powerpc64,
1062 .powerpc64le => .powerpc64le,
1063 .r600 => .r600,
1064 .amdgcn => .amdgcn,
1065 .riscv32 => .riscv32,
1066 .riscv64 => .riscv64,
1067 .sparc => .sparc,
1068 .sparcv9 => .sparcv9,
1069 .sparcel => .sparcel,
1070 .s390x => .s390x,
1071 .tce => .tce,
1072 .tcele => .tcele,
1073 .i386 => .i386,
1074 .x86_64 => .x86_64,
1075 .xcore => .xcore,
1076 .nvptx => .nvptx,
1077 .nvptx64 => .nvptx64,
1078 .le32 => .le32,
1079 .le64 => .le64,
1080 .amdil => .amdil,
1081 .amdil64 => .amdil64,
1082 .hsail => .hsail,
1083 .hsail64 => .hsail64,
1084 .spir => .spir,
1085 .spir64 => .spir64,
1086 .shave => .shave,
1087 .lanai => .lanai,
1088 .wasm32 => .wasm32,
1089 .wasm64 => .wasm64,
1090 .renderscript32 => .renderscript32,
1091 .renderscript64 => .renderscript64,
1092 },
1093 .os = enumInt(Target.Os, in_target.os),
1094 .abi = enumInt(Target.Abi, in_target.abi),
1095 .cpu_features = in_target.cpu_features.cpu_features,
1096 },
1097 };
1098 const result = @import("introspect.zig").detectDynamicLinker(
10221099 std.heap.c_allocator,
1023 mem.toSliceConst(u8, o_file),
1024 if (want_dirname) .only_dir else .full_path,
1100 target,
10251101 ) catch |err| switch (err) {
10261102 error.OutOfMemory => return .OutOfMemory,
1027 error.LibCRuntimeNotFound => return .FileNotFound,
1028 error.CCompilerExitCode => return .CCompilerExitCode,
1029 error.CCompilerCrashed => return .CCompilerCrashed,
1030 error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler,
1103 error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
10311104 };
10321105 out_ptr.* = result.ptr;
10331106 out_len.* = result.len;
10341107 return .None;
10351108}
1109
1110fn enumInt(comptime Enum: type, int: c_int) Enum {
1111 return @intToEnum(Enum, @intCast(@TagType(Enum), int));
1112}
src-self-hosted/util.zig-137
......@@ -2,143 +2,6 @@ const std = @import("std");
22const Target = std.Target;
33const llvm = @import("llvm.zig");
44
5pub const FloatAbi = enum {
6 Hard,
7 Soft,
8 SoftFp,
9};
10
11/// TODO expose the arch and subarch separately
12pub fn isArmOrThumb(self: Target) bool {
13 return switch (self.getArch()) {
14 .arm,
15 .armeb,
16 .aarch64,
17 .aarch64_be,
18 .thumb,
19 .thumbeb,
20 => true,
21 else => false,
22 };
23}
24
25pub fn getFloatAbi(self: Target) FloatAbi {
26 return switch (self.getAbi()) {
27 .gnueabihf,
28 .eabihf,
29 .musleabihf,
30 => .Hard,
31 else => .Soft,
32 };
33}
34
35pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
36 const env = self.getAbi();
37 const arch = self.getArch();
38 const os = self.getOs();
39 switch (os) {
40 .freebsd => {
41 return "/libexec/ld-elf.so.1";
42 },
43 .linux => {
44 switch (env) {
45 .android => {
46 if (self.getArchPtrBitWidth() == 64) {
47 return "/system/bin/linker64";
48 } else {
49 return "/system/bin/linker";
50 }
51 },
52 .gnux32 => {
53 if (arch == .x86_64) {
54 return "/libx32/ld-linux-x32.so.2";
55 }
56 },
57 .musl,
58 .musleabi,
59 .musleabihf,
60 => {
61 if (arch == .x86_64) {
62 return "/lib/ld-musl-x86_64.so.1";
63 }
64 },
65 else => {},
66 }
67 switch (arch) {
68 .i386,
69 .sparc,
70 .sparcel,
71 => return "/lib/ld-linux.so.2",
72
73 .aarch64 => return "/lib/ld-linux-aarch64.so.1",
74
75 .aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
76
77 .arm,
78 .thumb,
79 => return switch (getFloatAbi(self)) {
80 .Hard => return "/lib/ld-linux-armhf.so.3",
81 else => return "/lib/ld-linux.so.3",
82 },
83
84 .armeb,
85 .thumbeb,
86 => return switch (getFloatAbi(self)) {
87 .Hard => return "/lib/ld-linux-armhf.so.3",
88 else => return "/lib/ld-linux.so.3",
89 },
90
91 .mips,
92 .mipsel,
93 .mips64,
94 .mips64el,
95 => return null,
96
97 .powerpc => return "/lib/ld.so.1",
98 .powerpc64 => return "/lib64/ld64.so.2",
99 .powerpc64le => return "/lib64/ld64.so.2",
100 .s390x => return "/lib64/ld64.so.1",
101 .sparcv9 => return "/lib64/ld-linux.so.2",
102 .x86_64 => return "/lib64/ld-linux-x86-64.so.2",
103
104 .arc,
105 .avr,
106 .bpfel,
107 .bpfeb,
108 .hexagon,
109 .msp430,
110 .r600,
111 .amdgcn,
112 .riscv32,
113 .riscv64,
114 .tce,
115 .tcele,
116 .xcore,
117 .nvptx,
118 .nvptx64,
119 .le32,
120 .le64,
121 .amdil,
122 .amdil64,
123 .hsail,
124 .hsail64,
125 .spir,
126 .spir64,
127 .kalimba,
128 .shave,
129 .lanai,
130 .wasm32,
131 .wasm64,
132 .renderscript32,
133 .renderscript64,
134 .aarch64_32,
135 => return null,
136 }
137 },
138 else => return null,
139 }
140}
141
1425pub fn getDarwinArchString(self: Target) [:0]const u8 {
1436 const arch = self.getArch();
1447 switch (arch) {
src/codegen.cpp+12-40
......@@ -8624,7 +8624,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
86248624 break;
86258625 }
86268626 buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type);
8627 const char *link_type = g->is_dynamic ? "Dynamic" : "Static";
8627 const char *link_type = g->have_dynamic_link ? "Dynamic" : "Static";
86288628 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
86298629 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
86308630 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
......@@ -8731,7 +8731,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
87318731 cache_int(&cache_hash, g->build_mode);
87328732 cache_bool(&cache_hash, g->strip_debug_symbols);
87338733 cache_int(&cache_hash, g->out_type);
8734 cache_bool(&cache_hash, g->is_dynamic);
8734 cache_bool(&cache_hash, detect_dynamic_link(g));
87358735 cache_bool(&cache_hash, g->is_test_build);
87368736 cache_bool(&cache_hash, g->is_single_threaded);
87378737 cache_bool(&cache_hash, g->test_is_evented);
......@@ -8957,6 +8957,8 @@ static void init(CodeGen *g) {
89578957}
89588958
89598959static void detect_dynamic_linker(CodeGen *g) {
8960 Error err;
8961
89608962 if (g->dynamic_linker_path != nullptr)
89618963 return;
89628964 if (!g->have_dynamic_link)
......@@ -8964,45 +8966,15 @@ static void detect_dynamic_linker(CodeGen *g) {
89648966 if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
89658967 return;
89668968
8967 const char *standard_ld_path = target_dynamic_linker(g->zig_target);
8968 if (standard_ld_path == nullptr)
8969 return;
8970
8971 if (g->zig_target->is_native) {
8972 // target_dynamic_linker is usually correct. However on some systems, such as NixOS
8973 // it will be incorrect. See if we can do better by looking at what zig's own
8974 // dynamic linker path is.
8975 g->dynamic_linker_path = get_self_dynamic_linker_path();
8976 if (g->dynamic_linker_path != nullptr)
8977 return;
8978
8979 // If Zig is statically linked, such as via distributed binary static builds, the above
8980 // trick won't work. What are we left with? Try to run the system C compiler and get
8981 // it to tell us the dynamic linker path
8982#if defined(ZIG_OS_LINUX)
8983 {
8984 Error err;
8985 for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
8986 const char *lib_name = possible_ld_names[i];
8987 char *result_ptr;
8988 size_t result_len;
8989 if ((err = stage2_libc_cc_print_file_name(&result_ptr, &result_len, lib_name, false))) {
8990 if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) {
8991 fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err));
8992 exit(1);
8993 }
8994 continue;
8995 }
8996 g->dynamic_linker_path = buf_create_from_mem(result_ptr, result_len);
8997 // Skips heap::c_allocator because the memory is allocated by stage2 library.
8998 free(result_ptr);
8999 return;
9000 }
9001 }
9002#endif
8969 char *dynamic_linker_ptr;
8970 size_t dynamic_linker_len;
8971 if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
8972 fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
8973 exit(1);
90038974 }
9004
9005 g->dynamic_linker_path = buf_create_from_str(standard_ld_path);
8975 g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
8976 // Skips heap::c_allocator because the memory is allocated by stage2 library.
8977 free(dynamic_linker_ptr);
90068978}
90078979
90088980static void detect_libc(CodeGen *g) {
src/compiler.cpp-34
......@@ -4,20 +4,6 @@
44
55#include <stdio.h>
66
7static Buf saved_dynamic_linker_path = BUF_INIT;
8static bool searched_for_dyn_linker = false;
9
10static void detect_dynamic_linker(Buf *lib_path) {
11#if defined(ZIG_OS_LINUX)
12 for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
13 if (buf_ends_with_str(lib_path, possible_ld_names[i])) {
14 buf_init_from_buf(&saved_dynamic_linker_path, lib_path);
15 break;
16 }
17 }
18#endif
19}
20
217Buf *get_self_libc_path(void) {
228 static Buf saved_libc_path = BUF_INIT;
239 static bool searched_for_libc = false;
......@@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) {
4329 }
4430}
4531
46Buf *get_self_dynamic_linker_path(void) {
47 for (;;) {
48 if (saved_dynamic_linker_path.list.length != 0) {
49 return &saved_dynamic_linker_path;
50 }
51 if (searched_for_dyn_linker)
52 return nullptr;
53 ZigList<Buf *> lib_paths = {};
54 Error err;
55 if ((err = os_self_exe_shared_libs(lib_paths)))
56 return nullptr;
57 for (size_t i = 0; i < lib_paths.length; i += 1) {
58 Buf *lib_path = lib_paths.at(i);
59 detect_dynamic_linker(lib_path);
60 }
61 searched_for_dyn_linker = true;
62 }
63}
64
6532Error get_compiler_id(Buf **result) {
6633 static Buf saved_compiler_id = BUF_INIT;
6734
......@@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) {
9865 return err;
9966 for (size_t i = 0; i < lib_paths.length; i += 1) {
10067 Buf *lib_path = lib_paths.at(i);
101 detect_dynamic_linker(lib_path);
10268 if ((err = cache_add_file(ch, lib_path)))
10369 return err;
10470 }
src/compiler.hpp-1
......@@ -12,7 +12,6 @@
1212#include "error.hpp"
1313
1414Error get_compiler_id(Buf **result);
15Buf *get_self_dynamic_linker_path(void);
1615Buf *get_self_libc_path(void);
1716
1817Buf *get_zig_lib_dir(void);
src/error.cpp+1
......@@ -80,6 +80,7 @@ const char *err_str(Error err) {
8080 case ErrorLibCKernel32LibNotFound: return "kernel32 library not found";
8181 case ErrorUnsupportedArchitecture: return "unsupported architecture";
8282 case ErrorWindowsSdkNotFound: return "Windows SDK not found";
83 case ErrorUnknownDynamicLinkerPath: return "Windows SDK not found";
8384 }
8485 return "(invalid error)";
8586}
src/os.cpp-18
......@@ -2129,21 +2129,3 @@ void os_file_close(OsFile *file) {
21292129 *file = -1;
21302130#endif
21312131}
2132
2133#ifdef ZIG_OS_LINUX
2134const char *possible_ld_names[] = {
2135#if defined(ZIG_ARCH_X86_64)
2136 "ld-linux-x86-64.so.2",
2137 "ld-musl-x86_64.so.1",
2138#elif defined(ZIG_ARCH_ARM64)
2139 "ld-linux-aarch64.so.1",
2140 "ld-musl-aarch64.so.1",
2141#elif defined(ZIG_ARCH_ARM)
2142 "ld-linux-armhf.so.3",
2143 "ld-musl-armhf.so.1",
2144 "ld-linux.so.3",
2145 "ld-musl-arm.so.1",
2146#endif
2147 NULL,
2148};
2149#endif
src/os.hpp-4
......@@ -43,10 +43,6 @@
4343#define ZIG_ARCH_UNKNOWN
4444#endif
4545
46#ifdef ZIG_OS_LINUX
47extern const char *possible_ld_names[];
48#endif
49
5046#if defined(ZIG_OS_WINDOWS)
5147#define ZIG_PRI_usize "I64u"
5248#define ZIG_PRI_i64 "I64d"
src/stage2.cpp+2-4
......@@ -171,9 +171,7 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
171171 stage2_panic(msg, strlen(msg));
172172}
173173
174enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len,
175 const char *o_file, bool want_dirname)
176{
177 const char *msg = "stage0 called stage2_libc_cc_print_file_name";
174enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) {
175 const char *msg = "stage0 called stage2_detect_dynamic_linker";
178176 stage2_panic(msg, strlen(msg));
179177}
src/stage2.h+67-2
......@@ -12,6 +12,8 @@
1212#include <stdint.h>
1313#include <stdio.h>
1414
15#include "zig_llvm.h"
16
1517#ifdef __cplusplus
1618#define ZIG_EXTERN_C extern "C"
1719#else
......@@ -100,6 +102,7 @@ enum Error {
100102 ErrorLibCKernel32LibNotFound,
101103 ErrorUnsupportedArchitecture,
102104 ErrorWindowsSdkNotFound,
105 ErrorUnknownDynamicLinkerPath,
103106};
104107
105108// ABI warning
......@@ -242,8 +245,70 @@ ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, c
242245ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file);
243246// ABI warning
244247ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc);
248
249// ABI warning
250// Synchronize with target.cpp::os_list
251enum Os {
252 OsFreestanding,
253 OsAnanas,
254 OsCloudABI,
255 OsDragonFly,
256 OsFreeBSD,
257 OsFuchsia,
258 OsIOS,
259 OsKFreeBSD,
260 OsLinux,
261 OsLv2, // PS3
262 OsMacOSX,
263 OsNetBSD,
264 OsOpenBSD,
265 OsSolaris,
266 OsWindows,
267 OsHaiku,
268 OsMinix,
269 OsRTEMS,
270 OsNaCl, // Native Client
271 OsCNK, // BG/P Compute-Node Kernel
272 OsAIX,
273 OsCUDA, // NVIDIA CUDA
274 OsNVCL, // NVIDIA OpenCL
275 OsAMDHSA, // AMD HSA Runtime
276 OsPS4,
277 OsELFIAMCU,
278 OsTvOS, // Apple tvOS
279 OsWatchOS, // Apple watchOS
280 OsMesa3D,
281 OsContiki,
282 OsAMDPAL,
283 OsHermitCore,
284 OsHurd,
285 OsWASI,
286 OsEmscripten,
287 OsUefi,
288 OsOther,
289};
290
291// ABI warning
292struct ZigGLibCVersion {
293 uint32_t major; // always 2
294 uint32_t minor;
295 uint32_t patch;
296};
297
298// ABI warning
299struct ZigTarget {
300 enum ZigLLVM_ArchType arch;
301 enum ZigLLVM_SubArchType sub_arch;
302 enum ZigLLVM_VendorType vendor;
303 Os os;
304 enum ZigLLVM_EnvironmentType abi;
305 struct ZigGLibCVersion *glibc_version; // null means default
306 struct Stage2CpuFeatures *cpu_features;
307 bool is_native;
308};
309
245310// ABI warning
246ZIG_EXTERN_C enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len,
247 const char *o_file, bool want_dirname);
311ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,
312 char **out_ptr, size_t *out_len);
248313
249314#endif
src/target.cpp-203
......@@ -1204,213 +1204,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
12041204 }
12051205}
12061206
1207enum FloatAbi {
1208 FloatAbiHard,
1209 FloatAbiSoft,
1210 FloatAbiSoftFp,
1211};
1212
1213static FloatAbi get_float_abi(const ZigTarget *target) {
1214 const ZigLLVM_EnvironmentType env = target->abi;
1215 if (env == ZigLLVM_GNUEABIHF ||
1216 env == ZigLLVM_EABIHF ||
1217 env == ZigLLVM_MuslEABIHF)
1218 {
1219 return FloatAbiHard;
1220 } else {
1221 return FloatAbiSoft;
1222 }
1223}
1224
1225static bool is_64_bit(ZigLLVM_ArchType arch) {
1226 return target_arch_pointer_bit_width(arch) == 64;
1227}
1228
12291207bool target_is_android(const ZigTarget *target) {
12301208 return target->abi == ZigLLVM_Android;
12311209}
12321210
1233const char *target_dynamic_linker(const ZigTarget *target) {
1234 if (target_is_android(target)) {
1235 return is_64_bit(target->arch) ? "/system/bin/linker64" : "/system/bin/linker";
1236 }
1237
1238 if (target_is_musl(target)) {
1239 Buf buf = BUF_INIT;
1240 buf_init_from_str(&buf, "/lib/ld-musl-");
1241 bool is_arm = false;
1242 switch (target->arch) {
1243 case ZigLLVM_arm:
1244 case ZigLLVM_thumb:
1245 buf_append_str(&buf, "arm");
1246 is_arm = true;
1247 break;
1248 case ZigLLVM_armeb:
1249 case ZigLLVM_thumbeb:
1250 buf_append_str(&buf, "armeb");
1251 is_arm = true;
1252 break;
1253 default:
1254 buf_append_str(&buf, target_arch_name(target->arch));
1255 }
1256 if (is_arm && get_float_abi(target) == FloatAbiHard) {
1257 buf_append_str(&buf, "hf");
1258 }
1259 buf_append_str(&buf, ".so.1");
1260 return buf_ptr(&buf);
1261 }
1262
1263 switch (target->os) {
1264 case OsFreeBSD:
1265 return "/libexec/ld-elf.so.1";
1266 case OsNetBSD:
1267 return "/libexec/ld.elf_so";
1268 case OsDragonFly:
1269 return "/libexec/ld-elf.so.2";
1270 case OsLinux: {
1271 const ZigLLVM_EnvironmentType abi = target->abi;
1272 switch (target->arch) {
1273 case ZigLLVM_UnknownArch:
1274 zig_unreachable();
1275 case ZigLLVM_x86:
1276 case ZigLLVM_sparc:
1277 case ZigLLVM_sparcel:
1278 return "/lib/ld-linux.so.2";
1279
1280 case ZigLLVM_aarch64:
1281 return "/lib/ld-linux-aarch64.so.1";
1282
1283 case ZigLLVM_aarch64_be:
1284 return "/lib/ld-linux-aarch64_be.so.1";
1285
1286 case ZigLLVM_aarch64_32:
1287 return "/lib/ld-linux-aarch64_32.so.1";
1288
1289 case ZigLLVM_arm:
1290 case ZigLLVM_thumb:
1291 if (get_float_abi(target) == FloatAbiHard) {
1292 return "/lib/ld-linux-armhf.so.3";
1293 } else {
1294 return "/lib/ld-linux.so.3";
1295 }
1296
1297 case ZigLLVM_armeb:
1298 case ZigLLVM_thumbeb:
1299 if (get_float_abi(target) == FloatAbiHard) {
1300 return "/lib/ld-linux-armhf.so.3";
1301 } else {
1302 return "/lib/ld-linux.so.3";
1303 }
1304
1305 case ZigLLVM_mips:
1306 case ZigLLVM_mipsel:
1307 case ZigLLVM_mips64:
1308 case ZigLLVM_mips64el:
1309 zig_panic("TODO implement target_dynamic_linker for mips");
1310
1311 case ZigLLVM_ppc:
1312 return "/lib/ld.so.1";
1313
1314 case ZigLLVM_ppc64:
1315 return "/lib64/ld64.so.2";
1316
1317 case ZigLLVM_ppc64le:
1318 return "/lib64/ld64.so.2";
1319
1320 case ZigLLVM_systemz:
1321 return "/lib64/ld64.so.1";
1322
1323 case ZigLLVM_sparcv9:
1324 return "/lib64/ld-linux.so.2";
1325
1326 case ZigLLVM_x86_64:
1327 if (abi == ZigLLVM_GNUX32) {
1328 return "/libx32/ld-linux-x32.so.2";
1329 }
1330 if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) {
1331 return "/lib/ld-musl-x86_64.so.1";
1332 }
1333 return "/lib64/ld-linux-x86-64.so.2";
1334
1335 case ZigLLVM_wasm32:
1336 case ZigLLVM_wasm64:
1337 return nullptr;
1338
1339 case ZigLLVM_riscv32:
1340 return "/lib/ld-linux-riscv32-ilp32.so.1";
1341 case ZigLLVM_riscv64:
1342 return "/lib/ld-linux-riscv64-lp64.so.1";
1343
1344 case ZigLLVM_arc:
1345 case ZigLLVM_avr:
1346 case ZigLLVM_bpfel:
1347 case ZigLLVM_bpfeb:
1348 case ZigLLVM_hexagon:
1349 case ZigLLVM_msp430:
1350 case ZigLLVM_r600:
1351 case ZigLLVM_amdgcn:
1352 case ZigLLVM_tce:
1353 case ZigLLVM_tcele:
1354 case ZigLLVM_xcore:
1355 case ZigLLVM_nvptx:
1356 case ZigLLVM_nvptx64:
1357 case ZigLLVM_le32:
1358 case ZigLLVM_le64:
1359 case ZigLLVM_amdil:
1360 case ZigLLVM_amdil64:
1361 case ZigLLVM_hsail:
1362 case ZigLLVM_hsail64:
1363 case ZigLLVM_spir:
1364 case ZigLLVM_spir64:
1365 case ZigLLVM_kalimba:
1366 case ZigLLVM_shave:
1367 case ZigLLVM_lanai:
1368 case ZigLLVM_renderscript32:
1369 case ZigLLVM_renderscript64:
1370 zig_panic("TODO implement target_dynamic_linker for this arch");
1371 }
1372 zig_unreachable();
1373 }
1374 case OsFreestanding:
1375 case OsIOS:
1376 case OsTvOS:
1377 case OsWatchOS:
1378 case OsMacOSX:
1379 case OsUefi:
1380 case OsWindows:
1381 case OsEmscripten:
1382 case OsOther:
1383 return nullptr;
1384
1385 case OsAnanas:
1386 case OsCloudABI:
1387 case OsFuchsia:
1388 case OsKFreeBSD:
1389 case OsLv2:
1390 case OsOpenBSD:
1391 case OsSolaris:
1392 case OsHaiku:
1393 case OsMinix:
1394 case OsRTEMS:
1395 case OsNaCl:
1396 case OsCNK:
1397 case OsAIX:
1398 case OsCUDA:
1399 case OsNVCL:
1400 case OsAMDHSA:
1401 case OsPS4:
1402 case OsELFIAMCU:
1403 case OsMesa3D:
1404 case OsContiki:
1405 case OsAMDPAL:
1406 case OsHermitCore:
1407 case OsHurd:
1408 case OsWASI:
1409 zig_panic("TODO implement target_dynamic_linker for this OS");
1410 }
1411 zig_unreachable();
1412}
1413
14141211bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) {
14151212 assert(host_target != nullptr);
14161213
src/target.hpp+1-61
......@@ -8,51 +8,10 @@
88#ifndef ZIG_TARGET_HPP
99#define ZIG_TARGET_HPP
1010
11#include <zig_llvm.h>
11#include "stage2.h"
1212
1313struct Buf;
1414
15// Synchronize with target.cpp::os_list
16enum Os {
17 OsFreestanding,
18 OsAnanas,
19 OsCloudABI,
20 OsDragonFly,
21 OsFreeBSD,
22 OsFuchsia,
23 OsIOS,
24 OsKFreeBSD,
25 OsLinux,
26 OsLv2, // PS3
27 OsMacOSX,
28 OsNetBSD,
29 OsOpenBSD,
30 OsSolaris,
31 OsWindows,
32 OsHaiku,
33 OsMinix,
34 OsRTEMS,
35 OsNaCl, // Native Client
36 OsCNK, // BG/P Compute-Node Kernel
37 OsAIX,
38 OsCUDA, // NVIDIA CUDA
39 OsNVCL, // NVIDIA OpenCL
40 OsAMDHSA, // AMD HSA Runtime
41 OsPS4,
42 OsELFIAMCU,
43 OsTvOS, // Apple tvOS
44 OsWatchOS, // Apple watchOS
45 OsMesa3D,
46 OsContiki,
47 OsAMDPAL,
48 OsHermitCore,
49 OsHurd,
50 OsWASI,
51 OsEmscripten,
52 OsUefi,
53 OsOther,
54};
55
5615// Synchronize with target.cpp::subarch_list_list
5716enum SubArchList {
5817 SubArchListNone,
......@@ -78,23 +37,6 @@ enum TargetSubsystem {
7837 TargetSubsystemAuto
7938};
8039
81struct ZigGLibCVersion {
82 uint32_t major; // always 2
83 uint32_t minor;
84 uint32_t patch;
85};
86
87struct ZigTarget {
88 ZigLLVM_ArchType arch;
89 ZigLLVM_SubArchType sub_arch;
90 ZigLLVM_VendorType vendor;
91 Os os;
92 ZigLLVM_EnvironmentType abi;
93 ZigGLibCVersion *glibc_version; // null means default
94 Stage2CpuFeatures *cpu_features;
95 bool is_native;
96};
97
9840enum CIntType {
9941 CIntTypeShort,
10042 CIntTypeUShort,
......@@ -168,8 +110,6 @@ const char *target_lib_file_prefix(const ZigTarget *target);
168110const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
169111 size_t version_major, size_t version_minor, size_t version_patch);
170112
171const char *target_dynamic_linker(const ZigTarget *target);
172
173113bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
174114ZigLLVM_OSType get_llvm_os_type(Os os_type);
175115