| 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,9 +185,9 @@ libcxxabi_static_lib: ?CRTFile = null, |
| 185 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue | 185 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue |
| 186 | /// and resolved before calling linker.flush(). | 186 | /// and resolved before calling linker.flush(). |
| 187 | libunwind_static_lib: ?CRTFile = null, | 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 | /// and resolved before calling linker.flush(). | 189 | /// and resolved before calling linker.flush(). |
| 190 | tsan_static_lib: ?CRTFile = null, | 190 | tsan_lib: ?CRTFile = null, |
| 191 | /// Populated when we build the libc static library. A Job to build this is placed in the queue | 191 | /// Populated when we build the libc static library. A Job to build this is placed in the queue |
| 192 | /// and resolved before calling linker.flush(). | 192 | /// and resolved before calling linker.flush(). |
| 193 | libc_static_lib: ?CRTFile = null, | 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,10 +25,19 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 25 | defer arena_allocator.deinit(); | 25 | defer arena_allocator.deinit(); |
| 26 | const arena = arena_allocator.allocator(); | 26 | const arena = arena_allocator.allocator(); |
| 27 | 27 | ||
| 28 | const root_name = "tsan"; | ||
| 29 | const output_mode = .Lib; | ||
| 30 | const link_mode = .static; | ||
| 31 | const target = comp.getTarget(); | 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 | const basename = try std.zig.binNameAlloc(arena, .{ | 41 | const basename = try std.zig.binNameAlloc(arena, .{ |
| 33 | .root_name = root_name, | 42 | .root_name = root_name, |
| 34 | .target = target, | 43 | .target = target, |
| ... | @@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo | ... | @@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 43 | 52 | ||
| 44 | const optimize_mode = comp.compilerRtOptMode(); | 53 | const optimize_mode = comp.compilerRtOptMode(); |
| 45 | const strip = comp.compilerRtStrip(); | 54 | const strip = comp.compilerRtStrip(); |
| 55 | const link_libcpp = target.isDarwin(); | ||
| 46 | 56 | ||
| 47 | const config = Compilation.Config.resolve(.{ | 57 | const config = Compilation.Config.resolve(.{ |
| 48 | .output_mode = output_mode, | 58 | .output_mode = output_mode, |
| ... | @@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo | ... | @@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 54 | .root_optimize_mode = optimize_mode, | 64 | .root_optimize_mode = optimize_mode, |
| 55 | .root_strip = strip, | 65 | .root_strip = strip, |
| 56 | .link_libc = true, | 66 | .link_libc = true, |
| 67 | .link_libcpp = link_libcpp, | ||
| 57 | }) catch |err| { | 68 | }) catch |err| { |
| 58 | comp.setMiscFailure( | 69 | comp.setMiscFailure( |
| 59 | .libtsan, | 70 | .libtsan, |
| ... | @@ -272,6 +283,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo | ... | @@ -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 | const sub_compilation = Compilation.create(comp.gpa, arena, .{ | 294 | const sub_compilation = Compilation.create(comp.gpa, arena, .{ |
| 276 | .local_cache_directory = comp.global_cache_directory, | 295 | .local_cache_directory = comp.global_cache_directory, |
| 277 | .global_cache_directory = comp.global_cache_directory, | 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,7 +313,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 294 | .verbose_cimport = comp.verbose_cimport, | 313 | .verbose_cimport = comp.verbose_cimport, |
| 295 | .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, | 314 | .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, |
| 296 | .clang_passthrough_mode = comp.clang_passthrough_mode, | 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 | }) catch |err| { | 320 | }) catch |err| { |
| 299 | comp.setMiscFailure( | 321 | comp.setMiscFailure( |
| 300 | .libtsan, | 322 | .libtsan, |
| ... | @@ -317,8 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo | ... | @@ -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); | 342 | assert(comp.tsan_lib == null); |
| 321 | comp.tsan_static_lib = try sub_compilation.toCrtFile(); | 343 | comp.tsan_lib = try sub_compilation.toCrtFile(); |
| 322 | } | 344 | } |
| 323 | 345 | ||
| 324 | const tsan_sources = [_][]const u8{ | 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,7 +1145,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) l |
| 1145 | 1145 | ||
| 1146 | // TSAN | 1146 | // TSAN |
| 1147 | if (comp.config.any_sanitize_thread) { | 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 | // libc | 1151 | // libc |
| ... | @@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { | ... | @@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1603 | } | 1603 | } |
| 1604 | 1604 | ||
| 1605 | if (comp.config.any_sanitize_thread) { | 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 | // libc | 1609 | // libc |
| ... | @@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void | ... | @@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void |
| 2610 | } | 2610 | } |
| 2611 | 2611 | ||
| 2612 | if (comp.config.any_sanitize_thread) { | 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 | // libc | 2616 | // libc |
src/link/MachO.zig+17-6| ... | @@ -192,7 +192,7 @@ pub fn createEmpty( | ... | @@ -192,7 +192,7 @@ pub fn createEmpty( |
| 192 | null | 192 | null |
| 193 | else | 193 | else |
| 194 | try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); | 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 | const self = try arena.create(MachO); | 197 | const self = try arena.create(MachO); |
| 198 | self.* = .{ | 198 | self.* = .{ |
| ... | @@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) | ... | @@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) |
| 413 | 413 | ||
| 414 | // TSAN | 414 | // TSAN |
| 415 | if (comp.config.any_sanitize_thread) { | 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 | for (positionals.items) |obj| { | 419 | for (positionals.items) |obj| { |
| ... | @@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { | ... | @@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | if (comp.config.any_sanitize_thread) { | 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 | for (self.lib_dirs) |lib_dir| { | 839 | for (self.lib_dirs) |lib_dir| { |
| ... | @@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 { | ... | @@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 { |
| 2959 | } | 2961 | } |
| 2960 | 2962 | ||
| 2961 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { | 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 | const needed_size = try load_commands.calcLoadCommandsSize(self, false); | 2966 | const needed_size = try load_commands.calcLoadCommandsSize(self, false); |
| 2964 | const buffer = try gpa.alloc(u8, needed_size); | 2967 | const buffer = try gpa.alloc(u8, needed_size); |
| 2965 | defer gpa.free(buffer); | 2968 | defer gpa.free(buffer); |
| ... | @@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { | ... | @@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 3015 | ncmds += 1; | 3018 | ncmds += 1; |
| 3016 | } | 3019 | } |
| 3017 | 3020 | ||
| 3018 | try load_commands.writeRpathLCs(self.base.rpath_list, writer); | 3021 | for (self.base.rpath_list) |rpath| { |
| 3019 | ncmds += self.base.rpath_list.len; | 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 | try writer.writeStruct(macho.source_version_command{ .version = 0 }); | 3032 | try writer.writeStruct(macho.source_version_command{ .version = 0 }); |
| 3022 | ncmds += 1; | 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,6 +18,9 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 { | 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 | var sizeofcmds: u64 = 0; | 24 | var sizeofcmds: u64 = 0; |
| 22 | 25 | ||
| 23 | // LC_SEGMENT_64 | 26 | // LC_SEGMENT_64 |
| ... | @@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 | ... | @@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 |
| 48 | } | 51 | } |
| 49 | // LC_ID_DYLIB | 52 | // LC_ID_DYLIB |
| 50 | if (macho_file.base.isDynLib()) { | 53 | if (macho_file.base.isDynLib()) { |
| 51 | const gpa = macho_file.base.comp.gpa; | ||
| 52 | const emit = macho_file.base.emit; | 54 | const emit = macho_file.base.emit; |
| 53 | const install_name = macho_file.install_name orelse | 55 | const install_name = macho_file.install_name orelse |
| 54 | try emit.directory.join(gpa, &.{emit.sub_path}); | 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,6 +70,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 |
| 68 | assume_max_path_len, | 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 | // LC_SOURCE_VERSION | 84 | // LC_SOURCE_VERSION |
| 73 | sizeofcmds += @sizeOf(macho.source_version_command); | 85 | sizeofcmds += @sizeOf(macho.source_version_command); |
| ... | @@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { | ... | @@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { |
| 245 | }, writer); | 257 | }, writer); |
| 246 | } | 258 | } |
| 247 | 259 | ||
| 248 | pub fn writeRpathLCs(rpaths: []const []const u8, writer: anytype) !void { | 260 | pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void { |
| 249 | for (rpaths) |rpath| { | 261 | const rpath_len = rpath.len + 1; |
| 250 | const rpath_len = rpath.len + 1; | 262 | const cmdsize = @as(u32, @intCast(mem.alignForward( |
| 251 | const cmdsize = @as(u32, @intCast(mem.alignForward( | 263 | u64, |
| 252 | u64, | 264 | @sizeOf(macho.rpath_command) + rpath_len, |
| 253 | @sizeOf(macho.rpath_command) + rpath_len, | 265 | @sizeOf(u64), |
| 254 | @sizeOf(u64), | 266 | ))); |
| 255 | ))); | 267 | try writer.writeStruct(macho.rpath_command{ |
| 256 | try writer.writeStruct(macho.rpath_command{ | 268 | .cmdsize = cmdsize, |
| 257 | .cmdsize = cmdsize, | 269 | .path = @sizeOf(macho.rpath_command), |
| 258 | .path = @sizeOf(macho.rpath_command), | 270 | }); |
| 259 | }); | 271 | try writer.writeAll(rpath); |
| 260 | try writer.writeAll(rpath); | 272 | try writer.writeByte(0); |
| 261 | try writer.writeByte(0); | 273 | const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; |
| 262 | const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; | 274 | if (padding > 0) { |
| 263 | if (padding > 0) { | 275 | try writer.writeByteNTimes(0, padding); |
| 264 | try writer.writeByteNTimes(0, padding); | ||
| 265 | } | ||
| 266 | } | 276 | } |
| 267 | } | 277 | } |
| 268 | 278 |