Commit dcb7f5791a

Jakub Konka <kubkon@jakubkonka.com>
2024-02-08 13:22:48
macho: alloc improvement for relocatable
1 parent 1028463
Changed files (2)
src/link/MachO/relocatable.zig
@@ -437,18 +437,20 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
 
 fn allocateSections(macho_file: *MachO) !void {
     const slice = macho_file.sections.slice();
-
-    const last_index = for (0..slice.items(.header).len) |i| {
-        if (macho_file.isZigSection(@intCast(i))) break i;
-    } else slice.items(.header).len;
-
-    for (slice.items(.header)[0..last_index]) |*header| {
+    for (slice.items(.header)) |*header| {
+        const needed_size = header.size;
+        header.size = 0;
         const alignment = try math.powi(u32, 2, header.@"align");
         if (!header.isZerofill()) {
-            header.offset = math.cast(u32, macho_file.findFreeSpace(header.size, alignment)) orelse
-                return error.Overflow;
+            if (needed_size > macho_file.allocatedSize(header.offset)) {
+                header.offset = math.cast(u32, macho_file.findFreeSpace(needed_size, alignment)) orelse
+                    return error.Overflow;
+            }
+        }
+        if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) {
+            header.addr = macho_file.findFreeSpaceVirtual(needed_size, alignment);
         }
-        header.addr = macho_file.findFreeSpaceVirtual(header.size, alignment);
+        header.size = needed_size;
     }
 }
 
src/link/MachO.zig
@@ -3202,20 +3202,22 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
 
     const end = start + padToIdeal(size);
 
-    for (self.sections.items(.header)) |header| {
-        if (header.isZerofill()) continue;
-        const increased_size = padToIdeal(header.size);
-        const test_end = header.offset +| increased_size;
-        if (end > header.offset and start < test_end) {
-            return test_end;
+    if (self.base.isRelocatable()) {
+        for (self.sections.items(.header)) |header| {
+            if (header.isZerofill()) continue;
+            const increased_size = padToIdeal(header.size);
+            const test_end = header.offset +| increased_size;
+            if (end > header.offset and start < test_end) {
+                return test_end;
+            }
         }
-    }
-
-    for (self.segments.items) |seg| {
-        const increased_size = padToIdeal(seg.filesize);
-        const test_end = seg.fileoff +| increased_size;
-        if (end > seg.fileoff and start < test_end) {
-            return test_end;
+    } else {
+        for (self.segments.items) |seg| {
+            const increased_size = padToIdeal(seg.filesize);
+            const test_end = seg.fileoff +| increased_size;
+            if (end > seg.fileoff and start < test_end) {
+                return test_end;
+            }
         }
     }
 
@@ -3223,27 +3225,29 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
 }
 
 fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {
-    // Conservatively commit one page size as reserved space for the headers as we
-    // expect it to grow and everything else be moved in flush anyhow.
-    const header_size = self.getPageSize();
-    if (start < header_size)
-        return header_size;
-
     const end = start + padToIdeal(size);
 
-    for (self.sections.items(.header)) |header| {
-        const increased_size = padToIdeal(header.size);
-        const test_end = header.addr +| increased_size;
-        if (end > header.addr and start < test_end) {
-            return test_end;
+    if (self.base.isRelocatable()) {
+        for (self.sections.items(.header)) |header| {
+            const increased_size = padToIdeal(header.size);
+            const test_end = header.addr +| increased_size;
+            if (end > header.addr and start < test_end) {
+                return test_end;
+            }
         }
-    }
+    } else {
+        // Conservatively commit one page size as reserved space for the headers as we
+        // expect it to grow and everything else be moved in flush anyhow.
+        const header_size = self.getPageSize();
+        if (start < header_size)
+            return header_size;
 
-    for (self.segments.items) |seg| {
-        const increased_size = padToIdeal(seg.vmsize);
-        const test_end = seg.vmaddr +| increased_size;
-        if (end > seg.vmaddr and start < test_end) {
-            return test_end;
+        for (self.segments.items) |seg| {
+            const increased_size = padToIdeal(seg.vmsize);
+            const test_end = seg.vmaddr +| increased_size;
+            if (end > seg.vmaddr and start < test_end) {
+                return test_end;
+            }
         }
     }
 
@@ -3252,21 +3256,29 @@ fn detectAllocCollisionVirtual(self: *MachO, start: u64, size: u64) ?u64 {
 
 pub fn allocatedSize(self: *MachO, start: u64) u64 {
     if (start == 0) return 0;
+
     var min_pos: u64 = std.math.maxInt(u64);
-    for (self.sections.items(.header)) |header| {
-        if (header.offset <= start) continue;
-        if (header.offset < min_pos) min_pos = header.offset;
-    }
-    for (self.segments.items) |seg| {
-        if (seg.fileoff <= start) continue;
-        if (seg.fileoff < min_pos) min_pos = seg.fileoff;
+
+    if (self.base.isRelocatable()) {
+        for (self.sections.items(.header)) |header| {
+            if (header.offset <= start) continue;
+            if (header.offset < min_pos) min_pos = header.offset;
+        }
+    } else {
+        for (self.segments.items) |seg| {
+            if (seg.fileoff <= start) continue;
+            if (seg.fileoff < min_pos) min_pos = seg.fileoff;
+        }
     }
+
     return min_pos - start;
 }
 
 pub fn allocatedSizeVirtual(self: *MachO, start: u64) u64 {
     if (start == 0) return 0;
+
     var min_pos: u64 = std.math.maxInt(u64);
+
     if (self.base.isRelocatable()) {
         for (self.sections.items(.header)) |header| {
             if (header.addr <= start) continue;