| author | |
| committer | |
| log | 76afdd0586dc646bee1f20fd9ff23c044d70a211 |
| tree | 1c7e56b81b76ed53fc27b72e7d0242866417ceb7 |
| parent | e1e414e62a86cc460ef215ea8050c953b68b6080 |
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 to | 424 | // 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 |
| 662 | 662 | ||
| 663 | if (codesig) |*csig| { | 663 | if (codesig) |*csig| { |
| 664 | try self.writeCodeSignature(comp, csig); // code signing always comes last | 664 | 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 | } |
| 666 | 668 | ||
| 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 |
| 691 | 693 | ||
| 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. | ||
| 705 | pub 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 | |||
| 694 | inline fn conformUuid(out: *[Md5.digest_length]u8) void { | 711 | inline fn conformUuid(out: *[Md5.digest_length]u8) void { |
| 695 | // LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats | 712 | // 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 |
| 4172 | 4172 | ||
| 4173 | if (codesig) |*csig| { | 4173 | if (codesig) |*csig| { |
| 4174 | try zld.writeCodeSignature(comp, csig); // code signing always comes last | 4174 | 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 | } |
| 4177 | 4178 |