commit de61540c2d049b0774dd9c5e14aa8f65ed1c25ed (tree)
parent d9f1a952b8b0e19aafcf568b35cc220adbb4a7b5
Author: Jakub Konka <kubkon@jakubkonka.com>
Date: Fri, 5 Jul 2024 00:33:46 +0200
Merge pull request #20496 from ziglang/macos-tsan
Diffstat:
5 files changed, 79 insertions(+), 36 deletions(-)
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -185,9 +185,9 @@ libcxxabi_static_lib: ?CRTFile = null,
/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libunwind_static_lib: ?CRTFile = null,
-/// Populated when we build the TSAN static library. A Job to build this is placed in the queue
+/// Populated when we build the TSAN library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
-tsan_static_lib: ?CRTFile = null,
+tsan_lib: ?CRTFile = null,
/// Populated when we build the libc static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libc_static_lib: ?CRTFile = null,
diff --git a/src/libtsan.zig b/src/libtsan.zig
@@ -25,10 +25,19 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
- const root_name = "tsan";
- const output_mode = .Lib;
- const link_mode = .static;
const target = comp.getTarget();
+ const root_name = switch (target.os.tag) {
+ // On Apple platforms, we use the same name as LLVM because the
+ // TSAN library implementation hard-codes a check for these names.
+ .macos => "clang_rt.tsan_osx_dynamic",
+ .ios => switch (target.abi) {
+ .simulator => "clang_rt.tsan_iossim_dynamic",
+ else => "clang_rt.tsan_ios_dynamic",
+ },
+ else => "tsan",
+ };
+ const link_mode: std.builtin.LinkMode = if (target.isDarwin()) .dynamic else .static;
+ const output_mode = .Lib;
const basename = try std.zig.binNameAlloc(arena, .{
.root_name = root_name,
.target = target,
@@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
const optimize_mode = comp.compilerRtOptMode();
const strip = comp.compilerRtStrip();
+ const link_libcpp = target.isDarwin();
const config = Compilation.Config.resolve(.{
.output_mode = output_mode,
@@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
.root_optimize_mode = optimize_mode,
.root_strip = strip,
.link_libc = true,
+ .link_libcpp = link_libcpp,
}) catch |err| {
comp.setMiscFailure(
.libtsan,
@@ -272,6 +283,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
});
}
+ const skip_linker_dependencies = !target.isDarwin();
+ const linker_allow_shlib_undefined = target.isDarwin();
+ const install_name = if (target.isDarwin())
+ try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename})
+ else
+ null;
+ // Workaround for https://github.com/llvm/llvm-project/issues/97627
+ const headerpad_size: ?u32 = if (target.isDarwin()) 32 else null;
const sub_compilation = Compilation.create(comp.gpa, arena, .{
.local_cache_directory = comp.global_cache_directory,
.global_cache_directory = comp.global_cache_directory,
@@ -294,7 +313,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
- .skip_linker_dependencies = true,
+ .skip_linker_dependencies = skip_linker_dependencies,
+ .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
+ .install_name = install_name,
+ .headerpad_size = headerpad_size,
}) catch |err| {
comp.setMiscFailure(
.libtsan,
@@ -317,8 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
},
};
- assert(comp.tsan_static_lib == null);
- comp.tsan_static_lib = try sub_compilation.toCrtFile();
+ assert(comp.tsan_lib == null);
+ comp.tsan_lib = try sub_compilation.toCrtFile();
}
const tsan_sources = [_][]const u8{
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
@@ -1145,7 +1145,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) l
// TSAN
if (comp.config.any_sanitize_thread) {
- try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path });
+ try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path });
}
// libc
@@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
}
if (comp.config.any_sanitize_thread) {
- try argv.append(comp.tsan_static_lib.?.full_object_path);
+ try argv.append(comp.tsan_lib.?.full_object_path);
}
// libc
@@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void
}
if (comp.config.any_sanitize_thread) {
- try argv.append(comp.tsan_static_lib.?.full_object_path);
+ try argv.append(comp.tsan_lib.?.full_object_path);
}
// libc
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
@@ -192,7 +192,7 @@ pub fn createEmpty(
null
else
try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path});
- const allow_shlib_undefined = options.allow_shlib_undefined orelse comp.config.any_sanitize_thread;
+ const allow_shlib_undefined = options.allow_shlib_undefined orelse false;
const self = try arena.create(MachO);
self.* = .{
@@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node)
// TSAN
if (comp.config.any_sanitize_thread) {
- try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path });
+ try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path });
}
for (positionals.items) |obj| {
@@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
}
if (comp.config.any_sanitize_thread) {
- try argv.append(comp.tsan_static_lib.?.full_object_path);
+ const path = comp.tsan_lib.?.full_object_path;
+ try argv.append(path);
+ try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." });
}
for (self.lib_dirs) |lib_dir| {
@@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 {
}
fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
- const gpa = self.base.comp.gpa;
+ const comp = self.base.comp;
+ const gpa = comp.gpa;
const needed_size = try load_commands.calcLoadCommandsSize(self, false);
const buffer = try gpa.alloc(u8, needed_size);
defer gpa.free(buffer);
@@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
ncmds += 1;
}
- try load_commands.writeRpathLCs(self.base.rpath_list, writer);
- ncmds += self.base.rpath_list.len;
+ for (self.base.rpath_list) |rpath| {
+ try load_commands.writeRpathLC(rpath, writer);
+ ncmds += 1;
+ }
+ if (comp.config.any_sanitize_thread) {
+ const path = comp.tsan_lib.?.full_object_path;
+ const rpath = std.fs.path.dirname(path) orelse ".";
+ try load_commands.writeRpathLC(rpath, writer);
+ ncmds += 1;
+ }
try writer.writeStruct(macho.source_version_command{ .version = 0 });
ncmds += 1;
diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig
@@ -18,6 +18,9 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool
}
pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 {
+ const comp = macho_file.base.comp;
+ const gpa = comp.gpa;
+
var sizeofcmds: u64 = 0;
// LC_SEGMENT_64
@@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
}
// LC_ID_DYLIB
if (macho_file.base.isDynLib()) {
- const gpa = macho_file.base.comp.gpa;
const emit = macho_file.base.emit;
const install_name = macho_file.install_name orelse
try emit.directory.join(gpa, &.{emit.sub_path});
@@ -68,6 +70,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
assume_max_path_len,
);
}
+
+ if (comp.config.any_sanitize_thread) {
+ const path = comp.tsan_lib.?.full_object_path;
+ const rpath = std.fs.path.dirname(path) orelse ".";
+ sizeofcmds += calcInstallNameLen(
+ @sizeOf(macho.rpath_command),
+ rpath,
+ assume_max_path_len,
+ );
+ }
}
// LC_SOURCE_VERSION
sizeofcmds += @sizeOf(macho.source_version_command);
@@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
}, writer);
}
-pub fn writeRpathLCs(rpaths: []const []const u8, writer: anytype) !void {
- for (rpaths) |rpath| {
- const rpath_len = rpath.len + 1;
- const cmdsize = @as(u32, @intCast(mem.alignForward(
- u64,
- @sizeOf(macho.rpath_command) + rpath_len,
- @sizeOf(u64),
- )));
- try writer.writeStruct(macho.rpath_command{
- .cmdsize = cmdsize,
- .path = @sizeOf(macho.rpath_command),
- });
- try writer.writeAll(rpath);
- try writer.writeByte(0);
- const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
- if (padding > 0) {
- try writer.writeByteNTimes(0, padding);
- }
+pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
+ const rpath_len = rpath.len + 1;
+ const cmdsize = @as(u32, @intCast(mem.alignForward(
+ u64,
+ @sizeOf(macho.rpath_command) + rpath_len,
+ @sizeOf(u64),
+ )));
+ try writer.writeStruct(macho.rpath_command{
+ .cmdsize = cmdsize,
+ .path = @sizeOf(macho.rpath_command),
+ });
+ try writer.writeAll(rpath);
+ try writer.writeByte(0);
+ const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
+ if (padding > 0) {
+ try writer.writeByteNTimes(0, padding);
}
}