authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-16 17:11:44+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-16 17:30:25+01:00
log76afdd0586dc646bee1f20fd9ff23c044d70a211
tree1c7e56b81b76ed53fc27b72e7d0242866417ceb7
parente1e414e62a86cc460ef215ea8050c953b68b6080

link: move macOS kernel inode cache invalidation to MachO linker


3 files changed, 19 insertions(+), 20 deletions(-)

src/link.zig+1-20
...@@ -418,26 +418,7 @@ pub const File = struct {...@@ -418,26 +418,7 @@ pub const File = struct {
418 .Exe => {},418 .Exe => {},
419 }419 }
420 switch (base.tag) {420 switch (base.tag) {
421 .macho => if (base.file) |f| {421 .coff, .elf, .macho, .plan9, .wasm => if (base.file) |f| {
422 if (build_options.only_c) unreachable;
423 if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
424 if (base.options.target.cpu.arch == .aarch64) {
425 // XNU starting with Big Sur running on arm64 is caching inodes of running binaries.
426 // Any change to the binary will effectively invalidate the kernel's cache
427 // resulting in a SIGKILL on each subsequent run. Since when doing incremental
428 // linking we're modifying a binary in-place, this will end up with the kernel
429 // killing it on every subsequent run. To circumvent it, we will copy the file
430 // into a new inode, remove the original file, and rename the copy to match
431 // the original file. This is super messy, but there doesn't seem any other
432 // way to please the XNU.
433 const emit = base.options.emit orelse return;
434 try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, emit.sub_path, .{});
435 }
436 }
437 f.close();
438 base.file = null;
439 },
440 .coff, .elf, .plan9, .wasm => if (base.file) |f| {
441 if (build_options.only_c) unreachable;422 if (build_options.only_c) unreachable;
442 if (base.intermediary_basename != null) {423 if (base.intermediary_basename != null) {
443 // The file we have open is not the final file that we want to424 // The file we have open is not the final file that we want to
src/link/MachO.zig+17
...@@ -662,6 +662,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -662,6 +662,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
662662
663 if (codesig) |*csig| {663 if (codesig) |*csig| {
664 try self.writeCodeSignature(comp, csig); // code signing always comes last664 try self.writeCodeSignature(comp, csig); // code signing always comes last
665 const emit = self.base.options.emit.?;
666 try invalidateKernelCache(emit.directory.handle, emit.sub_path);
665 }667 }
666668
667 if (self.d_sym) |*d_sym| {669 if (self.d_sym) |*d_sym| {
...@@ -691,6 +693,21 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -691,6 +693,21 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
691693
692 self.cold_start = false;694 self.cold_start = false;
693}695}
696
697/// XNU starting with Big Sur running on arm64 is caching inodes of running binaries.
698/// Any change to the binary will effectively invalidate the kernel's cache
699/// resulting in a SIGKILL on each subsequent run. Since when doing incremental
700/// linking we're modifying a binary in-place, this will end up with the kernel
701/// killing it on every subsequent run. To circumvent it, we will copy the file
702/// into a new inode, remove the original file, and rename the copy to match
703/// the original file. This is super messy, but there doesn't seem any other
704/// way to please the XNU.
705pub fn invalidateKernelCache(dir: std.fs.Dir, sub_path: []const u8) !void {
706 if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
707 try dir.copyFile(sub_path, dir, sub_path, .{});
708 }
709}
710
694inline fn conformUuid(out: *[Md5.digest_length]u8) void {711inline fn conformUuid(out: *[Md5.digest_length]u8) void {
695 // LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats712 // LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
696 out[6] = (out[6] & 0x0F) | (3 << 4);713 out[6] = (out[6] & 0x0F) | (3 << 4);
src/link/MachO/zld.zig+1
...@@ -4172,6 +4172,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -4172,6 +4172,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
41724172
4173 if (codesig) |*csig| {4173 if (codesig) |*csig| {
4174 try zld.writeCodeSignature(comp, csig); // code signing always comes last4174 try zld.writeCodeSignature(comp, csig); // code signing always comes last
4175 try MachO.invalidateKernelCache(directory.handle, zld.options.emit.?.sub_path);
4175 }4176 }
4176 }4177 }
41774178