Commit dc222c9ba5
Changed files (2)
src
link
src/link/MachO/relocatable.zig
@@ -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;
src/link/MachO.zig
@@ -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.?);
}