| ... | @@ -194,10 +194,10 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, | ... | @@ -194,10 +194,10 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 194 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | 194 | /// overcapacity can be negative. A simple way to have negative overcapacity is to |
| 195 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | 195 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 196 | /// by 1 byte. It will then have -1 overcapacity. | 196 | /// by 1 byte. It will then have -1 overcapacity. |
| 197 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | 197 | block_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*TextBlock)) = .{}, |
| 198 | | 198 | |
| 199 | /// Pointer to the last allocated text block | 199 | /// Pointer to the last allocated text block |
| 200 | last_text_block: ?*TextBlock = null, | 200 | blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{}, |
| 201 | | 201 | |
| 202 | /// List of TextBlocks that are owned directly by the linker. | 202 | /// List of TextBlocks that are owned directly by the linker. |
| 203 | /// Currently these are only TextBlocks that are the result of linking | 203 | /// Currently these are only TextBlocks that are the result of linking |
| ... | @@ -206,8 +206,6 @@ last_text_block: ?*TextBlock = null, | ... | @@ -206,8 +206,6 @@ last_text_block: ?*TextBlock = null, |
| 206 | /// TODO consolidate this. | 206 | /// TODO consolidate this. |
| 207 | managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, | 207 | managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 208 | | 208 | |
| 209 | blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{}, | | |
| 210 | | | |
| 211 | /// Table of Decls that are currently alive. | 209 | /// Table of Decls that are currently alive. |
| 212 | /// We store them here so that we can properly dispose of any allocated | 210 | /// We store them here so that we can properly dispose of any allocated |
| 213 | /// memory within the TextBlock in the incremental linker. | 211 | /// memory within the TextBlock in the incremental linker. |
| ... | @@ -1535,6 +1533,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio | ... | @@ -1535,6 +1533,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1535 | | 1533 | |
| 1536 | if (res) |match| { | 1534 | if (res) |match| { |
| 1537 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); | 1535 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 1536 | _ = try self.block_free_lists.getOrPutValue(self.base.allocator, match, .{}); |
| 1538 | } | 1537 | } |
| 1539 | | 1538 | |
| 1540 | return res; | 1539 | return res; |
| ... | @@ -3417,8 +3416,13 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3417,8 +3416,13 @@ pub fn deinit(self: *MachO) void { |
| 3417 | } | 3416 | } |
| 3418 | self.managed_blocks.deinit(self.base.allocator); | 3417 | self.managed_blocks.deinit(self.base.allocator); |
| 3419 | self.blocks.deinit(self.base.allocator); | 3418 | self.blocks.deinit(self.base.allocator); |
| 3420 | self.text_block_free_list.deinit(self.base.allocator); | 3419 | { |
| 3421 | | 3420 | var it = self.block_free_lists.valueIterator(); |
| | 3421 | while (it.next()) |free_list| { |
| | 3422 | free_list.deinit(self.base.allocator); |
| | 3423 | } |
| | 3424 | self.block_free_lists.deinit(self.base.allocator); |
| | 3425 | } |
| 3422 | for (self.decls.keys()) |decl| { | 3426 | for (self.decls.keys()) |decl| { |
| 3423 | decl.link.macho.deinit(self.base.allocator); | 3427 | decl.link.macho.deinit(self.base.allocator); |
| 3424 | } | 3428 | } |
| ... | @@ -3441,16 +3445,21 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { | ... | @@ -3441,16 +3445,21 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 3441 | log.debug("freeTextBlock {*}", .{text_block}); | 3445 | log.debug("freeTextBlock {*}", .{text_block}); |
| 3442 | text_block.deinit(self.base.allocator); | 3446 | text_block.deinit(self.base.allocator); |
| 3443 | | 3447 | |
| | 3448 | const match = MatchingSection{ |
| | 3449 | .seg = self.text_segment_cmd_index.?, |
| | 3450 | .sect = self.text_section_index.?, |
| | 3451 | }; |
| | 3452 | const text_block_free_list = self.block_free_lists.getPtr(match).?; |
| 3444 | var already_have_free_list_node = false; | 3453 | var already_have_free_list_node = false; |
| 3445 | { | 3454 | { |
| 3446 | var i: usize = 0; | 3455 | var i: usize = 0; |
| 3447 | // TODO turn text_block_free_list into a hash map | 3456 | // TODO turn text_block_free_list into a hash map |
| 3448 | while (i < self.text_block_free_list.items.len) { | 3457 | while (i < text_block_free_list.items.len) { |
| 3449 | if (self.text_block_free_list.items[i] == text_block) { | 3458 | if (text_block_free_list.items[i] == text_block) { |
| 3450 | _ = self.text_block_free_list.swapRemove(i); | 3459 | _ = text_block_free_list.swapRemove(i); |
| 3451 | continue; | 3460 | continue; |
| 3452 | } | 3461 | } |
| 3453 | if (self.text_block_free_list.items[i] == text_block.prev) { | 3462 | if (text_block_free_list.items[i] == text_block.prev) { |
| 3454 | already_have_free_list_node = true; | 3463 | already_have_free_list_node = true; |
| 3455 | } | 3464 | } |
| 3456 | i += 1; | 3465 | i += 1; |
| ... | @@ -3458,10 +3467,15 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { | ... | @@ -3458,10 +3467,15 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 3458 | } | 3467 | } |
| 3459 | // TODO process free list for dbg info just like we do above for vaddrs | 3468 | // TODO process free list for dbg info just like we do above for vaddrs |
| 3460 | | 3469 | |
| 3461 | if (self.last_text_block == text_block) { | 3470 | if (self.blocks.getPtr(match)) |last_text_block| { |
| 3462 | // TODO shrink the __text section size here | 3471 | if (last_text_block.* == text_block) { |
| 3463 | self.last_text_block = text_block.prev; | 3472 | if (text_block.prev) |prev| { |
| | 3473 | // TODO shrink the __text section size here |
| | 3474 | last_text_block.* = prev; |
| | 3475 | } |
| | 3476 | } |
| 3464 | } | 3477 | } |
| | 3478 | |
| 3465 | if (self.d_sym) |*ds| { | 3479 | if (self.d_sym) |*ds| { |
| 3466 | if (ds.dbg_info_decl_first == text_block) { | 3480 | if (ds.dbg_info_decl_first == text_block) { |
| 3467 | ds.dbg_info_decl_first = text_block.dbg_info_next; | 3481 | ds.dbg_info_decl_first = text_block.dbg_info_next; |
| ... | @@ -3478,7 +3492,7 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { | ... | @@ -3478,7 +3492,7 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 3478 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { | 3492 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { |
| 3479 | // The free list is heuristics, it doesn't have to be perfect, so we can ignore | 3493 | // The free list is heuristics, it doesn't have to be perfect, so we can ignore |
| 3480 | // the OOM here. | 3494 | // the OOM here. |
| 3481 | self.text_block_free_list.append(self.base.allocator, prev) catch {}; | 3495 | text_block_free_list.append(self.base.allocator, prev) catch {}; |
| 3482 | } | 3496 | } |
| 3483 | } else { | 3497 | } else { |
| 3484 | text_block.prev = null; | 3498 | text_block.prev = null; |
| ... | @@ -4035,10 +4049,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4035,10 +4049,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4035 | .@"align" = alignment, | 4049 | .@"align" = alignment, |
| 4036 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 4050 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 4037 | }); | 4051 | }); |
| 4038 | _ = try self.section_ordinals.getOrPut(self.base.allocator, .{ | 4052 | const match = MatchingSection{ |
| 4039 | .seg = self.text_segment_cmd_index.?, | 4053 | .seg = self.text_segment_cmd_index.?, |
| 4040 | .sect = self.text_section_index.?, | 4054 | .sect = self.text_section_index.?, |
| 4041 | }); | 4055 | }; |
| | 4056 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 4057 | try self.block_free_lists.putNoClobber(self.base.allocator, match, .{}); |
| 4042 | self.load_commands_dirty = true; | 4058 | self.load_commands_dirty = true; |
| 4043 | } | 4059 | } |
| 4044 | | 4060 | |
| ... | @@ -4070,10 +4086,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4070,10 +4086,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4070 | .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 4086 | .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 4071 | .reserved2 = stub_size, | 4087 | .reserved2 = stub_size, |
| 4072 | }); | 4088 | }); |
| 4073 | _ = try self.section_ordinals.getOrPut(self.base.allocator, .{ | 4089 | const match = MatchingSection{ |
| 4074 | .seg = self.text_segment_cmd_index.?, | 4090 | .seg = self.text_segment_cmd_index.?, |
| 4075 | .sect = self.stubs_section_index.?, | 4091 | .sect = self.stubs_section_index.?, |
| 4076 | }); | 4092 | }; |
| | 4093 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 4094 | try self.block_free_lists.putNoClobber(self.base.allocator, match, .{}); |
| 4077 | self.load_commands_dirty = true; | 4095 | self.load_commands_dirty = true; |
| 4078 | } | 4096 | } |
| 4079 | | 4097 | |
| ... | @@ -4103,10 +4121,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4103,10 +4121,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4103 | .@"align" = alignment, | 4121 | .@"align" = alignment, |
| 4104 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | 4122 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 4105 | }); | 4123 | }); |
| 4106 | _ = try self.section_ordinals.getOrPut(self.base.allocator, .{ | 4124 | const match = MatchingSection{ |
| 4107 | .seg = self.text_segment_cmd_index.?, | 4125 | .seg = self.text_segment_cmd_index.?, |
| 4108 | .sect = self.stub_helper_section_index.?, | 4126 | .sect = self.stub_helper_section_index.?, |
| 4109 | }); | 4127 | }; |
| | 4128 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 4129 | try self.block_free_lists.putNoClobber(self.base.allocator, match, .{}); |
| 4110 | self.load_commands_dirty = true; | 4130 | self.load_commands_dirty = true; |
| 4111 | } | 4131 | } |
| 4112 | | 4132 | |
| ... | @@ -4148,10 +4168,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4148,10 +4168,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4148 | .@"align" = 3, // 2^3 = @sizeOf(u64) | 4168 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 4149 | .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, | 4169 | .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, |
| 4150 | }); | 4170 | }); |
| 4151 | _ = try self.section_ordinals.getOrPut(self.base.allocator, .{ | 4171 | const match = MatchingSection{ |
| 4152 | .seg = self.data_const_segment_cmd_index.?, | 4172 | .seg = self.data_const_segment_cmd_index.?, |
| 4153 | .sect = self.got_section_index.?, | 4173 | .sect = self.got_section_index.?, |
| 4154 | }); | 4174 | }; |
| | 4175 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 4176 | try self.block_free_lists.putNoClobber(self.base.allocator, match, .{}); |
| 4155 | self.load_commands_dirty = true; | 4177 | self.load_commands_dirty = true; |
| 4156 | } | 4178 | } |
| 4157 | | 4179 | |
| ... | @@ -4193,10 +4215,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4193,10 +4215,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4193 | .@"align" = 3, // 2^3 = @sizeOf(u64) | 4215 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 4194 | .flags = macho.S_LAZY_SYMBOL_POINTERS, | 4216 | .flags = macho.S_LAZY_SYMBOL_POINTERS, |
| 4195 | }); | 4217 | }); |
| 4196 | _ = try self.section_ordinals.getOrPut(self.base.allocator, .{ | 4218 | const match = MatchingSection{ |
| 4197 | .seg = self.data_segment_cmd_index.?, | 4219 | .seg = self.data_segment_cmd_index.?, |
| 4198 | .sect = self.la_symbol_ptr_section_index.?, | 4220 | .sect = self.la_symbol_ptr_section_index.?, |
| 4199 | }); | 4221 | }; |
| | 4222 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 4223 | try self.block_free_lists.putNoClobber(self.base.allocator, match, .{}); |
| 4200 | self.load_commands_dirty = true; | 4224 | self.load_commands_dirty = true; |
| 4201 | } | 4225 | } |
| 4202 | | 4226 | |
| ... | @@ -4216,10 +4240,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4216,10 +4240,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4216 | .offset = @intCast(u32, off), | 4240 | .offset = @intCast(u32, off), |
| 4217 | .@"align" = 3, // 2^3 = @sizeOf(u64) | 4241 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 4218 | }); | 4242 | }); |
| 4219 | _ = try self.section_ordinals.getOrPut(self.base.allocator, .{ | 4243 | const match = MatchingSection{ |
| 4220 | .seg = self.data_segment_cmd_index.?, | 4244 | .seg = self.data_segment_cmd_index.?, |
| 4221 | .sect = self.data_section_index.?, | 4245 | .sect = self.data_section_index.?, |
| 4222 | }); | 4246 | }; |
| | 4247 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| | 4248 | try self.block_free_lists.putNoClobber(self.base.allocator, match, .{}); |
| 4223 | self.load_commands_dirty = true; | 4249 | self.load_commands_dirty = true; |
| 4224 | } | 4250 | } |
| 4225 | | 4251 | |
| ... | @@ -4470,6 +4496,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4470,6 +4496,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4470 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 4496 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 4471 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 4497 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4472 | const text_section = &text_segment.sections.items[self.text_section_index.?]; | 4498 | const text_section = &text_segment.sections.items[self.text_section_index.?]; |
| | 4499 | const match = MatchingSection{ |
| | 4500 | .seg = self.text_segment_cmd_index.?, |
| | 4501 | .sect = self.text_section_index.?, |
| | 4502 | }; |
| | 4503 | const text_block_free_list = self.block_free_lists.getPtr(match).?; |
| 4473 | const new_block_ideal_capacity = padToIdeal(new_block_size); | 4504 | const new_block_ideal_capacity = padToIdeal(new_block_size); |
| 4474 | | 4505 | |
| 4475 | // We use these to indicate our intention to update metadata, placing the new block, | 4506 | // We use these to indicate our intention to update metadata, placing the new block, |
| ... | @@ -4484,8 +4515,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4484,8 +4515,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4484 | // The list is unordered. We'll just take the first thing that works. | 4515 | // The list is unordered. We'll just take the first thing that works. |
| 4485 | const vaddr = blk: { | 4516 | const vaddr = blk: { |
| 4486 | var i: usize = 0; | 4517 | var i: usize = 0; |
| 4487 | while (i < self.text_block_free_list.items.len) { | 4518 | while (i < text_block_free_list.items.len) { |
| 4488 | const big_block = self.text_block_free_list.items[i]; | 4519 | const big_block = text_block_free_list.items[i]; |
| 4489 | // We now have a pointer to a live text block that has too much capacity. | 4520 | // We now have a pointer to a live text block that has too much capacity. |
| 4490 | // Is it enough that we could fit this new text block? | 4521 | // Is it enough that we could fit this new text block? |
| 4491 | const sym = self.locals.items[big_block.local_sym_index]; | 4522 | const sym = self.locals.items[big_block.local_sym_index]; |
| ... | @@ -4500,7 +4531,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4500,7 +4531,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4500 | // should be deleted because the block that it points to has grown to take up | 4531 | // should be deleted because the block that it points to has grown to take up |
| 4501 | // more of the extra capacity. | 4532 | // more of the extra capacity. |
| 4502 | if (!big_block.freeListEligible(self.*)) { | 4533 | if (!big_block.freeListEligible(self.*)) { |
| 4503 | const bl = self.text_block_free_list.swapRemove(i); | 4534 | const bl = text_block_free_list.swapRemove(i); |
| 4504 | bl.deinit(self.base.allocator); | 4535 | bl.deinit(self.base.allocator); |
| 4505 | } else { | 4536 | } else { |
| 4506 | i += 1; | 4537 | i += 1; |
| ... | @@ -4519,7 +4550,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4519,7 +4550,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4519 | free_list_removal = i; | 4550 | free_list_removal = i; |
| 4520 | } | 4551 | } |
| 4521 | break :blk new_start_vaddr; | 4552 | break :blk new_start_vaddr; |
| 4522 | } else if (self.last_text_block) |last| { | 4553 | } else if (self.blocks.get(match)) |last| { |
| 4523 | const last_symbol = self.locals.items[last.local_sym_index]; | 4554 | const last_symbol = self.locals.items[last.local_sym_index]; |
| 4524 | // TODO We should pad out the excess capacity with NOPs. For executables, | 4555 | // TODO We should pad out the excess capacity with NOPs. For executables, |
| 4525 | // no padding seems to be OK, but it will probably not be for objects. | 4556 | // no padding seems to be OK, but it will probably not be for objects. |
| ... | @@ -4538,7 +4569,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4538,7 +4569,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4538 | const needed_size = (vaddr + new_block_size) - text_section.addr; | 4569 | const needed_size = (vaddr + new_block_size) - text_section.addr; |
| 4539 | assert(needed_size <= text_segment.inner.filesize); // TODO must move the entire text section. | 4570 | assert(needed_size <= text_segment.inner.filesize); // TODO must move the entire text section. |
| 4540 | | 4571 | |
| 4541 | self.last_text_block = text_block; | 4572 | _ = try self.blocks.getOrPutValue(self.base.allocator, match, text_block); |
| 4542 | text_section.size = needed_size; | 4573 | text_section.size = needed_size; |
| 4543 | self.load_commands_dirty = true; // TODO Make more granular. | 4574 | self.load_commands_dirty = true; // TODO Make more granular. |
| 4544 | | 4575 | |
| ... | @@ -4567,7 +4598,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, | ... | @@ -4567,7 +4598,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 4567 | text_block.next = null; | 4598 | text_block.next = null; |
| 4568 | } | 4599 | } |
| 4569 | if (free_list_removal) |i| { | 4600 | if (free_list_removal) |i| { |
| 4570 | _ = self.text_block_free_list.swapRemove(i); | 4601 | _ = text_block_free_list.swapRemove(i); |
| 4571 | } | 4602 | } |
| 4572 | | 4603 | |
| 4573 | return vaddr; | 4604 | return vaddr; |