authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-18 16:52:41+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:41+01:00
log6cd4c7612f7d0c1bf21695c29432296823875c46
tree36d232fa04e9f5f6b60f7730cefe70ce381d4cdf
parent2169a5559dedd1ea245264a0e642347677af91b8

macho: implement growSection mechanism


1 files changed, 53 insertions(+), 3 deletions(-)

src/link/MachO.zig+53-3
...@@ -3130,6 +3130,16 @@ fn allocatedSize(self: *MachO, start: u64) u64 {...@@ -3130,6 +3130,16 @@ fn allocatedSize(self: *MachO, start: u64) u64 {
3130 return min_pos - start;3130 return min_pos - start;
3131}3131}
31323132
3133fn allocatedVirtualSize(self: *MachO, start: u64) u64 {
3134 if (start == 0) return 0;
3135 var min_pos: u64 = std.math.maxInt(u64);
3136 for (self.segments.items) |seg| {
3137 if (seg.vmaddr <= start) continue;
3138 if (seg.vmaddr < min_pos) min_pos = seg.vmaddr;
3139 }
3140 return min_pos - start;
3141}
3142
3133fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 {3143fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 {
3134 var start: u64 = 0;3144 var start: u64 = 0;
3135 while (self.detectAllocCollision(start, object_size)) |item_end| {3145 while (self.detectAllocCollision(start, object_size)) |item_end| {
...@@ -3261,10 +3271,50 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3261,10 +3271,50 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3261 }3271 }
3262}3272}
32633273
3264pub fn growSection(self: *MachO, sect_index: u8, size: u64) !void {3274pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3265 const sect = &self.sections.items(.header)[sect_index];3275 const sect = &self.sections.items(.header)[sect_index];
3266 std.debug.print("curr={x}, needed={x}\n", .{ sect.size, size });3276 const seg_id = self.sections.items(.segment_id)[sect_index];
3267 @panic("TODO growSection");3277 const seg = &self.segments.items[seg_id];
3278
3279 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {
3280 const existing_size = sect.size;
3281 sect.size = 0;
3282
3283 // Must move the entire section.
3284 const new_offset = self.findFreeSpace(needed_size, self.getPageSize());
3285
3286 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{
3287 sect.segName(),
3288 sect.sectName(),
3289 new_offset,
3290 new_offset + existing_size,
3291 });
3292
3293 const amt = try self.base.file.?.copyRangeAll(sect.offset, self.base.file.?, new_offset, existing_size);
3294 // TODO figure out what to about this error condition - how to communicate it up.
3295 if (amt != existing_size) return error.InputOutput;
3296
3297 sect.offset = @intCast(new_offset);
3298 seg.fileoff = new_offset;
3299 }
3300
3301 sect.size = needed_size;
3302 if (!sect.isZerofill()) {
3303 seg.filesize = needed_size;
3304 }
3305
3306 const mem_capacity = self.allocatedVirtualSize(seg.vmaddr);
3307 if (needed_size > mem_capacity) {
3308 var err = try self.addErrorWithNotes(2);
3309 try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{
3310 seg_id,
3311 seg.segName(),
3312 });
3313 try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});
3314 try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
3315 }
3316
3317 seg.vmsize = needed_size;
3268}3318}
32693319
3270pub fn getTarget(self: MachO) std.Target {3320pub fn getTarget(self: MachO) std.Target {