authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-19 11:27:34+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-21 22:44:27+02:00
log91bb9302e57c62a1340291b8b207b1638b981bc6
tree8e50187918c9255a02a379ea4b9a6465d5a92c21
parentc6e916d7fe4234c821eeeff19a73b334129c00de

macho: correctly dirty the GOT table after memory realloc


2 files changed, 35 insertions(+), 12 deletions(-)

src/link/MachO.zig+34-11
...@@ -163,6 +163,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},...@@ -163,6 +163,7 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},
163163
164segment_table_dirty: bool = false,164segment_table_dirty: bool = false,
165got_table_count_dirty: bool = false,165got_table_count_dirty: bool = false,
166got_table_contents_dirty: bool = false,
166167
167/// A helper var to indicate if we are at the start of the incremental updates, or168/// 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 }
760761
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 }
12431251
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}
12641268
1265fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: u8, addr: u64, code: []const u8) !void {1269fn 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}
12741278
1275fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !void {1279fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1276 const sect_id = self.got_section_index.?;1280 const sect_id = self.got_section_index.?;
12771281
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 }
12831287
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 });
12911297
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);
12951301
1296 // TODO write in memory1302 // 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}
12981311
1299fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {1312fn 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}
13261348
1327pub fn allocateSpecialSymbols(self: *MachO) !void {1349pub 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}
21012124
2102fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {2125fn 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;
30143037
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(),
src/link/table_section.zig+1-1
...@@ -47,7 +47,7 @@ pub fn TableSection(comptime Entry: type) type {...@@ -47,7 +47,7 @@ pub fn TableSection(comptime Entry: type) type {
47 ) !void {47 ) !void {
48 _ = options;48 _ = options;
49 comptime assert(unused_format_string.len == 0);49 comptime assert(unused_format_string.len == 0);
50 try writer.writeAll("SectionTable:\n");50 try writer.writeAll("TableSection:\n");
51 for (self.entries.items, 0..) |entry, i| {51 for (self.entries.items, 0..) |entry, i| {
52 try writer.print(" {d} => {}\n", .{ i, entry });52 try writer.print(" {d} => {}\n", .{ i, entry });
53 }53 }