╭ glibc.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const Io = std.Io; 3 const Allocator = std.mem.Allocator; 4 const mem = std.mem; 5 const log = std.log; 6 const path = std.Io.Dir.path; 7 const assert = std.debug.assert; 8 const Version = std.SemanticVersion; 9 const Path = std.Build.Cache.Path; 10 11 const Compilation = @import("../Compilation.zig"); 12 const build_options = @import("build_options"); 13 const trace = @import("../tracy.zig").trace; 14 const Cache = std.Build.Cache; 15 const Module = @import("../Module.zig"); 16 const link = @import("../link.zig"); 17 18 pub const Lib = struct { 19 name: []const u8, 20 sover: u8, 21 removed_in: ?Version = null, 22 }; 23 24 pub const ABI = struct { 25 all_versions: []const Version, // all defined versions (one abilist from v2.0.0 up to current) 26 all_targets: []const std.zig.target.ArchOsAbi, 27 /// The bytes from the file verbatim, starting from the u16 number 28 /// of function inclusions. 29 inclusions: []const u8, 30 arena_state: std.heap.ArenaAllocator.State, 31 32 pub fn destroy(abi: *ABI, gpa: Allocator) void { 33 abi.arena_state.promote(gpa).deinit(); 34 } 35 }; 36 37 // The order of the elements in this array defines the linking order. 38 pub const libs = [_]Lib{ 39 .{ .name = "m", .sover = 6 }, 40 .{ .name = "c", .sover = 6 }, 41 .{ .name = "ld", .sover = 2 }, 42 .{ .name = "resolv", .sover = 2 }, 43 .{ .name = "pthread", .sover = 0, .removed_in = .{ .major = 2, .minor = 34, .patch = 0 } }, 44 .{ .name = "dl", .sover = 2, .removed_in = .{ .major = 2, .minor = 34, .patch = 0 } }, 45 .{ .name = "rt", .sover = 1, .removed_in = .{ .major = 2, .minor = 34, .patch = 0 } }, 46 .{ .name = "util", .sover = 1, .removed_in = .{ .major = 2, .minor = 34, .patch = 0 } }, 47 }; 48 49 pub const LoadMetaDataError = error{ 50 /// The files that ship with the Zig compiler were unable to be read, or otherwise had malformed data. 51 ZigInstallationCorrupt, 52 OutOfMemory, 53 }; 54 55 pub const abilists_path = "libc" ++ path.sep_str ++ "glibc" ++ path.sep_str ++ "abilists"; 56 pub const abilists_max_size = 800 * 1024; // Bigger than this and something is definitely borked. 57 58 /// This function will emit a log error when there is a problem with the zig 59 /// installation and then return `error.ZigInstallationCorrupt`. 60 pub fn loadMetaData(gpa: Allocator, contents: []const u8) LoadMetaDataError!*ABI { 61 const tracy = trace(@src()); 62 defer tracy.end(); 63 64 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 65 errdefer arena_allocator.deinit(); 66 const arena = arena_allocator.allocator(); 67 68 var index: usize = 0; 69 70 { 71 const libs_len = contents[index]; 72 index += 1; 73 74 var i: u8 = 0; 75 while (i < libs_len) : (i += 1) { 76 const lib_name = mem.sliceTo(contents[index..], 0); 77 index += lib_name.len + 1; 78 79 if (i >= libs.len or !mem.eql(u8, libs[i].name, lib_name)) { 80 log.err("libc" ++ path.sep_str ++ "glibc" ++ path.sep_str ++ 81 "abilists: invalid library name or index ({d}): '{s}'", .{ i, lib_name }); 82 return error.ZigInstallationCorrupt; 83 } 84 } 85 } 86 87 const versions = b: { 88 const versions_len = contents[index]; 89 index += 1; 90 91 const versions = try arena.alloc(Version, versions_len); 92 var i: u8 = 0; 93 while (i < versions.len) : (i += 1) { 94 versions[i] = .{ 95 .major = contents[index + 0], 96 .minor = contents[index + 1], 97 .patch = contents[index + 2], 98 }; 99 index += 3; 100 } 101 break :b versions; 102 }; 103 104 const targets = b: { 105 const targets_len = contents[index]; 106 index += 1; 107 108 const targets = try arena.alloc(std.zig.target.ArchOsAbi, targets_len); 109 var i: u8 = 0; 110 while (i < targets.len) : (i += 1) { 111 const target_name = mem.sliceTo(contents[index..], 0); 112 index += target_name.len + 1; 113 114 var component_it = mem.tokenizeScalar(u8, target_name, '-'); 115 const arch_name = component_it.next() orelse { 116 log.err("abilists: expected arch name", .{}); 117 return error.ZigInstallationCorrupt; 118 }; 119 const os_name = component_it.next() orelse { 120 log.err("abilists: expected OS name", .{}); 121 return error.ZigInstallationCorrupt; 122 }; 123 const abi_name = component_it.next() orelse { 124 log.err("abilists: expected ABI name", .{}); 125 return error.ZigInstallationCorrupt; 126 }; 127 const arch_tag = std.meta.stringToEnum(std.Target.Cpu.Arch, arch_name) orelse { 128 log.err("abilists: unrecognized arch: '{s}'", .{arch_name}); 129 return error.ZigInstallationCorrupt; 130 }; 131 if (!mem.eql(u8, os_name, "linux")) { 132 log.err("abilists: expected OS 'linux', found '{s}'", .{os_name}); 133 return error.ZigInstallationCorrupt; 134 } 135 const abi_tag = std.meta.stringToEnum(std.Target.Abi, abi_name) orelse { 136 log.err("abilists: unrecognized ABI: '{s}'", .{abi_name}); 137 return error.ZigInstallationCorrupt; 138 }; 139 140 targets[i] = .{ 141 .arch = arch_tag, 142 .os = .linux, 143 .abi = abi_tag, 144 }; 145 } 146 break :b targets; 147 }; 148 149 const abi = try arena.create(ABI); 150 abi.* = .{ 151 .all_versions = versions, 152 .all_targets = targets, 153 .inclusions = contents[index..], 154 .arena_state = arena_allocator.state, 155 }; 156 return abi; 157 } 158 159 pub const CrtFile = enum { 160 scrt1_o, 161 libc_nonshared_a, 162 }; 163 164 /// TODO replace anyerror with explicit error set, recording user-friendly errors with 165 /// lockAndSetMiscFailure and returning error.AlreadyReported. see libcxx.zig for example. 166 pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) anyerror!void { 167 if (!build_options.have_llvm) { 168 return error.ZigCompilerNotBuiltWithLLVMExtensions; 169 } 170 const gpa = comp.gpa; 171 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 172 defer arena_allocator.deinit(); 173 const arena = arena_allocator.allocator(); 174 175 const target = &comp.root_mod.resolved_target.result; 176 const target_ver = target.os.versionRange().gnuLibCVersion().?; 177 const nonshared_stat = target_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) != .gt; 178 const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33, .patch = 0 }) != .gt; 179 180 // In all cases in this function, we add the C compiler flags to 181 // cache_exempt_flags rather than extra_flags, because these arguments 182 // depend on only properties that are already covered by the cache 183 // manifest. Including these arguments in the cache could only possibly 184 // waste computation and create false negatives. 185 186 switch (crt_file) { 187 .scrt1_o => { 188 const start_o: Compilation.CSourceFile = blk: { 189 var args = std.array_list.Managed([]const u8).init(arena); 190 try add_include_dirs(comp, arena, &args); 191 try args.appendSlice(&[_][]const u8{ 192 "-w", // Disable all warnings. 193 "-D_LIBC_REENTRANT", 194 "-include", 195 try lib_path(comp, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-modules.h"), 196 "-DMODULE_NAME=libc", 197 "-include", 198 try lib_path(comp, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"), 199 "-DPIC", 200 "-DSHARED", 201 "-DTOP_NAMESPACE=glibc", 202 "-DASSEMBLER", 203 "-Wa,--noexecstack", 204 }); 205 const src_path = if (start_old_init_fini) "start-2.33.S" else "start.S"; 206 break :blk .{ 207 .src_path = try start_asm_path(comp, arena, src_path), 208 .cache_exempt_flags = args.items, 209 .owner = undefined, 210 }; 211 }; 212 const abi_note_o: Compilation.CSourceFile = blk: { 213 var args = std.array_list.Managed([]const u8).init(arena); 214 try args.appendSlice(&[_][]const u8{ 215 "-I", 216 try lib_path(comp, arena, lib_libc_glibc ++ "csu"), 217 }); 218 try add_include_dirs(comp, arena, &args); 219 try args.appendSlice(&[_][]const u8{ 220 "-w", // Disable all warnings. 221 "-D_LIBC_REENTRANT", 222 "-DMODULE_NAME=libc", 223 "-DTOP_NAMESPACE=glibc", 224 "-DASSEMBLER", 225 "-Wa,--noexecstack", 226 }); 227 break :blk .{ 228 .src_path = try lib_path(comp, arena, lib_libc_glibc ++ "csu" ++ path.sep_str ++ "abi-note.S"), 229 .cache_exempt_flags = args.items, 230 .owner = undefined, 231 }; 232 }; 233 const init_o: Compilation.CSourceFile = blk: { 234 var args = std.array_list.Managed([]const u8).init(arena); 235 try args.appendSlice(&[_][]const u8{ 236 "-w", // Disable all warnings. 237 }); 238 break :blk .{ 239 .src_path = try lib_path(comp, arena, lib_libc_glibc ++ "csu" ++ path.sep_str ++ "init.c"), 240 .cache_exempt_flags = args.items, 241 .owner = undefined, 242 }; 243 }; 244 var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o }; 245 const basename = if (comp.config.output_mode == .Exe and !comp.config.pie) "crt1" else "Scrt1"; 246 return comp.build_crt_file(basename, .Obj, .@"glibc Scrt1.o", prog_node, &files, .{}); 247 }, 248 .libc_nonshared_a => { 249 const s = path.sep_str; 250 const Dep = struct { 251 path: []const u8, 252 include: bool = true, 253 }; 254 const deps = [_]Dep{ 255 .{ .path = lib_libc_glibc ++ "stdlib" ++ s ++ "atexit.c" }, 256 .{ .path = lib_libc_glibc ++ "stdlib" ++ s ++ "at_quick_exit.c" }, 257 .{ .path = lib_libc_glibc ++ "sysdeps" ++ s ++ "pthread" ++ s ++ "pthread_atfork.c" }, 258 .{ .path = lib_libc_glibc ++ "debug" ++ s ++ "stack_chk_fail_local.c" }, 259 260 // libc_nonshared.a redirected stat functions to xstat until glibc 2.33, 261 // when they were finally versioned like other symbols. 262 .{ 263 .path = lib_libc_glibc ++ "io" ++ s ++ "stat-2.32.c", 264 .include = nonshared_stat, 265 }, 266 .{ 267 .path = lib_libc_glibc ++ "io" ++ s ++ "fstat-2.32.c", 268 .include = nonshared_stat, 269 }, 270 .{ 271 .path = lib_libc_glibc ++ "io" ++ s ++ "lstat-2.32.c", 272 .include = nonshared_stat, 273 }, 274 .{ 275 .path = lib_libc_glibc ++ "io" ++ s ++ "stat64-2.32.c", 276 .include = nonshared_stat, 277 }, 278 .{ 279 .path = lib_libc_glibc ++ "io" ++ s ++ "fstat64-2.32.c", 280 .include = nonshared_stat, 281 }, 282 .{ 283 .path = lib_libc_glibc ++ "io" ++ s ++ "lstat64-2.32.c", 284 .include = nonshared_stat, 285 }, 286 .{ 287 .path = lib_libc_glibc ++ "io" ++ s ++ "fstatat-2.32.c", 288 .include = nonshared_stat, 289 }, 290 .{ 291 .path = lib_libc_glibc ++ "io" ++ s ++ "fstatat64-2.32.c", 292 .include = nonshared_stat, 293 }, 294 .{ 295 .path = lib_libc_glibc ++ "io" ++ s ++ "mknodat-2.32.c", 296 .include = nonshared_stat, 297 }, 298 .{ 299 .path = lib_libc_glibc ++ "io" ++ s ++ "mknod-2.32.c", 300 .include = nonshared_stat, 301 }, 302 303 // __libc_start_main used to require statically linked init/fini callbacks 304 // until glibc 2.34 when they were assimilated into the shared library. 305 .{ 306 .path = lib_libc_glibc ++ "csu" ++ s ++ "elf-init-2.33.c", 307 .include = start_old_init_fini, 308 }, 309 }; 310 311 var files_buf: [deps.len]Compilation.CSourceFile = undefined; 312 var files_index: usize = 0; 313 314 for (deps) |dep| { 315 if (!dep.include) continue; 316 317 var args = std.array_list.Managed([]const u8).init(arena); 318 try args.appendSlice(&[_][]const u8{ 319 "-w", // Disable all warnings. 320 "-std=gnu11", 321 "-fgnu89-inline", 322 "-fmerge-all-constants", 323 "-frounding-math", 324 "-fno-common", 325 "-fmath-errno", 326 "-ftls-model=initial-exec", 327 "-Qunused-arguments", 328 }); 329 try add_include_dirs(comp, arena, &args); 330 331 try args.append("-DNO_INITFINI"); 332 333 if (target.cpu.arch == .x86) { 334 // This prevents i386/sysdep.h from trying to do some 335 // silly and unnecessary inline asm hack that uses weird 336 // syntax that clang does not support. 337 try args.append("-DCAN_USE_REGISTER_ASM_EBP"); 338 } 339 340 try args.appendSlice(&[_][]const u8{ 341 "-D_LIBC_REENTRANT", 342 "-include", 343 try lib_path(comp, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-modules.h"), 344 "-DMODULE_NAME=libc", 345 "-include", 346 try lib_path(comp, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"), 347 "-DPIC", 348 "-DLIBC_NONSHARED=1", 349 "-DTOP_NAMESPACE=glibc", 350 }); 351 files_buf[files_index] = .{ 352 .src_path = try lib_path(comp, arena, dep.path), 353 .cache_exempt_flags = args.items, 354 .owner = undefined, 355 }; 356 files_index += 1; 357 } 358 const files = files_buf[0..files_index]; 359 return comp.build_crt_file("c_nonshared", .Lib, .@"glibc libc_nonshared.a", prog_node, files, .{}); 360 }, 361 } 362 } 363 364 fn start_asm_path(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 { 365 const arch = comp.getTarget().cpu.arch; 366 const is_ppc = arch.isPowerPC(); 367 const is_aarch64 = arch.isAARCH64(); 368 const is_sparc = arch.isSPARC(); 369 const is_64 = comp.getTarget().ptrBitWidth() == 64; 370 371 const s = path.sep_str; 372 373 var result = std.array_list.Managed(u8).init(arena); 374 try result.appendSlice(comp.dirs.zig_lib.path orelse "."); 375 try result.appendSlice(s ++ "libc" ++ s ++ "glibc" ++ s ++ "sysdeps" ++ s); 376 if (is_sparc) { 377 if (is_64) { 378 try result.appendSlice("sparc" ++ s ++ "sparc64"); 379 } else { 380 try result.appendSlice("sparc" ++ s ++ "sparc32"); 381 } 382 } else if (arch.isArm()) { 383 try result.appendSlice("arm"); 384 } else if (arch.isMIPS()) { 385 try result.appendSlice("mips"); 386 } else if (arch == .x86_64) { 387 try result.appendSlice("x86_64"); 388 } else if (arch == .x86) { 389 try result.appendSlice("i386"); 390 } else if (is_aarch64) { 391 try result.appendSlice("aarch64"); 392 } else if (arch.isRISCV()) { 393 try result.appendSlice("riscv"); 394 } else if (is_ppc) { 395 if (is_64) { 396 try result.appendSlice("powerpc" ++ s ++ "powerpc64"); 397 } else { 398 try result.appendSlice("powerpc" ++ s ++ "powerpc32"); 399 } 400 } else if (arch == .s390x) { 401 try result.appendSlice("s390"); 402 } else if (arch.isLoongArch()) { 403 try result.appendSlice("loongarch"); 404 } else if (arch == .m68k) { 405 try result.appendSlice("m68k"); 406 } else if (arch == .arc) { 407 try result.appendSlice("arc"); 408 } else if (arch == .csky) { 409 try result.appendSlice("csky" ++ s ++ "abiv2"); 410 } 411 412 try result.appendSlice(s); 413 try result.appendSlice(basename); 414 return result.items; 415 } 416 417 fn add_include_dirs(comp: *Compilation, arena: Allocator, args: *std.array_list.Managed([]const u8)) error{OutOfMemory}!void { 418 const target = comp.getTarget(); 419 const opt_nptl: ?[]const u8 = if (target.os.tag == .linux) "nptl" else "htl"; 420 421 const s = path.sep_str; 422 423 try args.append("-I"); 424 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "include")); 425 426 if (target.os.tag == .linux) { 427 try add_include_dirs_arch(arena, args, target, null, try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv" ++ s ++ "linux")); 428 } 429 430 if (opt_nptl) |nptl| { 431 try add_include_dirs_arch(arena, args, target, nptl, try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps")); 432 } 433 434 if (target.os.tag == .linux) { 435 try args.append("-I"); 436 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ 437 "unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s ++ "generic")); 438 439 try args.append("-I"); 440 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ 441 "unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s ++ "include")); 442 try args.append("-I"); 443 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ 444 "unix" ++ s ++ "sysv" ++ s ++ "linux")); 445 } 446 if (opt_nptl) |nptl| { 447 try args.append("-I"); 448 try args.append(try path.join(arena, &.{ comp.dirs.zig_lib.path orelse ".", lib_libc_glibc ++ "sysdeps", nptl })); 449 } 450 451 try args.append("-I"); 452 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "pthread")); 453 454 try args.append("-I"); 455 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix" ++ s ++ "sysv")); 456 457 try add_include_dirs_arch(arena, args, target, null, try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix")); 458 459 try args.append("-I"); 460 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "unix")); 461 462 try add_include_dirs_arch(arena, args, target, null, try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps")); 463 464 try args.append("-I"); 465 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "generic")); 466 467 try args.append("-I"); 468 try args.append(try path.join(arena, &[_][]const u8{ comp.dirs.zig_lib.path orelse ".", lib_libc ++ "glibc" })); 469 470 try args.append("-I"); 471 try args.append(try std.fmt.allocPrint(arena, "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}", .{ 472 comp.dirs.zig_lib.path orelse ".", 473 std.zig.target.glibcArchNameHeaders(target.cpu.arch), 474 @tagName(target.os.tag), 475 std.zig.target.glibcAbiNameHeaders(target.abi), 476 })); 477 478 try args.append("-I"); 479 try args.append(try lib_path(comp, arena, lib_libc ++ "include" ++ s ++ "generic-glibc")); 480 481 const arch_name = std.zig.target.osArchName(target); 482 try args.append("-I"); 483 try args.append(try std.fmt.allocPrint(arena, "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-linux-any", .{ 484 comp.dirs.zig_lib.path orelse ".", arch_name, 485 })); 486 487 try args.append("-I"); 488 try args.append(try lib_path(comp, arena, lib_libc ++ "include" ++ s ++ "any-linux-any")); 489 } 490 491 fn add_include_dirs_arch( 492 arena: Allocator, 493 args: *std.array_list.Managed([]const u8), 494 target: *const std.Target, 495 opt_nptl: ?[]const u8, 496 dir: []const u8, 497 ) error{OutOfMemory}!void { 498 const arch = target.cpu.arch; 499 const is_x86 = arch.isX86(); 500 const is_aarch64 = arch.isAARCH64(); 501 const is_ppc = arch.isPowerPC(); 502 const is_sparc = arch.isSPARC(); 503 const is_64 = target.ptrBitWidth() == 64; 504 505 const s = path.sep_str; 506 507 if (is_x86) { 508 if (arch == .x86_64) { 509 if (opt_nptl) |nptl| { 510 try args.append("-I"); 511 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64", nptl })); 512 } else { 513 if (target.abi == .gnux32) { 514 try args.append("-I"); 515 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64", "x32" })); 516 } 517 try args.append("-I"); 518 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86_64" })); 519 } 520 } else if (arch == .x86) { 521 if (opt_nptl) |nptl| { 522 try args.append("-I"); 523 try args.append(try path.join(arena, &[_][]const u8{ dir, "i386", nptl })); 524 } else { 525 try args.append("-I"); 526 try args.append(try path.join(arena, &[_][]const u8{ dir, "i386" })); 527 } 528 } 529 if (opt_nptl) |nptl| { 530 try args.append("-I"); 531 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86", nptl })); 532 } else { 533 try args.append("-I"); 534 try args.append(try path.join(arena, &[_][]const u8{ dir, "x86" })); 535 } 536 } else if (arch.isArm()) { 537 if (opt_nptl) |nptl| { 538 try args.append("-I"); 539 try args.append(try path.join(arena, &[_][]const u8{ dir, "arm", nptl })); 540 } else { 541 try args.append("-I"); 542 try args.append(try path.join(arena, &[_][]const u8{ dir, "arm" })); 543 } 544 } else if (arch.isMIPS()) { 545 if (opt_nptl) |nptl| { 546 try args.append("-I"); 547 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips", nptl })); 548 } else { 549 if (is_64) { 550 try args.append("-I"); 551 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" ++ s ++ "mips64" })); 552 } else { 553 try args.append("-I"); 554 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" ++ s ++ "mips32" })); 555 } 556 try args.append("-I"); 557 try args.append(try path.join(arena, &[_][]const u8{ dir, "mips" })); 558 } 559 } else if (is_sparc) { 560 if (opt_nptl) |nptl| { 561 try args.append("-I"); 562 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc", nptl })); 563 } else { 564 if (is_64) { 565 try args.append("-I"); 566 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" ++ s ++ "sparc64" })); 567 } else { 568 try args.append("-I"); 569 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" ++ s ++ "sparc32" })); 570 } 571 try args.append("-I"); 572 try args.append(try path.join(arena, &[_][]const u8{ dir, "sparc" })); 573 } 574 } else if (is_aarch64) { 575 if (opt_nptl) |nptl| { 576 try args.append("-I"); 577 try args.append(try path.join(arena, &[_][]const u8{ dir, "aarch64", nptl })); 578 } else { 579 try args.append("-I"); 580 try args.append(try path.join(arena, &[_][]const u8{ dir, "aarch64" })); 581 } 582 } else if (is_ppc) { 583 if (opt_nptl) |nptl| { 584 try args.append("-I"); 585 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc", nptl })); 586 } else { 587 if (is_64) { 588 try args.append("-I"); 589 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" ++ s ++ "powerpc64" })); 590 } else { 591 try args.append("-I"); 592 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" ++ s ++ "powerpc32" })); 593 } 594 try args.append("-I"); 595 try args.append(try path.join(arena, &[_][]const u8{ dir, "powerpc" })); 596 } 597 } else if (arch.isRISCV()) { 598 if (opt_nptl) |nptl| { 599 try args.append("-I"); 600 try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv", nptl })); 601 } else { 602 try args.append("-I"); 603 try args.append(try path.join(arena, &[_][]const u8{ dir, "riscv" })); 604 } 605 } else if (arch == .s390x) { 606 if (opt_nptl) |nptl| { 607 try args.append("-I"); 608 try args.append(try path.join(arena, &[_][]const u8{ dir, "s390", nptl })); 609 } else { 610 try args.append("-I"); 611 try args.append(try path.join(arena, &[_][]const u8{ dir, "s390" })); 612 } 613 } else if (arch.isLoongArch()) { 614 try args.append("-I"); 615 try args.append(try path.join(arena, &[_][]const u8{ dir, "loongarch" })); 616 } else if (arch == .m68k) { 617 if (opt_nptl) |nptl| { 618 try args.append("-I"); 619 try args.append(try path.join(arena, &[_][]const u8{ dir, "m68k", nptl })); 620 } else { 621 // coldfire ABI support requires: https://github.com/ziglang/zig/issues/20690 622 try args.append("-I"); 623 try args.append(try path.join(arena, &[_][]const u8{ dir, "m68k" ++ s ++ "m680x0" })); 624 try args.append("-I"); 625 try args.append(try path.join(arena, &[_][]const u8{ dir, "m68k" })); 626 } 627 } else if (arch == .arc) { 628 try args.append("-I"); 629 try args.append(try path.join(arena, &[_][]const u8{ dir, "arc" })); 630 } else if (arch == .csky) { 631 try args.append("-I"); 632 try args.append(try path.join(arena, &[_][]const u8{ dir, "csky" })); 633 } 634 } 635 636 const lib_libc = "libc" ++ path.sep_str; 637 const lib_libc_glibc = lib_libc ++ "glibc" ++ path.sep_str; 638 639 fn lib_path(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 { 640 return path.join(arena, &.{ comp.dirs.zig_lib.path orelse ".", sub_path }); 641 } 642 643 pub const BuiltSharedObjects = struct { 644 lock: Cache.Lock, 645 dir_path: Path, 646 647 pub fn deinit(self: *BuiltSharedObjects, gpa: Allocator, io: Io) void { 648 self.lock.release(io); 649 gpa.free(self.dir_path.sub_path); 650 self.* = undefined; 651 } 652 }; 653 654 const all_map_basename = "all.map"; 655 656 fn wordDirective(target: *const std.Target) []const u8 { 657 // Based on its description in the GNU `as` manual, you might assume that `.word` is sized 658 // according to the target word size. But no; that would just make too much sense. 659 return if (target.ptrBitWidth() == 64) ".quad" else ".long"; 660 } 661 662 /// TODO replace anyerror with explicit error set, recording user-friendly errors with 663 /// lockAndSetMiscFailure and returning error.AlreadyReported. see libcxx.zig for example. 664 pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anyerror!void { 665 const tracy = trace(@src()); 666 defer tracy.end(); 667 668 if (!build_options.have_llvm) { 669 return error.ZigCompilerNotBuiltWithLLVMExtensions; 670 } 671 672 const gpa = comp.gpa; 673 const io = comp.io; 674 675 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 676 defer arena_allocator.deinit(); 677 const arena = arena_allocator.allocator(); 678 679 const target = comp.getTarget(); 680 const target_version = target.os.versionRange().gnuLibCVersion().?; 681 682 // Use the global cache directory. 683 var cache: Cache = .{ 684 .gpa = gpa, 685 .io = io, 686 .manifest_dir = try comp.dirs.global_cache.handle.createDirPathOpen(io, "h", .{}), 687 .cwd = comp.dirs.cwd, 688 }; 689 cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() }); 690 cache.addPrefix(comp.dirs.zig_lib); 691 cache.addPrefix(comp.dirs.global_cache); 692 defer cache.manifest_dir.close(io); 693 694 var man = cache.obtain(); 695 defer man.deinit(); 696 man.hash.addBytes(build_options.version); 697 man.hash.add(target.cpu.arch); 698 man.hash.add(target.abi); 699 man.hash.add(target_version); 700 701 const abilists_index = try man.addInputPath(.{ 702 .root_dir = comp.dirs.zig_lib, 703 .sub_path = abilists_path, 704 }, .{ 705 .request_contents = true, 706 }); 707 708 var diag: Cache.Manifest.CheckDiagnostic = undefined; 709 const status = man.check(&diag, prog_node) catch |err| switch (err) { 710 error.OutOfMemory, error.Canceled => |e| return e, 711 error.CacheCheckFailed => { 712 comp.lockAndSetMiscFailure( 713 .glibc_shared_objects, 714 "compiling glibc shared objects: checking cache failed: {f}", 715 .{diag.fmt(&man)}, 716 ); 717 return error.AlreadyReported; 718 }, 719 }; 720 log.debug("glibc_shared_objects cache {f}", .{status.fmt(&man)}); 721 if (status == .hit) { 722 const digest = man.hitDigestHex(); 723 return queueSharedObjects(comp, .{ 724 .lock = man.toOwnedLock(), 725 .dir_path = .{ 726 .root_dir = comp.dirs.global_cache, 727 .sub_path = try gpa.dupe(u8, "o" ++ path.sep_str ++ digest), 728 }, 729 }); 730 } 731 732 const digest = man.missDigestHex(); 733 const o_sub_path = try path.join(arena, &.{ "o", &digest }); 734 735 var o_directory: Cache.Directory = .{ 736 .handle = try comp.dirs.global_cache.handle.createDirPathOpen(io, o_sub_path, .{}), 737 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}), 738 }; 739 defer o_directory.handle.close(io); 740 741 const abilists_contents = abilists_index.contents(&man); 742 const metadata = try loadMetaData(gpa, abilists_contents); 743 defer metadata.destroy(gpa); 744 745 const target_targ_index = for (metadata.all_targets, 0..) |targ, i| { 746 if (targ.arch == target.cpu.arch and 747 targ.os == target.os.tag and 748 targ.abi == target.abi) 749 { 750 break i; 751 } 752 } else { 753 unreachable; // std.zig.target.available_libcs prevents us from getting here 754 }; 755 756 const target_ver_index = for (metadata.all_versions, 0..) |ver, i| { 757 switch (ver.order(target_version)) { 758 .eq => break i, 759 .lt => continue, 760 .gt => { 761 // TODO Expose via compile error mechanism instead of log. 762 log.warn("invalid target glibc version: {f}", .{target_version}); 763 return error.InvalidTargetGLibCVersion; 764 }, 765 } 766 } else blk: { 767 const latest_index = metadata.all_versions.len - 1; 768 log.warn("zig cannot build new glibc version {f}; providing instead {f}", .{ 769 target_version, metadata.all_versions[latest_index], 770 }); 771 break :blk latest_index; 772 }; 773 774 { 775 var map_contents = std.array_list.Managed(u8).init(arena); 776 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| { 777 if (ver.patch == 0) { 778 try map_contents.print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor }); 779 } else { 780 try map_contents.print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch }); 781 } 782 } 783 try o_directory.handle.writeFile(io, .{ .sub_path = all_map_basename, .data = map_contents.items }); 784 map_contents.deinit(); // The most recent allocation of an arena can be freed :) 785 } 786 787 var stubs_asm = std.array_list.Managed(u8).init(gpa); 788 defer stubs_asm.deinit(); 789 790 for (libs, 0..) |lib, lib_i| { 791 if (lib.removed_in) |rem_in| { 792 if (target_version.order(rem_in) != .lt) continue; 793 } 794 795 stubs_asm.shrinkRetainingCapacity(0); 796 try stubs_asm.appendSlice(".text\n"); 797 798 var sym_i: usize = 0; 799 var sym_name_buf: Io.Writer.Allocating = .init(arena); 800 var opt_symbol_name: ?[]const u8 = null; 801 var versions_buffer: [32]u8 = undefined; 802 var versions_len: usize = undefined; 803 804 // There can be situations where there are multiple inclusions for the same symbol with 805 // partially overlapping versions, due to different target lists. For example: 806 // 807 // lgammal: 808 // library: libm.so 809 // versions: 2.4 2.23 810 // targets: ... powerpc64-linux-gnu s390x-linux-gnu 811 // lgammal: 812 // library: libm.so 813 // versions: 2.2 2.23 814 // targets: sparc64-linux-gnu s390x-linux-gnu 815 // 816 // If we don't handle this, we end up writing the default `lgammal` symbol for version 2.33 817 // twice, which causes a "duplicate symbol" assembler error. 818 var versions_written: std.array_hash_map.Auto(Version, void) = .empty; 819 820 var inc_reader: Io.Reader = .fixed(metadata.inclusions); 821 822 const fn_inclusions_len = try inc_reader.takeInt(u16, .little); 823 824 while (sym_i < fn_inclusions_len) : (sym_i += 1) { 825 const sym_name = opt_symbol_name orelse n: { 826 sym_name_buf.clearRetainingCapacity(); 827 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0); 828 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API 829 inc_reader.toss(1); 830 831 opt_symbol_name = sym_name_buf.written(); 832 versions_buffer = undefined; 833 versions_len = 0; 834 835 break :n sym_name_buf.written(); 836 }; 837 const targets = try inc_reader.takeLeb128(u64); 838 var lib_index = try inc_reader.takeByte(); 839 840 const is_terminal = (lib_index & (1 << 7)) != 0; 841 if (is_terminal) { 842 lib_index &= ~@as(u8, 1 << 7); 843 opt_symbol_name = null; 844 } 845 846 // Test whether the inclusion applies to our current library and target. 847 const ok_lib_and_target = 848 (lib_index == lib_i) and 849 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); 850 851 while (true) { 852 const byte = try inc_reader.takeByte(); 853 const last = (byte & 0b1000_0000) != 0; 854 const ver_i = @as(u7, @truncate(byte)); 855 if (ok_lib_and_target and ver_i <= target_ver_index) { 856 versions_buffer[versions_len] = ver_i; 857 versions_len += 1; 858 } 859 if (last) break; 860 } 861 862 if (!is_terminal) continue; 863 864 // Pick the default symbol version: 865 // - If there are no versions, don't emit it 866 // - Take the greatest one <= than the target one 867 // - If none of them is <= than the 868 // specified one don't pick any default version 869 if (versions_len == 0) continue; 870 var chosen_def_ver_index: u8 = 255; 871 { 872 var ver_buf_i: u8 = 0; 873 while (ver_buf_i < versions_len) : (ver_buf_i += 1) { 874 const ver_index = versions_buffer[ver_buf_i]; 875 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) { 876 chosen_def_ver_index = ver_index; 877 } 878 } 879 } 880 881 versions_written.clearRetainingCapacity(); 882 try versions_written.ensureTotalCapacity(arena, versions_len); 883 884 { 885 var ver_buf_i: u8 = 0; 886 while (ver_buf_i < versions_len) : (ver_buf_i += 1) { 887 // Example: 888 // .balign 4 889 // .globl _Exit_2_2_5 890 // .type _Exit_2_2_5, %function 891 // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5, remove 892 // _Exit_2_2_5: .long 0 893 const ver_index = versions_buffer[ver_buf_i]; 894 const ver = metadata.all_versions[ver_index]; 895 896 if (versions_written.getOrPutAssumeCapacity(ver).found_existing) continue; 897 898 // Default symbol version definition vs normal symbol version definition 899 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index; 900 const at_sign_str: []const u8 = if (want_default) "@@" else "@"; 901 if (ver.patch == 0) { 902 const sym_plus_ver = try std.fmt.allocPrint( 903 arena, 904 "{s}_{d}_{d}", 905 .{ sym_name, ver.major, ver.minor }, 906 ); 907 try stubs_asm.print( 908 \\.balign {d} 909 \\.globl {s} 910 \\.type {s}, %function 911 \\.symver {s}, {s}{s}GLIBC_{d}.{d}, remove 912 \\{s}: {s} 0 913 \\ 914 , .{ 915 target.ptrBitWidth() / 8, 916 sym_plus_ver, 917 sym_plus_ver, 918 sym_plus_ver, 919 sym_name, 920 at_sign_str, 921 ver.major, 922 ver.minor, 923 sym_plus_ver, 924 wordDirective(target), 925 }); 926 } else { 927 const sym_plus_ver = try std.fmt.allocPrint( 928 arena, 929 "{s}_{d}_{d}_{d}", 930 .{ sym_name, ver.major, ver.minor, ver.patch }, 931 ); 932 try stubs_asm.print( 933 \\.balign {d} 934 \\.globl {s} 935 \\.type {s}, %function 936 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}, remove 937 \\{s}: {s} 0 938 \\ 939 , .{ 940 target.ptrBitWidth() / 8, 941 sym_plus_ver, 942 sym_plus_ver, 943 sym_plus_ver, 944 sym_name, 945 at_sign_str, 946 ver.major, 947 ver.minor, 948 ver.patch, 949 sym_plus_ver, 950 wordDirective(target), 951 }); 952 } 953 } 954 } 955 } 956 957 try stubs_asm.appendSlice(".rodata\n"); 958 959 // For some targets, the real `libc.so.6` will contain a weak reference to `_IO_stdin_used`, 960 // making the linker put the symbol in the dynamic symbol table. We likewise need to emit a 961 // reference to it here for that effect, or it will not show up, which in turn will cause 962 // the real glibc to think that the program was built against an ancient `FILE` structure 963 // (pre-glibc 2.1). 964 // 965 // Note that glibc only compiles in the legacy compatibility code for some targets; it 966 // depends on what is defined in the `shlib-versions` file for the particular architecture 967 // and ABI. Those files are preprocessed by 2 separate tools during the glibc build to get 968 // the final `abi-versions.h`, so it would be quite brittle to try to condition our emission 969 // of the `_IO_stdin_used` reference in the exact same way. The only downside of emitting 970 // the reference unconditionally is that it ends up being unused for newer targets; it 971 // otherwise has no negative effect. 972 // 973 // glibc uses a weak reference because it has to work with programs compiled against pre-2.1 974 // versions where the symbol didn't exist. We only care about modern glibc versions, so use 975 // a strong reference. 976 if (std.mem.eql(u8, lib.name, "c")) { 977 try stubs_asm.print( 978 \\.balign {d} 979 \\.globl _IO_stdin_used 980 \\{s} _IO_stdin_used 981 \\ 982 , .{ 983 target.ptrBitWidth() / 8, 984 wordDirective(target), 985 }); 986 } 987 988 try stubs_asm.appendSlice(".data\n"); 989 990 const obj_inclusions_len = try inc_reader.takeInt(u16, .little); 991 992 var sizes = try arena.alloc(u16, metadata.all_versions.len); 993 994 sym_i = 0; 995 opt_symbol_name = null; 996 versions_buffer = undefined; 997 versions_len = undefined; 998 while (sym_i < obj_inclusions_len) : (sym_i += 1) { 999 const sym_name = opt_symbol_name orelse n: { 1000 sym_name_buf.clearRetainingCapacity(); 1001 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0); 1002 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API 1003 inc_reader.toss(1); 1004 1005 opt_symbol_name = sym_name_buf.written(); 1006 versions_buffer = undefined; 1007 versions_len = 0; 1008 1009 break :n sym_name_buf.written(); 1010 }; 1011 const targets = try inc_reader.takeLeb128(u64); 1012 const size = try inc_reader.takeLeb128(u16); 1013 var lib_index = try inc_reader.takeByte(); 1014 1015 const is_terminal = (lib_index & (1 << 7)) != 0; 1016 if (is_terminal) { 1017 lib_index &= ~@as(u8, 1 << 7); 1018 opt_symbol_name = null; 1019 } 1020 1021 // Test whether the inclusion applies to our current library and target. 1022 const ok_lib_and_target = 1023 (lib_index == lib_i) and 1024 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); 1025 1026 while (true) { 1027 const byte = try inc_reader.takeByte(); 1028 const last = (byte & 0b1000_0000) != 0; 1029 const ver_i = @as(u7, @truncate(byte)); 1030 if (ok_lib_and_target and ver_i <= target_ver_index) { 1031 versions_buffer[versions_len] = ver_i; 1032 versions_len += 1; 1033 sizes[ver_i] = size; 1034 } 1035 if (last) break; 1036 } 1037 1038 if (!is_terminal) continue; 1039 1040 // Pick the default symbol version: 1041 // - If there are no versions, don't emit it 1042 // - Take the greatest one <= than the target one 1043 // - If none of them is <= than the 1044 // specified one don't pick any default version 1045 if (versions_len == 0) continue; 1046 var chosen_def_ver_index: u8 = 255; 1047 { 1048 var ver_buf_i: u8 = 0; 1049 while (ver_buf_i < versions_len) : (ver_buf_i += 1) { 1050 const ver_index = versions_buffer[ver_buf_i]; 1051 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) { 1052 chosen_def_ver_index = ver_index; 1053 } 1054 } 1055 } 1056 1057 versions_written.clearRetainingCapacity(); 1058 try versions_written.ensureTotalCapacity(arena, versions_len); 1059 1060 { 1061 var ver_buf_i: u8 = 0; 1062 while (ver_buf_i < versions_len) : (ver_buf_i += 1) { 1063 // Example: 1064 // .balign 4 1065 // .globl environ_2_2_5 1066 // .type environ_2_2_5, %object 1067 // .size environ_2_2_5, 4 1068 // .symver environ_2_2_5, environ@@GLIBC_2.2.5, remove 1069 // environ_2_2_5: .fill 4, 1, 0 1070 const ver_index = versions_buffer[ver_buf_i]; 1071 const ver = metadata.all_versions[ver_index]; 1072 1073 if (versions_written.getOrPutAssumeCapacity(ver).found_existing) continue; 1074 1075 // Default symbol version definition vs normal symbol version definition 1076 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index; 1077 const at_sign_str: []const u8 = if (want_default) "@@" else "@"; 1078 if (ver.patch == 0) { 1079 const sym_plus_ver = try std.fmt.allocPrint( 1080 arena, 1081 "{s}_{d}_{d}", 1082 .{ sym_name, ver.major, ver.minor }, 1083 ); 1084 try stubs_asm.print( 1085 \\.balign {d} 1086 \\.globl {s} 1087 \\.type {s}, %object 1088 \\.size {s}, {d} 1089 \\.symver {s}, {s}{s}GLIBC_{d}.{d}, remove 1090 \\{s}: .fill {d}, 1, 0 1091 \\ 1092 , .{ 1093 target.ptrBitWidth() / 8, 1094 sym_plus_ver, 1095 sym_plus_ver, 1096 sym_plus_ver, 1097 sizes[ver_index], 1098 sym_plus_ver, 1099 sym_name, 1100 at_sign_str, 1101 ver.major, 1102 ver.minor, 1103 sym_plus_ver, 1104 sizes[ver_index], 1105 }); 1106 } else { 1107 const sym_plus_ver = try std.fmt.allocPrint( 1108 arena, 1109 "{s}_{d}_{d}_{d}", 1110 .{ sym_name, ver.major, ver.minor, ver.patch }, 1111 ); 1112 try stubs_asm.print( 1113 \\.balign {d} 1114 \\.globl {s} 1115 \\.type {s}, %object 1116 \\.size {s}, {d} 1117 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}, remove 1118 \\{s}: .fill {d}, 1, 0 1119 \\ 1120 , .{ 1121 target.ptrBitWidth() / 8, 1122 sym_plus_ver, 1123 sym_plus_ver, 1124 sym_plus_ver, 1125 sizes[ver_index], 1126 sym_plus_ver, 1127 sym_name, 1128 at_sign_str, 1129 ver.major, 1130 ver.minor, 1131 ver.patch, 1132 sym_plus_ver, 1133 sizes[ver_index], 1134 }); 1135 } 1136 } 1137 } 1138 } 1139 1140 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc. 1141 const asm_file_basename = std.mem.print(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable; 1142 try o_directory.handle.writeFile(io, .{ .sub_path = asm_file_basename, .data = stubs_asm.items }); 1143 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node); 1144 } 1145 1146 man.finalize() catch |err| log.warn("failed to write cache manifest for glibc stubs: {t}", .{err}); 1147 1148 return queueSharedObjects(comp, .{ 1149 .lock = man.toOwnedLock(), 1150 .dir_path = .{ 1151 .root_dir = comp.dirs.global_cache, 1152 .sub_path = try gpa.dupe(u8, "o" ++ path.sep_str ++ digest), 1153 }, 1154 }); 1155 } 1156 1157 fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) std.Io.Cancelable!void { 1158 const io = comp.io; 1159 const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?; 1160 1161 assert(comp.glibc_so_files == null); 1162 comp.glibc_so_files = so_files; 1163 1164 var task_buffer: [libs.len]link.PrelinkTask = undefined; 1165 var task_buffer_i: usize = 0; 1166 1167 { 1168 comp.mutex.lockUncancelable(io); // protect comp.arena 1169 defer comp.mutex.unlock(io); 1170 1171 for (libs) |lib| { 1172 if (lib.removed_in) |rem_in| { 1173 if (target_version.order(rem_in) != .lt) continue; 1174 } 1175 const so_path: Path = .{ 1176 .root_dir = so_files.dir_path.root_dir, 1177 .sub_path = std.fmt.allocPrint(comp.arena, "{s}{c}lib{s}.so.{d}", .{ 1178 so_files.dir_path.sub_path, path.sep, lib.name, lib.sover, 1179 }) catch return comp.setAllocFailure(), 1180 }; 1181 task_buffer[task_buffer_i] = .{ .load_dso = so_path }; 1182 task_buffer_i += 1; 1183 } 1184 } 1185 1186 try comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]); 1187 } 1188 1189 fn buildSharedLib( 1190 comp: *Compilation, 1191 arena: Allocator, 1192 bin_directory: Cache.Directory, 1193 asm_file_basename: []const u8, 1194 lib: Lib, 1195 prog_node: std.Progress.Node, 1196 ) !void { 1197 const tracy = trace(@src()); 1198 defer tracy.end(); 1199 1200 const io = comp.io; 1201 const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }); 1202 const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; 1203 const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); 1204 const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; 1205 1206 const optimize_mode = comp.compilerRtOptMode(); 1207 const strip = comp.compilerRtStrip(); 1208 const config = try Compilation.Config.resolve(.{ 1209 .output_mode = .Lib, 1210 .link_mode = .dynamic, 1211 .resolved_target = comp.root_mod.resolved_target, 1212 .is_test = false, 1213 .have_zcu = false, 1214 .emit_bin = true, 1215 .root_optimize_mode = optimize_mode, 1216 .root_strip = strip, 1217 .link_libc = false, 1218 }); 1219 1220 const root_mod = try Module.create(arena, .{ 1221 .paths = .{ 1222 .root = .zig_lib_root, 1223 .root_src_path = "", 1224 }, 1225 .fully_qualified_name = "root", 1226 .inherited = .{ 1227 .resolved_target = comp.root_mod.resolved_target, 1228 .strip = strip, 1229 .stack_check = false, 1230 .stack_protector = 0, 1231 .sanitize_c = .off, 1232 .sanitize_thread = false, 1233 .red_zone = comp.root_mod.red_zone, 1234 .omit_frame_pointer = comp.root_mod.omit_frame_pointer, 1235 .valgrind = false, 1236 .optimize_mode = optimize_mode, 1237 }, 1238 .global = config, 1239 .cc_argv = &.{}, 1240 .parent = null, 1241 }); 1242 1243 const c_source_files = [1]Compilation.CSourceFile{ 1244 .{ 1245 .src_path = try path.join(arena, &.{ bin_directory.path.?, asm_file_basename }), 1246 .owner = root_mod, 1247 }, 1248 }; 1249 1250 const misc_task: Compilation.MiscTask = .@"glibc shared object"; 1251 1252 var sub_create_diag: Compilation.CreateDiagnostic = undefined; 1253 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{ 1254 .thread_limit = comp.thread_limit, 1255 .dirs = comp.dirs.withoutLocalCache(), 1256 .self_exe_path = comp.self_exe_path, 1257 // Because we manually cache the whole set of objects, we don't cache the individual objects 1258 // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path. 1259 .cache_mode = .none, 1260 .config = config, 1261 .root_mod = root_mod, 1262 .root_name = lib.name, 1263 .libc_installation = comp.libc_installation, 1264 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, 1265 .verbose_cc = comp.verbose_cc, 1266 .verbose_link = comp.verbose_link, 1267 .verbose_air = comp.verbose_air, 1268 .verbose_llvm_ir = comp.verbose_llvm_ir, 1269 .verbose_llvm_bc = comp.verbose_llvm_bc, 1270 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 1271 .clang_passthrough_mode = comp.clang_passthrough_mode, 1272 .version = version, 1273 .version_script = .{ 1274 .root_dir = bin_directory, 1275 .sub_path = all_map_basename, 1276 }, 1277 .soname = soname, 1278 .c_source_files = &c_source_files, 1279 .skip_linker_dependencies = true, 1280 .environ_map = comp.environ_map, 1281 }) catch |err| switch (err) { 1282 error.CreateFail => { 1283 comp.lockAndSetMiscFailure(misc_task, "sub-compilation of {t} failed: {f}", .{ misc_task, sub_create_diag }); 1284 return error.AlreadyReported; 1285 }, 1286 else => |e| return e, 1287 }; 1288 defer sub_compilation.destroy(); 1289 1290 try comp.updateSubCompilation(sub_compilation, misc_task, prog_node); 1291 } 1292 1293 pub fn needsCrt0(output_mode: std.lang.OutputMode) ?CrtFile { 1294 return switch (output_mode) { 1295 .Obj, .Lib => null, 1296 .Exe => .scrt1_o, 1297 }; 1298 } 1299