| ... | @@ -163,6 +163,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -163,6 +163,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 163 | | 163 | |
| 164 | segment_table_dirty: bool = false, | 164 | segment_table_dirty: bool = false, |
| 165 | got_table_count_dirty: bool = false, | 165 | got_table_count_dirty: bool = false, |
| | 166 | got_table_contents_dirty: bool = false, |
| 166 | | 167 | |
| 167 | /// A helper var to indicate if we are at the start of the incremental updates, or | 168 | /// A helper var to indicate if we are at the start of the incremental updates, or |
| 168 | /// already somewhere further along the update-and-run chain. | 169 | /// already somewhere further along the update-and-run chain. |
| ... | @@ -758,6 +759,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -758,6 +759,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 758 | try self.writeAtom(atom_index, code.items); | 759 | try self.writeAtom(atom_index, code.items); |
| 759 | } | 760 | } |
| 760 | | 761 | |
| | 762 | if (self.got_table_contents_dirty) { |
| | 763 | for (self.got_table.entries.items, 0..) |entry, i| { |
| | 764 | if (!self.got_table.lookup.contains(entry)) continue; |
| | 765 | try self.writeOffsetTableEntry(i); |
| | 766 | } |
| | 767 | } |
| | 768 | |
| 761 | if (build_options.enable_logging) { | 769 | if (build_options.enable_logging) { |
| 762 | self.logSymtab(); | 770 | self.logSymtab(); |
| 763 | self.logSections(); | 771 | self.logSections(); |
| ... | @@ -1242,12 +1250,8 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void { | ... | @@ -1242,12 +1250,8 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void { |
| 1242 | } | 1250 | } |
| 1243 | | 1251 | |
| 1244 | if (is_hot_update_compatible) { | 1252 | if (is_hot_update_compatible) { |
| 1245 | if (self.base.child_pid) |pid| blk: { | 1253 | if (self.hot_state.mach_task) |task| { |
| 1246 | const task = self.hot_state.mach_task orelse { | 1254 | self.writeToMemory(task, section.segment_index, sym.n_value, code) catch |err| { |
| 1247 | log.warn("cannot hot swap: no Mach task acquired for child process with pid {d}", .{pid}); | | |
| 1248 | break :blk; | | |
| 1249 | }; | | |
| 1250 | self.updateAtomInMemory(task, section.segment_index, sym.n_value, code) catch |err| { | | |
| 1251 | log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)}); | 1255 | log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)}); |
| 1252 | }; | 1256 | }; |
| 1253 | } | 1257 | } |
| ... | @@ -1262,7 +1266,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void { | ... | @@ -1262,7 +1266,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void { |
| 1262 | } | 1266 | } |
| 1263 | } | 1267 | } |
| 1264 | | 1268 | |
| 1265 | fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void { | 1269 | fn writeToMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void { |
| 1266 | const segment = self.segments.items[segment_index]; | 1270 | const segment = self.segments.items[segment_index]; |
| 1267 | const cpu_arch = self.base.options.target.cpu.arch; | 1271 | const cpu_arch = self.base.options.target.cpu.arch; |
| 1268 | const nwritten = if (!segment.isWriteable()) | 1272 | const nwritten = if (!segment.isWriteable()) |
| ... | @@ -1272,7 +1276,7 @@ fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: | ... | @@ -1272,7 +1276,7 @@ fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: |
| 1272 | if (nwritten != code.len) return error.InputOutput; | 1276 | if (nwritten != code.len) return error.InputOutput; |
| 1273 | } | 1277 | } |
| 1274 | | 1278 | |
| 1275 | fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !void { | 1279 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1276 | const sect_id = self.got_section_index.?; | 1280 | const sect_id = self.got_section_index.?; |
| 1277 | | 1281 | |
| 1278 | if (self.got_table_count_dirty) { | 1282 | if (self.got_table_count_dirty) { |
| ... | @@ -1282,18 +1286,27 @@ fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !vo | ... | @@ -1282,18 +1286,27 @@ fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !vo |
| 1282 | } | 1286 | } |
| 1283 | | 1287 | |
| 1284 | const header = &self.sections.items(.header)[sect_id]; | 1288 | const header = &self.sections.items(.header)[sect_id]; |
| | 1289 | const segment_index = self.sections.items(.segment_index)[sect_id]; |
| | 1290 | const segment = self.getSegment(sect_id); |
| 1285 | const entry = self.got_table.entries.items[index]; | 1291 | const entry = self.got_table.entries.items[index]; |
| 1286 | const entry_value = self.getSymbol(entry).n_value; | 1292 | const entry_value = self.getSymbol(entry).n_value; |
| 1287 | const entry_offset = index * @sizeOf(u64); | 1293 | const entry_offset = index * @sizeOf(u64); |
| 1288 | const file_offset = header.offset + entry_offset; | 1294 | const file_offset = header.offset + entry_offset; |
| 1289 | const vmaddr = header.addr + entry_offset; | 1295 | const vmaddr = segment.vmaddr + entry_offset; |
| 1290 | _ = vmaddr; | 1296 | log.warn("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value }); |
| 1291 | | 1297 | |
| 1292 | var buf: [8]u8 = undefined; | 1298 | var buf: [8]u8 = undefined; |
| 1293 | mem.writeIntLittle(u64, &buf, entry_value); | 1299 | mem.writeIntLittle(u64, &buf, entry_value); |
| 1294 | try self.base.file.?.pwriteAll(&buf, file_offset); | 1300 | try self.base.file.?.pwriteAll(&buf, file_offset); |
| 1295 | | 1301 | |
| 1296 | // TODO write in memory | 1302 | // TODO write in memory |
| | 1303 | if (is_hot_update_compatible) { |
| | 1304 | if (self.hot_state.mach_task) |task| { |
| | 1305 | self.writeToMemory(task, segment_index, vmaddr, &buf) catch |err| { |
| | 1306 | log.warn("cannot hot swap: writing to memory failed: {s}", .{@errorName(err)}); |
| | 1307 | }; |
| | 1308 | } |
| | 1309 | } |
| 1297 | } | 1310 | } |
| 1298 | | 1311 | |
| 1299 | fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { | 1312 | fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { |
| ... | @@ -1322,6 +1335,15 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { | ... | @@ -1322,6 +1335,15 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { |
| 1322 | reloc.dirty = true; | 1335 | reloc.dirty = true; |
| 1323 | } | 1336 | } |
| 1324 | } | 1337 | } |
| | 1338 | |
| | 1339 | // Dirty synthetic table sections if necessary |
| | 1340 | for (&[_]u8{self.got_section_index.?}, &[_]*bool{&self.got_table_contents_dirty}) |sect_id, dirty| { |
| | 1341 | if (dirty.*) continue; |
| | 1342 | const segment_index = self.sections.items(.segment_index)[sect_id]; |
| | 1343 | const segment = self.segments.items[segment_index]; |
| | 1344 | if (segment.vmaddr < addr) continue; |
| | 1345 | dirty.* = true; |
| | 1346 | } |
| 1325 | } | 1347 | } |
| 1326 | | 1348 | |
| 1327 | pub fn allocateSpecialSymbols(self: *MachO) !void { | 1349 | pub fn allocateSpecialSymbols(self: *MachO) !void { |
| ... | @@ -2097,6 +2119,7 @@ fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { | ... | @@ -2097,6 +2119,7 @@ fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 2097 | const got_index = try self.got_table.allocateEntry(self.base.allocator, target); | 2119 | const got_index = try self.got_table.allocateEntry(self.base.allocator, target); |
| 2098 | try self.writeOffsetTableEntry(got_index); | 2120 | try self.writeOffsetTableEntry(got_index); |
| 2099 | self.markRelocsDirtyByTarget(target); | 2121 | self.markRelocsDirtyByTarget(target); |
| | 2122 | self.got_table_count_dirty = true; |
| 2100 | } | 2123 | } |
| 2101 | | 2124 | |
| 2102 | fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { | 2125 | fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { |
| ... | @@ -3010,7 +3033,7 @@ fn growSection(self: *MachO, sect_id: u8, needed_size: u64) !void { | ... | @@ -3010,7 +3033,7 @@ fn growSection(self: *MachO, sect_id: u8, needed_size: u64) !void { |
| 3010 | const last_atom = self.getAtom(last_atom_index); | 3033 | const last_atom = self.getAtom(last_atom_index); |
| 3011 | const sym = last_atom.getSymbol(self); | 3034 | const sym = last_atom.getSymbol(self); |
| 3012 | break :blk (sym.n_value + last_atom.size) - segment.vmaddr; | 3035 | break :blk (sym.n_value + last_atom.size) - segment.vmaddr; |
| 3013 | } else 0; | 3036 | } else header.size; |
| 3014 | | 3037 | |
| 3015 | log.debug("moving {s},{s} from 0x{x} to 0x{x}", .{ | 3038 | log.debug("moving {s},{s} from 0x{x} to 0x{x}", .{ |
| 3016 | header.segName(), | 3039 | header.segName(), |