From dcb7f5791a206d7713bea153a8d94f22dfb155a9 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 8 Feb 2024 13:22:48 +0100 Subject: [PATCH] macho: alloc improvement for relocatable --- src/link/MachO.zig | 86 +++++++++++++++++++--------------- src/link/MachO/relocatable.zig | 20 ++++---- 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index d018cc01a2..e6923bbbe9 100644 --- a/src/link/MachO.zig +++ b/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; diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index b5241c498e..f6dd2e99e2 100644 --- a/src/link/MachO/relocatable.zig +++ b/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; + } } - header.addr = macho_file.findFreeSpaceVirtual(header.size, alignment); + if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) { + header.addr = macho_file.findFreeSpaceVirtual(needed_size, alignment); + } + header.size = needed_size; } }