| ... | ... | @@ -3130,6 +3130,16 @@ fn allocatedSize(self: *MachO, start: u64) u64 { |
| 3130 | 3130 | return min_pos - start; |
| 3131 | 3131 | } |
| 3132 | 3132 | |
| 3133 | fn 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 | |
| 3133 | 3143 | fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { |
| 3134 | 3144 | var start: u64 = 0; |
| 3135 | 3145 | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| ... | ... | @@ -3261,10 +3271,50 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3261 | 3271 | } |
| 3262 | 3272 | } |
| 3263 | 3273 | |
| 3264 | | pub fn growSection(self: *MachO, sect_index: u8, size: u64) !void { |
| 3274 | pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3265 | 3275 | const sect = &self.sections.items(.header)[sect_index]; |
| 3266 | | std.debug.print("curr={x}, needed={x}\n", .{ sect.size, size }); |
| 3267 | | @panic("TODO growSection"); |
| 3276 | const seg_id = self.sections.items(.segment_id)[sect_index]; |
| 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 | } |
| 3269 | 3319 | |
| 3270 | 3320 | pub fn getTarget(self: MachO) std.Target { |