| author | |
| committer | |
| log | de61540c2d049b0774dd9c5e14aa8f65ed1c25ed |
| tree | 9185a2671aeeff937a0809a55a50bff7b9b83e8b |
| parent | d9f1a952b8b0e19aafcf568b35cc220adbb4a7b5 |
| parent | d2cace58bd031e72b830ebd42f5946f4000e52a4 |
| signature |
5 files changed, 79 insertions(+), 36 deletions(-)
src/Compilation.zig+2-2| ... | ... | @@ -185,9 +185,9 @@ libcxxabi_static_lib: ?CRTFile = null, |
| 185 | 185 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue |
| 186 | 186 | /// and resolved before calling linker.flush(). |
| 187 | 187 | libunwind_static_lib: ?CRTFile = null, |
| 188 | /// Populated when we build the TSAN static library. A Job to build this is placed in the queue | |
| 188 | /// Populated when we build the TSAN library. A Job to build this is placed in the queue | |
| 189 | 189 | /// and resolved before calling linker.flush(). |
| 190 | tsan_static_lib: ?CRTFile = null, | |
| 190 | tsan_lib: ?CRTFile = null, | |
| 191 | 191 | /// Populated when we build the libc static library. A Job to build this is placed in the queue |
| 192 | 192 | /// and resolved before calling linker.flush(). |
| 193 | 193 | libc_static_lib: ?CRTFile = null, |
src/libtsan.zig+28-6| ... | ... | @@ -25,10 +25,19 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 25 | 25 | defer arena_allocator.deinit(); |
| 26 | 26 | const arena = arena_allocator.allocator(); |
| 27 | 27 | |
| 28 | const root_name = "tsan"; | |
| 29 | const output_mode = .Lib; | |
| 30 | const link_mode = .static; | |
| 31 | 28 | const target = comp.getTarget(); |
| 29 | const root_name = switch (target.os.tag) { | |
| 30 | // On Apple platforms, we use the same name as LLVM because the | |
| 31 | // TSAN library implementation hard-codes a check for these names. | |
| 32 | .macos => "clang_rt.tsan_osx_dynamic", | |
| 33 | .ios => switch (target.abi) { | |
| 34 | .simulator => "clang_rt.tsan_iossim_dynamic", | |
| 35 | else => "clang_rt.tsan_ios_dynamic", | |
| 36 | }, | |
| 37 | else => "tsan", | |
| 38 | }; | |
| 39 | const link_mode: std.builtin.LinkMode = if (target.isDarwin()) .dynamic else .static; | |
| 40 | const output_mode = .Lib; | |
| 32 | 41 | const basename = try std.zig.binNameAlloc(arena, .{ |
| 33 | 42 | .root_name = root_name, |
| 34 | 43 | .target = target, |
| ... | ... | @@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 43 | 52 | |
| 44 | 53 | const optimize_mode = comp.compilerRtOptMode(); |
| 45 | 54 | const strip = comp.compilerRtStrip(); |
| 55 | const link_libcpp = target.isDarwin(); | |
| 46 | 56 | |
| 47 | 57 | const config = Compilation.Config.resolve(.{ |
| 48 | 58 | .output_mode = output_mode, |
| ... | ... | @@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 54 | 64 | .root_optimize_mode = optimize_mode, |
| 55 | 65 | .root_strip = strip, |
| 56 | 66 | .link_libc = true, |
| 67 | .link_libcpp = link_libcpp, | |
| 57 | 68 | }) catch |err| { |
| 58 | 69 | comp.setMiscFailure( |
| 59 | 70 | .libtsan, |
| ... | ... | @@ -272,6 +283,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 272 | 283 | }); |
| 273 | 284 | } |
| 274 | 285 | |
| 286 | const skip_linker_dependencies = !target.isDarwin(); | |
| 287 | const linker_allow_shlib_undefined = target.isDarwin(); | |
| 288 | const install_name = if (target.isDarwin()) | |
| 289 | try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename}) | |
| 290 | else | |
| 291 | null; | |
| 292 | // Workaround for https://github.com/llvm/llvm-project/issues/97627 | |
| 293 | const headerpad_size: ?u32 = if (target.isDarwin()) 32 else null; | |
| 275 | 294 | const sub_compilation = Compilation.create(comp.gpa, arena, .{ |
| 276 | 295 | .local_cache_directory = comp.global_cache_directory, |
| 277 | 296 | .global_cache_directory = comp.global_cache_directory, |
| ... | ... | @@ -294,7 +313,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 294 | 313 | .verbose_cimport = comp.verbose_cimport, |
| 295 | 314 | .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, |
| 296 | 315 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 297 | .skip_linker_dependencies = true, | |
| 316 | .skip_linker_dependencies = skip_linker_dependencies, | |
| 317 | .linker_allow_shlib_undefined = linker_allow_shlib_undefined, | |
| 318 | .install_name = install_name, | |
| 319 | .headerpad_size = headerpad_size, | |
| 298 | 320 | }) catch |err| { |
| 299 | 321 | comp.setMiscFailure( |
| 300 | 322 | .libtsan, |
| ... | ... | @@ -317,8 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 317 | 339 | }, |
| 318 | 340 | }; |
| 319 | 341 | |
| 320 | assert(comp.tsan_static_lib == null); | |
| 321 | comp.tsan_static_lib = try sub_compilation.toCrtFile(); | |
| 342 | assert(comp.tsan_lib == null); | |
| 343 | comp.tsan_lib = try sub_compilation.toCrtFile(); | |
| 322 | 344 | } |
| 323 | 345 | |
| 324 | 346 | const tsan_sources = [_][]const u8{ |
src/link/Elf.zig+3-3| ... | ... | @@ -1145,7 +1145,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) l |
| 1145 | 1145 | |
| 1146 | 1146 | // TSAN |
| 1147 | 1147 | if (comp.config.any_sanitize_thread) { |
| 1148 | try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path }); | |
| 1148 | try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path }); | |
| 1149 | 1149 | } |
| 1150 | 1150 | |
| 1151 | 1151 | // libc |
| ... | ... | @@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1603 | 1603 | } |
| 1604 | 1604 | |
| 1605 | 1605 | if (comp.config.any_sanitize_thread) { |
| 1606 | try argv.append(comp.tsan_static_lib.?.full_object_path); | |
| 1606 | try argv.append(comp.tsan_lib.?.full_object_path); | |
| 1607 | 1607 | } |
| 1608 | 1608 | |
| 1609 | 1609 | // libc |
| ... | ... | @@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void |
| 2610 | 2610 | } |
| 2611 | 2611 | |
| 2612 | 2612 | if (comp.config.any_sanitize_thread) { |
| 2613 | try argv.append(comp.tsan_static_lib.?.full_object_path); | |
| 2613 | try argv.append(comp.tsan_lib.?.full_object_path); | |
| 2614 | 2614 | } |
| 2615 | 2615 | |
| 2616 | 2616 | // libc |
src/link/MachO.zig+17-6| ... | ... | @@ -192,7 +192,7 @@ pub fn createEmpty( |
| 192 | 192 | null |
| 193 | 193 | else |
| 194 | 194 | try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); |
| 195 | const allow_shlib_undefined = options.allow_shlib_undefined orelse comp.config.any_sanitize_thread; | |
| 195 | const allow_shlib_undefined = options.allow_shlib_undefined orelse false; | |
| 196 | 196 | |
| 197 | 197 | const self = try arena.create(MachO); |
| 198 | 198 | self.* = .{ |
| ... | ... | @@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) |
| 413 | 413 | |
| 414 | 414 | // TSAN |
| 415 | 415 | if (comp.config.any_sanitize_thread) { |
| 416 | try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path }); | |
| 416 | try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path }); | |
| 417 | 417 | } |
| 418 | 418 | |
| 419 | 419 | for (positionals.items) |obj| { |
| ... | ... | @@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 831 | 831 | } |
| 832 | 832 | |
| 833 | 833 | if (comp.config.any_sanitize_thread) { |
| 834 | try argv.append(comp.tsan_static_lib.?.full_object_path); | |
| 834 | const path = comp.tsan_lib.?.full_object_path; | |
| 835 | try argv.append(path); | |
| 836 | try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." }); | |
| 835 | 837 | } |
| 836 | 838 | |
| 837 | 839 | for (self.lib_dirs) |lib_dir| { |
| ... | ... | @@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 { |
| 2959 | 2961 | } |
| 2960 | 2962 | |
| 2961 | 2963 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2962 | const gpa = self.base.comp.gpa; | |
| 2964 | const comp = self.base.comp; | |
| 2965 | const gpa = comp.gpa; | |
| 2963 | 2966 | const needed_size = try load_commands.calcLoadCommandsSize(self, false); |
| 2964 | 2967 | const buffer = try gpa.alloc(u8, needed_size); |
| 2965 | 2968 | defer gpa.free(buffer); |
| ... | ... | @@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 3015 | 3018 | ncmds += 1; |
| 3016 | 3019 | } |
| 3017 | 3020 | |
| 3018 | try load_commands.writeRpathLCs(self.base.rpath_list, writer); | |
| 3019 | ncmds += self.base.rpath_list.len; | |
| 3021 | for (self.base.rpath_list) |rpath| { | |
| 3022 | try load_commands.writeRpathLC(rpath, writer); | |
| 3023 | ncmds += 1; | |
| 3024 | } | |
| 3025 | if (comp.config.any_sanitize_thread) { | |
| 3026 | const path = comp.tsan_lib.?.full_object_path; | |
| 3027 | const rpath = std.fs.path.dirname(path) orelse "."; | |
| 3028 | try load_commands.writeRpathLC(rpath, writer); | |
| 3029 | ncmds += 1; | |
| 3030 | } | |
| 3020 | 3031 | |
| 3021 | 3032 | try writer.writeStruct(macho.source_version_command{ .version = 0 }); |
| 3022 | 3033 | ncmds += 1; |
src/link/MachO/load_commands.zig+29-19| ... | ... | @@ -18,6 +18,9 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 { |
| 21 | const comp = macho_file.base.comp; | |
| 22 | const gpa = comp.gpa; | |
| 23 | ||
| 21 | 24 | var sizeofcmds: u64 = 0; |
| 22 | 25 | |
| 23 | 26 | // LC_SEGMENT_64 |
| ... | ... | @@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 |
| 48 | 51 | } |
| 49 | 52 | // LC_ID_DYLIB |
| 50 | 53 | if (macho_file.base.isDynLib()) { |
| 51 | const gpa = macho_file.base.comp.gpa; | |
| 52 | 54 | const emit = macho_file.base.emit; |
| 53 | 55 | const install_name = macho_file.install_name orelse |
| 54 | 56 | try emit.directory.join(gpa, &.{emit.sub_path}); |
| ... | ... | @@ -68,6 +70,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 |
| 68 | 70 | assume_max_path_len, |
| 69 | 71 | ); |
| 70 | 72 | } |
| 73 | ||
| 74 | if (comp.config.any_sanitize_thread) { | |
| 75 | const path = comp.tsan_lib.?.full_object_path; | |
| 76 | const rpath = std.fs.path.dirname(path) orelse "."; | |
| 77 | sizeofcmds += calcInstallNameLen( | |
| 78 | @sizeOf(macho.rpath_command), | |
| 79 | rpath, | |
| 80 | assume_max_path_len, | |
| 81 | ); | |
| 82 | } | |
| 71 | 83 | } |
| 72 | 84 | // LC_SOURCE_VERSION |
| 73 | 85 | sizeofcmds += @sizeOf(macho.source_version_command); |
| ... | ... | @@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { |
| 245 | 257 | }, writer); |
| 246 | 258 | } |
| 247 | 259 | |
| 248 | pub fn writeRpathLCs(rpaths: []const []const u8, writer: anytype) !void { | |
| 249 | for (rpaths) |rpath| { | |
| 250 | const rpath_len = rpath.len + 1; | |
| 251 | const cmdsize = @as(u32, @intCast(mem.alignForward( | |
| 252 | u64, | |
| 253 | @sizeOf(macho.rpath_command) + rpath_len, | |
| 254 | @sizeOf(u64), | |
| 255 | ))); | |
| 256 | try writer.writeStruct(macho.rpath_command{ | |
| 257 | .cmdsize = cmdsize, | |
| 258 | .path = @sizeOf(macho.rpath_command), | |
| 259 | }); | |
| 260 | try writer.writeAll(rpath); | |
| 261 | try writer.writeByte(0); | |
| 262 | const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; | |
| 263 | if (padding > 0) { | |
| 264 | try writer.writeByteNTimes(0, padding); | |
| 265 | } | |
| 260 | pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void { | |
| 261 | const rpath_len = rpath.len + 1; | |
| 262 | const cmdsize = @as(u32, @intCast(mem.alignForward( | |
| 263 | u64, | |
| 264 | @sizeOf(macho.rpath_command) + rpath_len, | |
| 265 | @sizeOf(u64), | |
| 266 | ))); | |
| 267 | try writer.writeStruct(macho.rpath_command{ | |
| 268 | .cmdsize = cmdsize, | |
| 269 | .path = @sizeOf(macho.rpath_command), | |
| 270 | }); | |
| 271 | try writer.writeAll(rpath); | |
| 272 | try writer.writeByte(0); | |
| 273 | const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; | |
| 274 | if (padding > 0) { | |
| 275 | try writer.writeByteNTimes(0, padding); | |
| 266 | 276 | } |
| 267 | 277 | } |
| 268 | 278 |