macho: use findFreeSpace for all sections

This commit is contained in:
Jakub Konka
2024-02-02 20:26:50 +01:00
parent c5155170b2
commit dc222c9ba5
2 changed files with 48 additions and 48 deletions

View File

@@ -3275,6 +3275,34 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
return null;
}
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;
}
}
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;
}
}
return null;
}
fn allocatedSize(self: *MachO, start: u64) u64 {
if (start == 0) return 0;
var min_pos: u64 = std.math.maxInt(u64);
@@ -3307,6 +3335,14 @@ pub fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 {
return start;
}
pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32) u64 {
var start: u64 = 0;
while (self.detectAllocCollisionVirtual(start, object_size)) |item_end| {
start = mem.alignForward(u64, item_end, min_alignment);
}
return start;
}
pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void {
const file = self.base.file.?;
const amt = try file.copyRangeAll(old_offset, file, new_offset, size);
@@ -3411,7 +3447,11 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
fn allocSect(macho_file: *MachO, sect_id: u8, size: u64) !void {
const sect = &macho_file.sections.items(.header)[sect_id];
const alignment = try math.powi(u32, 2, sect.@"align");
sect.offset = @intCast(macho_file.findFreeSpace(size, alignment));
if (!sect.isZerofill()) {
sect.offset = math.cast(u32, macho_file.findFreeSpace(size, alignment)) orelse
return error.Overflow;
}
sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);
sect.size = size;
}
}.allocSect;
@@ -3462,7 +3502,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
.flags = macho.S_ZEROFILL,
});
if (self.base.isRelocatable()) {
self.sections.items(.header)[self.zig_bss_sect_index.?].size = 1024;
try allocSect(self, self.zig_bss_sect_index.?, 1024);
} else {
appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?);
}

View File

@@ -59,8 +59,7 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
try calcSectionSizes(macho_file);
try createSegment(macho_file);
try allocateSectionsVM(macho_file);
try allocateSectionsFile(macho_file);
try allocateSections(macho_file);
allocateSegment(macho_file);
macho_file.allocateAtoms();
@@ -224,58 +223,20 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
sect.@"align" = 3;
}
fn allocateSectionsVM(macho_file: *MachO) !void {
var vmaddr: u64 = 0;
const slice = macho_file.sections.slice();
for (slice.items(.header)) |*header| {
const alignment = try math.powi(u32, 2, header.@"align");
vmaddr = mem.alignForward(u64, vmaddr, alignment);
header.addr = vmaddr;
vmaddr += header.size;
}
}
fn allocateSectionsFile(macho_file: *MachO) !void {
var fileoff = load_commands.calcLoadCommandsSizeObject(macho_file) + @sizeOf(macho.mach_header_64);
fn allocateSections(macho_file: *MachO) !void {
const slice = macho_file.sections.slice();
const last_index = for (slice.items(.header), 0..) |header, i| {
if (mem.indexOf(u8, header.segName(), "ZIG")) |_| break i;
} else slice.items(.header).len;
// TODO: I actually think for relocatable we can just use findFreeSpace
// all the way since there is a single segment involved anyhow.
for (slice.items(.header)[0..last_index]) |*header| {
if (header.isZerofill()) continue;
const alignment = try math.powi(u32, 2, header.@"align");
fileoff = mem.alignForward(u32, fileoff, alignment);
header.offset = fileoff;
fileoff += @intCast(header.size);
}
for (slice.items(.header)[last_index..]) |*header| {
if (header.isZerofill()) continue;
if (header.offset < fileoff) {
const existing_size = header.size;
header.size = 0;
// Must move the entire section.
const alignment = try math.powi(u32, 2, header.@"align");
const new_offset = macho_file.findFreeSpace(existing_size, alignment);
log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{
header.segName(),
header.sectName(),
new_offset,
new_offset + existing_size,
});
try macho_file.copyRangeAll(header.offset, new_offset, existing_size);
header.offset = @intCast(new_offset);
header.size = existing_size;
if (!header.isZerofill()) {
header.offset = math.cast(u32, macho_file.findFreeSpace(header.size, alignment)) orelse
return error.Overflow;
}
header.addr = macho_file.findFreeSpaceVirtual(header.size, alignment);
}
}
@@ -308,7 +269,6 @@ fn allocateSegment(macho_file: *MachO) void {
if (!header.isZerofill()) {
fileoff = @max(fileoff, header.offset + header.size);
}
std.debug.print("fileoff={x},vmaddr={x}\n", .{ fileoff, vmaddr });
}
seg.vmsize = vmaddr - seg.vmaddr;