Commit 9fb44e8e1f

Jakub Konka <kubkon@jakubkonka.com>
2021-09-09 00:25:55
macho: precompute total required size when parsing objects
This way, we can preallocate the necessary sizes for segments and sections upfront rather than doing it per parsed atom.
1 parent e00b9d6
Changed files (1)
src
src/link/MachO.zig
@@ -2589,6 +2589,47 @@ fn resolveDyldStubBinder(self: *MachO) !void {
 }
 
 fn parseTextBlocks(self: *MachO) !void {
+    var section_metadata = std.AutoHashMap(MatchingSection, struct {
+        size: u64,
+        alignment: u32,
+    }).init(self.base.allocator);
+    defer section_metadata.deinit();
+
+    for (self.objects.items) |object| {
+        const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
+        for (seg.sections.items) |sect| {
+            const match = (try self.getMatchingSection(sect)) orelse {
+                log.debug("unhandled section", .{});
+                continue;
+            };
+            const res = try section_metadata.getOrPut(match);
+            if (!res.found_existing) {
+                res.value_ptr.* = .{
+                    .size = 0,
+                    .alignment = 0,
+                };
+            }
+            const alignment = try math.powi(u32, 2, sect.@"align");
+            res.value_ptr.size += mem.alignForwardGeneric(u64, sect.size, alignment);
+            res.value_ptr.alignment = math.max(res.value_ptr.alignment, sect.@"align");
+        }
+    }
+
+    var it = section_metadata.iterator();
+    while (it.next()) |entry| {
+        const match = entry.key_ptr.*;
+        const metadata = entry.value_ptr.*;
+        const seg = self.load_commands.items[match.seg].Segment;
+        const sect = seg.sections.items[match.sect];
+        log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
+            commands.segmentName(sect),
+            commands.sectionName(sect),
+            metadata.size,
+            metadata.alignment,
+        });
+        try self.growSection(match, @intCast(u32, metadata.size));
+    }
+
     for (self.objects.items) |*object, object_id| {
         try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);
     }