| ... | @@ -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 | } |
| 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 | fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 { | 3143 | fn 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 | } |
| 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 | 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 | } |
| 3269 | | 3319 | |
| 3270 | pub fn getTarget(self: MachO) std.Target { | 3320 | pub fn getTarget(self: MachO) std.Target { |