| ... | @@ -114,6 +114,8 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -114,6 +114,8 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 114 | offset_table_count_dirty: bool = false, | 114 | offset_table_count_dirty: bool = false, |
| 115 | header_dirty: bool = false, | 115 | header_dirty: bool = false, |
| 116 | load_commands_dirty: bool = false, | 116 | load_commands_dirty: bool = false, |
| | 117 | binding_info_dirty: bool = false, |
| | 118 | lazy_binding_info_dirty: bool = false, |
| 117 | export_info_dirty: bool = false, | 119 | export_info_dirty: bool = false, |
| 118 | string_table_dirty: bool = false, | 120 | string_table_dirty: bool = false, |
| 119 | | 121 | |
| ... | @@ -322,6 +324,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -322,6 +324,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 322 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; | 324 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| 323 | self.load_commands_dirty = true; | 325 | self.load_commands_dirty = true; |
| 324 | } | 326 | } |
| | 327 | try self.writeBindingInfoTable(); |
| | 328 | try self.writeLazyBindingInfoTable(); |
| 325 | try self.writeExportTrie(); | 329 | try self.writeExportTrie(); |
| 326 | try self.writeAllGlobalAndUndefSymbols(); | 330 | try self.writeAllGlobalAndUndefSymbols(); |
| 327 | try self.writeStringTable(); | 331 | try self.writeStringTable(); |
| ... | @@ -354,6 +358,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -354,6 +358,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 354 | assert(!self.offset_table_count_dirty); | 358 | assert(!self.offset_table_count_dirty); |
| 355 | assert(!self.header_dirty); | 359 | assert(!self.header_dirty); |
| 356 | assert(!self.load_commands_dirty); | 360 | assert(!self.load_commands_dirty); |
| | 361 | assert(!self.binding_info_dirty); |
| | 362 | assert(!self.lazy_binding_info_dirty); |
| 357 | assert(!self.export_info_dirty); | 363 | assert(!self.export_info_dirty); |
| 358 | assert(!self.string_table_dirty); | 364 | assert(!self.string_table_dirty); |
| 359 | | 365 | |
| ... | @@ -831,7 +837,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -831,7 +837,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 831 | symbol.dylib_ordinal = next_ordinal; | 837 | symbol.dylib_ordinal = next_ordinal; |
| 832 | } | 838 | } |
| 833 | | 839 | |
| 834 | // Write update dyld info | 840 | // Write updated dyld info. |
| 835 | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 841 | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 836 | { | 842 | { |
| 837 | const size = try self.binding_info_table.calcSize(); | 843 | const size = try self.binding_info_table.calcSize(); |
| ... | @@ -861,6 +867,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -861,6 +867,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 861 | // Write updated load commands and the header | 867 | // Write updated load commands and the header |
| 862 | try self.writeLoadCommands(); | 868 | try self.writeLoadCommands(); |
| 863 | try self.writeHeader(); | 869 | try self.writeHeader(); |
| | 870 | |
| | 871 | assert(!self.header_dirty); |
| | 872 | assert(!self.load_commands_dirty); |
| 864 | } | 873 | } |
| 865 | if (self.code_signature_cmd_index == null) outer: { | 874 | if (self.code_signature_cmd_index == null) outer: { |
| 866 | if (target.cpu.arch != .aarch64) break :outer; // This is currently needed only for aarch64 targets. | 875 | if (target.cpu.arch != .aarch64) break :outer; // This is currently needed only for aarch64 targets. |
| ... | @@ -896,6 +905,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -896,6 +905,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 896 | try self.writeHeader(); | 905 | try self.writeHeader(); |
| 897 | // Generate adhoc code signature | 906 | // Generate adhoc code signature |
| 898 | try self.writeCodeSignature(); | 907 | try self.writeCodeSignature(); |
| | 908 | |
| | 909 | assert(!self.header_dirty); |
| | 910 | assert(!self.load_commands_dirty); |
| 899 | } | 911 | } |
| 900 | } | 912 | } |
| 901 | } | 913 | } |
| ... | @@ -2136,7 +2148,7 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -2136,7 +2148,7 @@ fn writeExportTrie(self: *MachO) !void { |
| 2136 | dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); | 2148 | dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| 2137 | } | 2149 | } |
| 2138 | dyld_info.export_size = @intCast(u32, needed_size); | 2150 | dyld_info.export_size = @intCast(u32, needed_size); |
| 2139 | log.debug("writing export trie from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); | 2151 | log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size }); |
| 2140 | | 2152 | |
| 2141 | try self.base.file.?.pwriteAll(buffer, dyld_info.export_off); | 2153 | try self.base.file.?.pwriteAll(buffer, dyld_info.export_off); |
| 2142 | self.load_commands_dirty = true; | 2154 | self.load_commands_dirty = true; |
| ... | @@ -2144,65 +2156,62 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -2144,65 +2156,62 @@ fn writeExportTrie(self: *MachO) !void { |
| 2144 | } | 2156 | } |
| 2145 | | 2157 | |
| 2146 | fn writeBindingInfoTable(self: *MachO) !void { | 2158 | fn writeBindingInfoTable(self: *MachO) !void { |
| 2147 | const size = self.binding_info_table.calcSize(); | 2159 | if (!self.binding_info_dirty) return; |
| | 2160 | |
| | 2161 | const tracy = trace(@src()); |
| | 2162 | defer tracy.end(); |
| | 2163 | |
| | 2164 | const size = try self.binding_info_table.calcSize(); |
| 2148 | var buffer = try self.base.allocator.alloc(u8, size); | 2165 | var buffer = try self.base.allocator.alloc(u8, size); |
| 2149 | defer self.base.allocator.free(buffer); | 2166 | defer self.base.allocator.free(buffer); |
| 2150 | | 2167 | |
| 2151 | var stream = std.io.fixedBufferStream(buffer); | 2168 | var stream = std.io.fixedBufferStream(buffer); |
| 2152 | try self.binding_info_table.write(stream.writer()); | 2169 | try self.binding_info_table.write(stream.writer()); |
| 2153 | | 2170 | |
| | 2171 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2154 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 2172 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2155 | const bind_size = @intCast(u32, mem.alignForward(buffer.len, @sizeOf(u64))); | 2173 | const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.bind_off); |
| 2156 | dyld_info.bind_off = self.linkedit_segment_next_offset.?; | 2174 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 2157 | dyld_info.bind_size = bind_size; | | |
| 2158 | | | |
| 2159 | log.debug("writing binding info table from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + bind_size }); | | |
| 2160 | | 2175 | |
| 2161 | if (bind_size > buffer.len) { | 2176 | if (needed_size > allocated_size) { |
| 2162 | // Pad out to align(8). | 2177 | dyld_info.bind_off = 0; |
| 2163 | try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.bind_off + bind_size); | 2178 | dyld_info.bind_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| 2164 | } | 2179 | } |
| 2165 | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); | | |
| 2166 | | 2180 | |
| 2167 | self.linkedit_segment_next_offset = dyld_info.bind_off + dyld_info.bind_size; | 2181 | dyld_info.bind_size = @intCast(u32, needed_size); |
| 2168 | // Advance size of __LINKEDIT segment | 2182 | log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size }); |
| 2169 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2183 | |
| 2170 | linkedit.inner.filesize += dyld_info.bind_size; | 2184 | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); |
| 2171 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | 2185 | self.load_commands_dirty = true; |
| 2172 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | 2186 | self.binding_info_dirty = false; |
| 2173 | } | | |
| 2174 | self.cmd_table_dirty = true; | | |
| 2175 | } | 2187 | } |
| 2176 | | 2188 | |
| 2177 | fn writeLazyBindingInfoTable(self: *MachO) !void { | 2189 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2178 | const size = self.lazy_binding_info_table.calcSize(); | 2190 | if (!self.lazy_binding_info_dirty) return; |
| | 2191 | |
| | 2192 | const size = try self.lazy_binding_info_table.calcSize(); |
| 2179 | var buffer = try self.base.allocator.alloc(u8, size); | 2193 | var buffer = try self.base.allocator.alloc(u8, size); |
| 2180 | defer self.base.allocator.free(buffer); | 2194 | defer self.base.allocator.free(buffer); |
| 2181 | | 2195 | |
| 2182 | var stream = std.io.fixedBufferStream(buffer); | 2196 | var stream = std.io.fixedBufferStream(buffer); |
| 2183 | try self.lazy_binding_info_table.write(stream.writer()); | 2197 | try self.lazy_binding_info_table.write(stream.writer()); |
| 2184 | | 2198 | |
| | 2199 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2185 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 2200 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2186 | const bind_size = @intCast(u32, mem.alignForward(buffer.len, @sizeOf(u64))); | 2201 | const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.lazy_bind_off); |
| 2187 | dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?; | 2202 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 2188 | dyld_info.lazy_bind_size = bind_size; | | |
| 2189 | | | |
| 2190 | log.debug("writing lazy binding info table from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + bind_size }); | | |
| 2191 | | 2203 | |
| 2192 | if (bind_size > buffer.len) { | 2204 | if (needed_size > allocated_size) { |
| 2193 | // Pad out to align(8). | 2205 | dyld_info.lazy_bind_off = 0; |
| 2194 | try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.lazy_bind_off + bind_size); | 2206 | dyld_info.lazy_bind_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| 2195 | } | 2207 | } |
| 2196 | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); | | |
| 2197 | | 2208 | |
| 2198 | self.linkedit_segment_next_offset = dyld_info.lazy_bind_off + dyld_info.lazy_bind_size; | 2209 | dyld_info.lazy_bind_size = @intCast(u32, needed_size); |
| 2199 | // Advance size of __LINKEDIT segment | 2210 | log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size }); |
| 2200 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2211 | |
| 2201 | linkedit.inner.filesize += dyld_info.lazy_bind_size; | 2212 | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 2202 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | 2213 | self.load_commands_dirty = true; |
| 2203 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | 2214 | self.lazy_binding_info_dirty = false; |
| 2204 | } | | |
| 2205 | self.cmd_table_dirty = true; | | |
| 2206 | } | 2215 | } |
| 2207 | | 2216 | |
| 2208 | fn writeStringTable(self: *MachO) !void { | 2217 | fn writeStringTable(self: *MachO) !void { |