| ... | ... | @@ -41,6 +41,7 @@ const Md5 = std.crypto.hash.Md5; |
| 41 | 41 | const Module = @import("../Module.zig"); |
| 42 | 42 | const Relocation = @import("MachO/Relocation.zig"); |
| 43 | 43 | const StringTable = @import("strtab.zig").StringTable; |
| 44 | const TableSection = @import("table_section.zig").TableSection; |
| 44 | 45 | const Trie = @import("MachO/Trie.zig"); |
| 45 | 46 | const Type = @import("../type.zig").Type; |
| 46 | 47 | const TypedValue = @import("../TypedValue.zig"); |
| ... | ... | @@ -154,13 +155,14 @@ stub_helper_preamble_atom_index: ?Atom.Index = null, |
| 154 | 155 | |
| 155 | 156 | strtab: StringTable(.strtab) = .{}, |
| 156 | 157 | |
| 157 | | got_table: SectionTable = .{}, |
| 158 | got_table: TableSection(SymbolWithLoc) = .{}, |
| 158 | 159 | stubs_table: SectionTable = .{}, |
| 159 | 160 | tlv_table: SectionTable = .{}, |
| 160 | 161 | |
| 161 | 162 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 162 | 163 | |
| 163 | 164 | segment_table_dirty: bool = false, |
| 165 | got_table_count_dirty: bool = false, |
| 164 | 166 | |
| 165 | 167 | /// A helper var to indicate if we are at the start of the incremental updates, or |
| 166 | 168 | /// already somewhere further along the update-and-run chain. |
| ... | ... | @@ -1270,6 +1272,30 @@ fn updateAtomInMemory(self: *MachO, task: std.os.darwin.MachTask, segment_index: |
| 1270 | 1272 | if (nwritten != code.len) return error.InputOutput; |
| 1271 | 1273 | } |
| 1272 | 1274 | |
| 1275 | fn writeOffsetTableEntry(self: *MachO, index: @TypeOf(self.got_table).Index) !void { |
| 1276 | const sect_id = self.got_section_index.?; |
| 1277 | |
| 1278 | if (self.got_table_count_dirty) { |
| 1279 | const needed_size = self.got_table.entries.items.len * @sizeOf(u64); |
| 1280 | try self.growSection(sect_id, needed_size); |
| 1281 | self.got_table_count_dirty = false; |
| 1282 | } |
| 1283 | |
| 1284 | const header = &self.sections.items(.header)[sect_id]; |
| 1285 | const entry = self.got_table.entries.items[index]; |
| 1286 | const entry_value = self.getSymbol(entry).n_value; |
| 1287 | const entry_offset = index * @sizeOf(u64); |
| 1288 | const file_offset = header.offset + entry_offset; |
| 1289 | const vmaddr = header.addr + entry_offset; |
| 1290 | _ = vmaddr; |
| 1291 | |
| 1292 | var buf: [8]u8 = undefined; |
| 1293 | mem.writeIntLittle(u64, &buf, entry_value); |
| 1294 | try self.base.file.?.pwriteAll(&buf, file_offset); |
| 1295 | |
| 1296 | // TODO write in memory |
| 1297 | } |
| 1298 | |
| 1273 | 1299 | fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { |
| 1274 | 1300 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 1275 | 1301 | try self.writeAtom(atom_index, &buffer); |
| ... | ... | @@ -1290,10 +1316,9 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { |
| 1290 | 1316 | log.debug("marking relocs dirty by address: {x}", .{addr}); |
| 1291 | 1317 | for (self.relocs.values()) |*relocs| { |
| 1292 | 1318 | for (relocs.items) |*reloc| { |
| 1293 | | const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue; |
| 1294 | | const target_atom = self.getAtom(target_atom_index); |
| 1295 | | const target_sym = target_atom.getSymbol(self); |
| 1296 | | if (target_sym.n_value < addr) continue; |
| 1319 | const target_addr = reloc.getTargetBaseAddress(self) orelse continue; |
| 1320 | if (target_addr == 0) continue; |
| 1321 | if (target_addr < addr) continue; |
| 1297 | 1322 | reloc.dirty = true; |
| 1298 | 1323 | } |
| 1299 | 1324 | } |
| ... | ... | @@ -1335,40 +1360,6 @@ pub fn createAtom(self: *MachO) !Atom.Index { |
| 1335 | 1360 | return atom_index; |
| 1336 | 1361 | } |
| 1337 | 1362 | |
| 1338 | | pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { |
| 1339 | | const atom_index = try self.createAtom(); |
| 1340 | | self.getAtomPtr(atom_index).size = @sizeOf(u64); |
| 1341 | | |
| 1342 | | const sym = self.getAtom(atom_index).getSymbolPtr(self); |
| 1343 | | sym.n_type = macho.N_SECT; |
| 1344 | | sym.n_sect = self.got_section_index.? + 1; |
| 1345 | | sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64)); |
| 1346 | | |
| 1347 | | log.debug("allocated GOT atom at 0x{x}", .{sym.n_value}); |
| 1348 | | |
| 1349 | | try Atom.addRelocation(self, atom_index, .{ |
| 1350 | | .type = .unsigned, |
| 1351 | | .target = target, |
| 1352 | | .offset = 0, |
| 1353 | | .addend = 0, |
| 1354 | | .pcrel = false, |
| 1355 | | .length = 3, |
| 1356 | | }); |
| 1357 | | |
| 1358 | | const target_sym = self.getSymbol(target); |
| 1359 | | if (target_sym.undf()) { |
| 1360 | | try Atom.addBinding(self, atom_index, .{ |
| 1361 | | .target = self.getGlobal(self.getSymbolName(target)).?, |
| 1362 | | .offset = 0, |
| 1363 | | }); |
| 1364 | | } else { |
| 1365 | | try Atom.addRebase(self, atom_index, 0); |
| 1366 | | } |
| 1367 | | try self.writePtrWidthAtom(atom_index); |
| 1368 | | |
| 1369 | | return atom_index; |
| 1370 | | } |
| 1371 | | |
| 1372 | 1363 | fn createDyldPrivateAtom(self: *MachO) !void { |
| 1373 | 1364 | if (self.dyld_private_atom_index != null) return; |
| 1374 | 1365 | |
| ... | ... | @@ -2104,9 +2095,7 @@ fn allocateGlobal(self: *MachO) !u32 { |
| 2104 | 2095 | fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 2105 | 2096 | if (self.got_table.lookup.contains(target)) return; |
| 2106 | 2097 | const got_index = try self.got_table.allocateEntry(self.base.allocator, target); |
| 2107 | | const got_atom_index = try self.createGotAtom(target); |
| 2108 | | const got_atom = self.getAtom(got_atom_index); |
| 2109 | | self.got_table.entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; |
| 2098 | try self.writeOffsetTableEntry(got_index); |
| 2110 | 2099 | self.markRelocsDirtyByTarget(target); |
| 2111 | 2100 | } |
| 2112 | 2101 | |
| ... | ... | @@ -2532,8 +2521,8 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2532 | 2521 | } else .{ .sym_index = sym_index }; |
| 2533 | 2522 | self.markRelocsDirtyByTarget(target); |
| 2534 | 2523 | log.debug(" (updating GOT entry)", .{}); |
| 2535 | | const got_atom_index = self.got_table.getAtomIndex(self, target).?; |
| 2536 | | try self.writePtrWidthAtom(got_atom_index); |
| 2524 | const got_atom_index = self.got_table.lookup.get(target).?; |
| 2525 | try self.writeOffsetTableEntry(got_atom_index); |
| 2537 | 2526 | } |
| 2538 | 2527 | } else if (code_len < atom.size) { |
| 2539 | 2528 | self.shrinkAtom(atom_index, code_len); |
| ... | ... | @@ -3276,6 +3265,20 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void { |
| 3276 | 3265 | } |
| 3277 | 3266 | } |
| 3278 | 3267 | |
| 3268 | // Gather GOT pointers |
| 3269 | const segment_index = self.sections.items(.segment_index)[self.got_section_index.?]; |
| 3270 | for (self.got_table.entries.items, 0..) |entry, i| { |
| 3271 | if (!self.got_table.lookup.contains(entry)) continue; |
| 3272 | const sym = self.getSymbol(entry); |
| 3273 | if (sym.undf()) continue; |
| 3274 | const offset = i * @sizeOf(u64); |
| 3275 | log.debug(" | rebase at {x}", .{offset}); |
| 3276 | rebase.entries.appendAssumeCapacity(.{ |
| 3277 | .offset = offset, |
| 3278 | .segment_id = segment_index, |
| 3279 | }); |
| 3280 | } |
| 3281 | |
| 3279 | 3282 | try rebase.finalize(gpa); |
| 3280 | 3283 | } |
| 3281 | 3284 | |
| ... | ... | @@ -3320,6 +3323,32 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void { |
| 3320 | 3323 | } |
| 3321 | 3324 | } |
| 3322 | 3325 | |
| 3326 | // Gather GOT pointers |
| 3327 | const segment_index = self.sections.items(.segment_index)[self.got_section_index.?]; |
| 3328 | for (self.got_table.entries.items, 0..) |entry, i| { |
| 3329 | if (!self.got_table.lookup.contains(entry)) continue; |
| 3330 | const sym = self.getSymbol(entry); |
| 3331 | if (!sym.undf()) continue; |
| 3332 | const offset = i * @sizeOf(u64); |
| 3333 | const bind_sym = self.getSymbol(entry); |
| 3334 | const bind_sym_name = self.getSymbolName(entry); |
| 3335 | const dylib_ordinal = @divTrunc( |
| 3336 | @bitCast(i16, bind_sym.n_desc), |
| 3337 | macho.N_SYMBOL_RESOLVER, |
| 3338 | ); |
| 3339 | log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{ |
| 3340 | offset, |
| 3341 | bind_sym_name, |
| 3342 | dylib_ordinal, |
| 3343 | }); |
| 3344 | bind.entries.appendAssumeCapacity(.{ |
| 3345 | .target = entry, |
| 3346 | .offset = offset, |
| 3347 | .segment_id = segment_index, |
| 3348 | .addend = 0, |
| 3349 | }); |
| 3350 | } |
| 3351 | |
| 3323 | 3352 | try bind.finalize(gpa, self); |
| 3324 | 3353 | } |
| 3325 | 3354 | |
| ... | ... | @@ -3620,10 +3649,10 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void { |
| 3620 | 3649 | const got = &self.sections.items(.header)[sect_id]; |
| 3621 | 3650 | got.reserved1 = nstubs; |
| 3622 | 3651 | for (self.got_table.entries.items) |entry| { |
| 3623 | | if (entry.sym_index == 0) continue; |
| 3624 | | const target_sym = self.getSymbol(entry.target); |
| 3652 | if (!self.got_table.lookup.contains(entry)) continue; |
| 3653 | const target_sym = self.getSymbol(entry); |
| 3625 | 3654 | if (target_sym.undf()) { |
| 3626 | | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?); |
| 3655 | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?); |
| 3627 | 3656 | } else { |
| 3628 | 3657 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 3629 | 3658 | } |
| ... | ... | @@ -4321,7 +4350,7 @@ pub fn logSymtab(self: *MachO) void { |
| 4321 | 4350 | } |
| 4322 | 4351 | |
| 4323 | 4352 | log.debug("GOT entries:", .{}); |
| 4324 | | log.debug("{}", .{self.got_table.fmtDebug(self)}); |
| 4353 | log.debug("{}", .{self.got_table}); |
| 4325 | 4354 | |
| 4326 | 4355 | log.debug("stubs entries:", .{}); |
| 4327 | 4356 | log.debug("{}", .{self.stubs_table.fmtDebug(self)}); |