Commit 6756aaccf1

Jakub Konka <kubkon@jakubkonka.com>
2024-07-04 22:01:19
macho: do not save rpaths globally in the driver
1 parent 76c3b6b
Changed files (2)
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});
@@ -61,7 +63,17 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
     }
     // LC_RPATH
     {
-        for (macho_file.rpaths.items) |rpath| {
+        for (macho_file.base.rpath_list) |rpath| {
+            sizeofcmds += calcInstallNameLen(
+                @sizeOf(macho.rpath_command),
+                rpath,
+                assume_max_path_len,
+            );
+        }
+
+        if (comp.config.any_sanitize_thread) {
+            const path = comp.tsan_dynamic_lib.?.full_object_path;
+            const rpath = std.fs.path.dirname(path) orelse ".";
             sizeofcmds += calcInstallNameLen(
                 @sizeOf(macho.rpath_command),
                 rpath,
@@ -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);
     }
 }
 
src/link/MachO.zig
@@ -150,7 +150,6 @@ no_implicit_dylibs: bool = false,
 /// Whether the linker should parse and always force load objects containing ObjC in archives.
 // TODO: in Zig we currently take -ObjC as always on
 force_load_objc: bool = true,
-rpaths: std.ArrayListUnmanaged([]const u8) = .{},
 
 /// Hot-code swapping state.
 hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
@@ -359,8 +358,6 @@ pub fn deinit(self: *MachO) void {
     }
     self.thunks.deinit(gpa);
     self.unwind_records.deinit(gpa);
-
-    self.rpaths.deinit(gpa);
 }
 
 pub fn flush(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
@@ -398,9 +395,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node)
     if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
     if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
 
-    try self.rpaths.ensureUnusedCapacity(gpa, self.base.rpath_list.len);
-    self.rpaths.appendSliceAssumeCapacity(self.base.rpath_list);
-
     var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
     defer positionals.deinit();
 
@@ -419,10 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node)
 
     // TSAN
     if (comp.config.any_sanitize_thread) {
-        const path = comp.tsan_dynamic_lib.?.full_object_path;
-        try positionals.append(.{ .path = path });
-        const basename = std.fs.path.dirname(path) orelse ".";
-        try self.rpaths.append(gpa, basename);
+        try positionals.append(.{ .path = comp.tsan_dynamic_lib.?.full_object_path });
     }
 
     for (positionals.items) |obj| {
@@ -780,7 +771,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
             try argv.append(syslibroot);
         }
 
-        for (self.rpaths.items) |rpath| {
+        for (self.base.rpath_list) |rpath| {
             try argv.append("-rpath");
             try argv.append(rpath);
         }
@@ -840,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
         }
 
         if (comp.config.any_sanitize_thread) {
-            try argv.append(comp.tsan_dynamic_lib.?.full_object_path);
+            const path = comp.tsan_dynamic_lib.?.full_object_path;
+            try argv.append(path);
+            try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." });
         }
 
         for (self.lib_dirs) |lib_dir| {
@@ -2968,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);
@@ -3024,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
         ncmds += 1;
     }
 
-    try load_commands.writeRpathLCs(self.rpaths.items, writer);
-    ncmds += self.rpaths.items.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_dynamic_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;