| ... | ... | @@ -163,6 +163,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 163 | 163 | |
| 164 | 164 | segment_table_dirty: bool = false, |
| 165 | 165 | got_table_count_dirty: bool = false, |
| 166 | got_table_contents_dirty: bool = false, |
| 166 | 167 | |
| 167 | 168 | /// A helper var to indicate if we are at the start of the incremental updates, or |
| 168 | 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 | 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 | 769 | if (build_options.enable_logging) { |
| 762 | 770 | self.logSymtab(); |
| 763 | 771 | self.logSections(); |
| ... | ... | @@ -1242,12 +1250,8 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void { |
| 1242 | 1250 | } |
| 1243 | 1251 | |
| 1244 | 1252 | if (is_hot_update_compatible) { |
| 1245 | | if (self.base.child_pid) |pid| blk: { |
| 1246 | | const task = self.hot_state.mach_task orelse { |
| 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| { |
| 1253 | if (self.hot_state.mach_task) |task| { |
| 1254 | self.writeToMemory(task, section.segment_index, sym.n_value, code) catch |err| { |
| 1251 | 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 | 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 | 1270 | const segment = self.segments.items[segment_index]; |
| 1267 | 1271 | const cpu_arch = self.base.options.target.cpu.arch; |
| 1268 | 1272 | const nwritten = if (!segment.isWriteable()) |
| ... | ... | @@ -1272,7 +1276,7 @@ fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: |
| 1272 | 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 | 1280 | const sect_id = self.got_section_index.?; |
| 1277 | 1281 | |
| 1278 | 1282 | if (self.got_table_count_dirty) { |
| ... | ... | @@ -1282,18 +1286,27 @@ fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !vo |
| 1282 | 1286 | } |
| 1283 | 1287 | |
| 1284 | 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 | 1291 | const entry = self.got_table.entries.items[index]; |
| 1286 | 1292 | const entry_value = self.getSymbol(entry).n_value; |
| 1287 | 1293 | const entry_offset = index * @sizeOf(u64); |
| 1288 | 1294 | const file_offset = header.offset + entry_offset; |
| 1289 | | const vmaddr = header.addr + entry_offset; |
| 1290 | | _ = vmaddr; |
| 1295 | const vmaddr = segment.vmaddr + entry_offset; |
| 1296 | log.warn("writing GOT entry {d}: @{x} => {x}", .{ index, vmaddr, entry_value }); |
| 1291 | 1297 | |
| 1292 | 1298 | var buf: [8]u8 = undefined; |
| 1293 | 1299 | mem.writeIntLittle(u64, &buf, entry_value); |
| 1294 | 1300 | try self.base.file.?.pwriteAll(&buf, file_offset); |
| 1295 | 1301 | |
| 1296 | 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 | 1312 | fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { |
| ... | ... | @@ -1322,6 +1335,15 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { |
| 1322 | 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 | 1349 | pub fn allocateSpecialSymbols(self: *MachO) !void { |
| ... | ... | @@ -2097,6 +2119,7 @@ fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 2097 | 2119 | const got_index = try self.got_table.allocateEntry(self.base.allocator, target); |
| 2098 | 2120 | try self.writeOffsetTableEntry(got_index); |
| 2099 | 2121 | self.markRelocsDirtyByTarget(target); |
| 2122 | self.got_table_count_dirty = true; |
| 2100 | 2123 | } |
| 2101 | 2124 | |
| 2102 | 2125 | fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { |
| ... | ... | @@ -3010,7 +3033,7 @@ fn growSection(self: *MachO, sect_id: u8, needed_size: u64) !void { |
| 3010 | 3033 | const last_atom = self.getAtom(last_atom_index); |
| 3011 | 3034 | const sym = last_atom.getSymbol(self); |
| 3012 | 3035 | break :blk (sym.n_value + last_atom.size) - segment.vmaddr; |
| 3013 | | } else 0; |
| 3036 | } else header.size; |
| 3014 | 3037 | |
| 3015 | 3038 | log.debug("moving {s},{s} from 0x{x} to 0x{x}", .{ |
| 3016 | 3039 | header.segName(), |