Commit 060406a526

Jakub Konka <kubkon@jakubkonka.com>
2024-01-21 10:54:03
macho: ensure we zero-out regions after copying them over
This is to ensure that the loader correctly zeroes-out zerofill sections when mapping them. For context, Apple's loader dyld will map the regions where any zerofill would theoretically reside as belonging to zerofill section.
1 parent 3a64109
Changed files (2)
src
arch
x86_64
link
src/arch/x86_64/Lower.zig
@@ -440,9 +440,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
                             });
                             lower.result_insts_len += 1;
                             emit_mnemonic = .mov;
-                            break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
-                                .base = .{ .reg = .rax },
-                            }) };
+                            break :op .{ .reg = .rax };
                         }
 
                         _ = lower.reloc(.{ .linker_reloc = sym });
src/link/MachO.zig
@@ -2346,9 +2346,7 @@ fn allocateSections(self: *MachO) !void {
                 new_offset + existing_size,
             });
 
-            const amt = try self.base.file.?.copyRangeAll(header.offset, self.base.file.?, new_offset, existing_size);
-            // TODO figure out what to about this error condition - how to communicate it up.
-            if (amt != existing_size) return error.InputOutput;
+            try self.copyRangeAllZeroOut(header.offset, new_offset, existing_size);
 
             header.offset = @intCast(new_offset);
             header.size = existing_size;
@@ -3268,6 +3266,19 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 {
     return start;
 }
 
+/// Like File.copyRangeAll but also ensures the source region is zeroed out after copy.
+/// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader.
+fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void {
+    const gpa = self.base.comp.gpa;
+    const file = self.base.file.?;
+    const amt = try file.copyRangeAll(old_offset, file, new_offset, size);
+    if (amt != size) return error.InputOutput;
+    const zeroes = try gpa.alloc(u8, size);
+    defer gpa.free(zeroes);
+    @memset(zeroes, 0);
+    try file.pwriteAll(zeroes, old_offset);
+}
+
 const InitMetadataOptions = struct {
     symbol_count_hint: u64,
     program_code_size_hint: u64,
@@ -3408,9 +3419,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
             new_offset + existing_size,
         });
 
-        const amt = try self.base.file.?.copyRangeAll(sect.offset, self.base.file.?, new_offset, existing_size);
-        // TODO figure out what to about this error condition - how to communicate it up.
-        if (amt != existing_size) return error.InputOutput;
+        try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
 
         sect.offset = @intCast(new_offset);
         seg.fileoff = new_offset;