| ... | @@ -116,7 +116,9 @@ global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | ... | @@ -116,7 +116,9 @@ global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 116 | /// Table of all undefined symbols | 116 | /// Table of all undefined symbols |
| 117 | undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 117 | undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 118 | | 118 | |
| | 119 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 119 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 120 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| | 121 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 120 | | 122 | |
| 121 | dyld_stub_binder_index: ?u16 = null, | 123 | dyld_stub_binder_index: ?u16 = null, |
| 122 | | 124 | |
| ... | @@ -153,6 +155,12 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System"; | ... | @@ -153,6 +155,12 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System"; |
| 153 | /// TODO we should search for libSystem and fail if it doesn't exist, instead of hardcoding it | 155 | /// TODO we should search for libSystem and fail if it doesn't exist, instead of hardcoding it |
| 154 | const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib"; | 156 | const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib"; |
| 155 | | 157 | |
| | 158 | /// In order for a slice of bytes to be considered eligible to keep metadata pointing at |
| | 159 | /// it as a possible place to put new symbols, it must have enough room for this many bytes |
| | 160 | /// (plus extra for reserved capacity). |
| | 161 | const minimum_text_block_size = 64; |
| | 162 | const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den; |
| | 163 | |
| 156 | pub const TextBlock = struct { | 164 | pub const TextBlock = struct { |
| 157 | /// Each decl always gets a local symbol with the fully qualified name. | 165 | /// Each decl always gets a local symbol with the fully qualified name. |
| 158 | /// The vaddr and size are found here directly. | 166 | /// The vaddr and size are found here directly. |
| ... | @@ -179,6 +187,33 @@ pub const TextBlock = struct { | ... | @@ -179,6 +187,33 @@ pub const TextBlock = struct { |
| 179 | .prev = null, | 187 | .prev = null, |
| 180 | .next = null, | 188 | .next = null, |
| 181 | }; | 189 | }; |
| | 190 | |
| | 191 | /// Returns how much room there is to grow in virtual address space. |
| | 192 | /// File offset relocation happens transparently, so it is not included in |
| | 193 | /// this calculation. |
| | 194 | fn capacity(self: TextBlock, macho_file: MachO) u64 { |
| | 195 | const self_sym = macho_file.local_symbols.items[self.local_sym_index]; |
| | 196 | if (self.next) |next| { |
| | 197 | const next_sym = macho_file.local_symbols.items[next.local_sym_index]; |
| | 198 | return next_sym.n_value - self_sym.n_value; |
| | 199 | } else { |
| | 200 | // We are the last block. |
| | 201 | // The capacity is limited only by virtual address space. |
| | 202 | return std.math.maxInt(u64) - self_sym.n_value; |
| | 203 | } |
| | 204 | } |
| | 205 | |
| | 206 | fn freeListEligible(self: TextBlock, macho_file: MachO) bool { |
| | 207 | // No need to keep a free list node for the last block. |
| | 208 | const next = self.next orelse return false; |
| | 209 | const self_sym = macho_file.local_symbols.items[self.local_sym_index]; |
| | 210 | const next_sym = macho_file.local_symbols.items[next.local_sym_index]; |
| | 211 | const cap = next_sym.n_value - self_sym.n_value; |
| | 212 | const ideal_cap = self.size * alloc_num / alloc_den; |
| | 213 | if (cap <= ideal_cap) return false; |
| | 214 | const surplus = cap - ideal_cap; |
| | 215 | return surplus >= min_text_capacity; |
| | 216 | } |
| 182 | }; | 217 | }; |
| 183 | | 218 | |
| 184 | pub const Export = struct { | 219 | pub const Export = struct { |
| ... | @@ -721,11 +756,13 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { | ... | @@ -721,11 +756,13 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { |
| 721 | | 756 | |
| 722 | pub fn deinit(self: *MachO) void { | 757 | pub fn deinit(self: *MachO) void { |
| 723 | self.offset_table.deinit(self.base.allocator); | 758 | self.offset_table.deinit(self.base.allocator); |
| | 759 | self.offset_table_free_list.deinit(self.base.allocator); |
| 724 | self.string_table.deinit(self.base.allocator); | 760 | self.string_table.deinit(self.base.allocator); |
| 725 | self.undef_symbols.deinit(self.base.allocator); | 761 | self.undef_symbols.deinit(self.base.allocator); |
| 726 | self.global_symbols.deinit(self.base.allocator); | 762 | self.global_symbols.deinit(self.base.allocator); |
| 727 | self.global_symbol_free_list.deinit(self.base.allocator); | 763 | self.global_symbol_free_list.deinit(self.base.allocator); |
| 728 | self.local_symbols.deinit(self.base.allocator); | 764 | self.local_symbols.deinit(self.base.allocator); |
| | 765 | self.local_symbol_free_list.deinit(self.base.allocator); |
| 729 | self.sections.deinit(self.base.allocator); | 766 | self.sections.deinit(self.base.allocator); |
| 730 | self.load_commands.deinit(self.base.allocator); | 767 | self.load_commands.deinit(self.base.allocator); |
| 731 | } | 768 | } |