| ... | ... | @@ -35,6 +35,7 @@ const Section = MachO.Section; |
| 35 | 35 | const StringTable = @import("../strtab.zig").StringTable; |
| 36 | 36 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 37 | 37 | const SymbolResolver = MachO.SymbolResolver; |
| 38 | const TableSection = @import("../table_section.zig").TableSection; |
| 38 | 39 | const Trie = @import("Trie.zig"); |
| 39 | 40 | const UnwindInfo = @import("UnwindInfo.zig"); |
| 40 | 41 | |
| ... | ... | @@ -66,6 +67,8 @@ pub const Zld = struct { |
| 66 | 67 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, |
| 67 | 68 | sections: std.MultiArrayList(Section) = .{}, |
| 68 | 69 | |
| 70 | got_section_index: ?u8 = null, |
| 71 | |
| 69 | 72 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 70 | 73 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| 71 | 74 | |
| ... | ... | @@ -81,8 +84,7 @@ pub const Zld = struct { |
| 81 | 84 | tlv_ptr_entries: std.ArrayListUnmanaged(IndirectPointer) = .{}, |
| 82 | 85 | tlv_ptr_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 83 | 86 | |
| 84 | | got_entries: std.ArrayListUnmanaged(IndirectPointer) = .{}, |
| 85 | | got_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 87 | got_table: TableSection(SymbolWithLoc) = .{}, |
| 86 | 88 | |
| 87 | 89 | stubs: std.ArrayListUnmanaged(IndirectPointer) = .{}, |
| 88 | 90 | stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| ... | ... | @@ -266,32 +268,6 @@ pub const Zld = struct { |
| 266 | 268 | return index; |
| 267 | 269 | } |
| 268 | 270 | |
| 269 | | pub fn createGotAtom(self: *Zld) !AtomIndex { |
| 270 | | const sym_index = try self.allocateSymbol(); |
| 271 | | const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3); |
| 272 | | const sym = self.getSymbolPtr(.{ .sym_index = sym_index }); |
| 273 | | sym.n_type = macho.N_SECT; |
| 274 | | |
| 275 | | const sect_id = self.getSectionByName("__DATA_CONST", "__got") orelse |
| 276 | | try self.initSection("__DATA_CONST", "__got", .{ |
| 277 | | .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, |
| 278 | | }); |
| 279 | | sym.n_sect = sect_id + 1; |
| 280 | | |
| 281 | | self.addAtomToSection(atom_index); |
| 282 | | |
| 283 | | return atom_index; |
| 284 | | } |
| 285 | | |
| 286 | | fn writeGotPointer(self: *Zld, got_index: u32, writer: anytype) !void { |
| 287 | | const target_addr = blk: { |
| 288 | | const entry = self.got_entries.items[got_index]; |
| 289 | | const sym = entry.getTargetSymbol(self); |
| 290 | | break :blk sym.n_value; |
| 291 | | }; |
| 292 | | try writer.writeIntLittle(u64, target_addr); |
| 293 | | } |
| 294 | | |
| 295 | 271 | pub fn createTlvPtrAtom(self: *Zld) !AtomIndex { |
| 296 | 272 | const sym_index = try self.allocateSymbol(); |
| 297 | 273 | const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3); |
| ... | ... | @@ -311,16 +287,9 @@ pub const Zld = struct { |
| 311 | 287 | } |
| 312 | 288 | |
| 313 | 289 | fn createDyldStubBinderGotAtom(self: *Zld) !void { |
| 314 | | const gpa = self.gpa; |
| 315 | 290 | const global_index = self.dyld_stub_binder_index orelse return; |
| 316 | 291 | const target = self.globals.items[global_index]; |
| 317 | | const atom_index = try self.createGotAtom(); |
| 318 | | const got_index = @as(u32, @intCast(self.got_entries.items.len)); |
| 319 | | try self.got_entries.append(gpa, .{ |
| 320 | | .target = target, |
| 321 | | .atom_index = atom_index, |
| 322 | | }); |
| 323 | | try self.got_table.putNoClobber(gpa, target, got_index); |
| 292 | try self.addGotEntry(target); |
| 324 | 293 | } |
| 325 | 294 | |
| 326 | 295 | fn createDyldPrivateAtom(self: *Zld) !void { |
| ... | ... | @@ -381,9 +350,7 @@ pub const Zld = struct { |
| 381 | 350 | }; |
| 382 | 351 | const dyld_stub_binder_got_addr = blk: { |
| 383 | 352 | const sym_loc = self.globals.items[self.dyld_stub_binder_index.?]; |
| 384 | | const index = self.got_table.get(sym_loc).?; |
| 385 | | const entry = self.got_entries.items[index]; |
| 386 | | break :blk entry.getAtomSymbol(self).n_value; |
| 353 | break :blk self.getGotEntryAddress(sym_loc).?; |
| 387 | 354 | }; |
| 388 | 355 | try stub_helpers.writeStubHelperPreambleCode(.{ |
| 389 | 356 | .cpu_arch = cpu_arch, |
| ... | ... | @@ -876,7 +843,6 @@ pub const Zld = struct { |
| 876 | 843 | |
| 877 | 844 | self.tlv_ptr_entries.deinit(gpa); |
| 878 | 845 | self.tlv_ptr_table.deinit(gpa); |
| 879 | | self.got_entries.deinit(gpa); |
| 880 | 846 | self.got_table.deinit(gpa); |
| 881 | 847 | self.stubs.deinit(gpa); |
| 882 | 848 | self.stubs_table.deinit(gpa); |
| ... | ... | @@ -993,6 +959,16 @@ pub const Zld = struct { |
| 993 | 959 | return global_index; |
| 994 | 960 | } |
| 995 | 961 | |
| 962 | pub fn addGotEntry(zld: *Zld, target: SymbolWithLoc) !void { |
| 963 | if (zld.got_table.lookup.contains(target)) return; |
| 964 | _ = try zld.got_table.allocateEntry(zld.gpa, target); |
| 965 | if (zld.got_section_index == null) { |
| 966 | zld.got_section_index = try zld.initSection("__DATA_CONST", "__got", .{ |
| 967 | .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, |
| 968 | }); |
| 969 | } |
| 970 | } |
| 971 | |
| 996 | 972 | fn allocateSpecialSymbols(self: *Zld) !void { |
| 997 | 973 | for (&[_]?u32{ |
| 998 | 974 | self.dso_handle_index, |
| ... | ... | @@ -1056,9 +1032,7 @@ pub const Zld = struct { |
| 1056 | 1032 | buffer.appendSliceAssumeCapacity(&[_]u8{0} ** @sizeOf(u64)); |
| 1057 | 1033 | } else if (atom.getFile() == null) outer: { |
| 1058 | 1034 | switch (header.type()) { |
| 1059 | | macho.S_NON_LAZY_SYMBOL_POINTERS => { |
| 1060 | | try self.writeGotPointer(count, buffer.writer()); |
| 1061 | | }, |
| 1035 | macho.S_NON_LAZY_SYMBOL_POINTERS => unreachable, |
| 1062 | 1036 | macho.S_LAZY_SYMBOL_POINTERS => { |
| 1063 | 1037 | try self.writeLazyPointer(count, buffer.writer()); |
| 1064 | 1038 | }, |
| ... | ... | @@ -1113,41 +1087,70 @@ pub const Zld = struct { |
| 1113 | 1087 | } |
| 1114 | 1088 | } |
| 1115 | 1089 | |
| 1090 | fn writeGotEntries(self: *Zld) !void { |
| 1091 | const sect_id = self.got_section_index orelse return; |
| 1092 | const header = self.sections.items(.header)[sect_id]; |
| 1093 | var buffer = try std.ArrayList(u8).initCapacity(self.gpa, header.size); |
| 1094 | defer buffer.deinit(); |
| 1095 | for (self.got_table.entries.items) |entry| { |
| 1096 | const sym = self.getSymbol(entry); |
| 1097 | buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable; |
| 1098 | } |
| 1099 | log.debug("writing .got contents at file offset 0x{x}", .{header.offset}); |
| 1100 | try self.file.pwriteAll(buffer.items, header.offset); |
| 1101 | } |
| 1102 | |
| 1116 | 1103 | fn pruneAndSortSections(self: *Zld) !void { |
| 1117 | | const gpa = self.gpa; |
| 1104 | const Entry = struct { |
| 1105 | index: u8, |
| 1118 | 1106 | |
| 1119 | | const SortSection = struct { |
| 1120 | | pub fn lessThan(_: void, lhs: Section, rhs: Section) bool { |
| 1121 | | return getSectionPrecedence(lhs.header) < getSectionPrecedence(rhs.header); |
| 1107 | pub fn lessThan(zld: *Zld, lhs: @This(), rhs: @This()) bool { |
| 1108 | const lhs_header = zld.sections.items(.header)[lhs.index]; |
| 1109 | const rhs_header = zld.sections.items(.header)[rhs.index]; |
| 1110 | return getSectionPrecedence(lhs_header) < getSectionPrecedence(rhs_header); |
| 1122 | 1111 | } |
| 1123 | 1112 | }; |
| 1124 | 1113 | |
| 1125 | | const slice = self.sections.slice(); |
| 1126 | | var sections = std.ArrayList(Section).init(gpa); |
| 1127 | | defer sections.deinit(); |
| 1128 | | try sections.ensureTotalCapacity(slice.len); |
| 1114 | const gpa = self.gpa; |
| 1129 | 1115 | |
| 1130 | | { |
| 1131 | | var i: u8 = 0; |
| 1132 | | while (i < slice.len) : (i += 1) { |
| 1133 | | const section = self.sections.get(i); |
| 1134 | | if (section.header.size == 0) { |
| 1135 | | log.debug("pruning section {s},{s} {?d}", .{ |
| 1136 | | section.header.segName(), |
| 1137 | | section.header.sectName(), |
| 1138 | | section.first_atom_index, |
| 1139 | | }); |
| 1140 | | continue; |
| 1141 | | } |
| 1142 | | sections.appendAssumeCapacity(section); |
| 1116 | var entries = try std.ArrayList(Entry).initCapacity(gpa, self.sections.slice().len); |
| 1117 | defer entries.deinit(); |
| 1118 | |
| 1119 | for (0..self.sections.slice().len) |index| { |
| 1120 | const section = self.sections.get(index); |
| 1121 | if (section.header.size == 0) { |
| 1122 | log.debug("pruning section {s},{s} {?d}", .{ |
| 1123 | section.header.segName(), |
| 1124 | section.header.sectName(), |
| 1125 | section.first_atom_index, |
| 1126 | }); |
| 1127 | continue; |
| 1143 | 1128 | } |
| 1129 | entries.appendAssumeCapacity(.{ .index = @intCast(index) }); |
| 1130 | } |
| 1131 | |
| 1132 | mem.sort(Entry, entries.items, self, Entry.lessThan); |
| 1133 | |
| 1134 | var slice = self.sections.toOwnedSlice(); |
| 1135 | defer slice.deinit(gpa); |
| 1136 | |
| 1137 | const backlinks = try gpa.alloc(u8, slice.len); |
| 1138 | defer gpa.free(backlinks); |
| 1139 | for (entries.items, 0..) |entry, i| { |
| 1140 | backlinks[entry.index] = @as(u8, @intCast(i)); |
| 1144 | 1141 | } |
| 1145 | 1142 | |
| 1146 | | mem.sort(Section, sections.items, {}, SortSection.lessThan); |
| 1143 | try self.sections.ensureTotalCapacity(gpa, entries.items.len); |
| 1144 | for (entries.items) |entry| { |
| 1145 | self.sections.appendAssumeCapacity(slice.get(entry.index)); |
| 1146 | } |
| 1147 | 1147 | |
| 1148 | | self.sections.shrinkRetainingCapacity(0); |
| 1149 | | for (sections.items) |out| { |
| 1150 | | self.sections.appendAssumeCapacity(out); |
| 1148 | for (&[_]*?u8{ |
| 1149 | &self.got_section_index, |
| 1150 | }) |maybe_index| { |
| 1151 | if (maybe_index.*) |*index| { |
| 1152 | index.* = backlinks[index.*]; |
| 1153 | } |
| 1151 | 1154 | } |
| 1152 | 1155 | } |
| 1153 | 1156 | |
| ... | ... | @@ -1227,6 +1230,12 @@ pub const Zld = struct { |
| 1227 | 1230 | } else break; |
| 1228 | 1231 | } |
| 1229 | 1232 | } |
| 1233 | |
| 1234 | if (self.got_section_index) |sect_id| { |
| 1235 | const header = &self.sections.items(.header)[sect_id]; |
| 1236 | header.size = self.got_table.count() * @sizeOf(u64); |
| 1237 | header.@"align" = 3; |
| 1238 | } |
| 1230 | 1239 | } |
| 1231 | 1240 | |
| 1232 | 1241 | fn allocateSegments(self: *Zld) !void { |
| ... | ... | @@ -1448,40 +1457,12 @@ pub const Zld = struct { |
| 1448 | 1457 | seg.vmsize = mem.alignForward(u64, seg.filesize, MachO.getPageSize(self.options.target.cpu.arch)); |
| 1449 | 1458 | } |
| 1450 | 1459 | |
| 1451 | | fn collectRebaseDataFromContainer( |
| 1452 | | self: *Zld, |
| 1453 | | sect_id: u8, |
| 1454 | | rebase: *Rebase, |
| 1455 | | container: anytype, |
| 1456 | | ) !void { |
| 1457 | | const slice = self.sections.slice(); |
| 1458 | | const segment_index = slice.items(.segment_index)[sect_id]; |
| 1459 | | const seg = self.getSegment(sect_id); |
| 1460 | | |
| 1461 | | try rebase.entries.ensureUnusedCapacity(self.gpa, container.items.len); |
| 1462 | | |
| 1463 | | for (container.items) |entry| { |
| 1464 | | const target_sym = entry.getTargetSymbol(self); |
| 1465 | | if (target_sym.undf()) continue; |
| 1466 | | |
| 1467 | | const atom_sym = entry.getAtomSymbol(self); |
| 1468 | | const base_offset = atom_sym.n_value - seg.vmaddr; |
| 1469 | | |
| 1470 | | log.debug(" | rebase at {x}", .{base_offset}); |
| 1471 | | |
| 1472 | | rebase.entries.appendAssumeCapacity(.{ |
| 1473 | | .offset = base_offset, |
| 1474 | | .segment_id = segment_index, |
| 1475 | | }); |
| 1476 | | } |
| 1477 | | } |
| 1478 | | |
| 1479 | 1460 | fn collectRebaseData(self: *Zld, rebase: *Rebase) !void { |
| 1480 | 1461 | log.debug("collecting rebase data", .{}); |
| 1481 | 1462 | |
| 1482 | 1463 | // First, unpack GOT entries |
| 1483 | | if (self.getSectionByName("__DATA_CONST", "__got")) |sect_id| { |
| 1484 | | try self.collectRebaseDataFromContainer(sect_id, rebase, self.got_entries); |
| 1464 | if (self.got_section_index) |sect_id| { |
| 1465 | try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table); |
| 1485 | 1466 | } |
| 1486 | 1467 | |
| 1487 | 1468 | const slice = self.sections.slice(); |
| ... | ... | @@ -1543,7 +1524,11 @@ pub const Zld = struct { |
| 1543 | 1524 | }; |
| 1544 | 1525 | |
| 1545 | 1526 | if (should_rebase) { |
| 1546 | | log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) }); |
| 1527 | log.debug(" ATOM({d}, %{d}, '{s}')", .{ |
| 1528 | atom_index, |
| 1529 | atom.sym_index, |
| 1530 | self.getSymbolName(atom.getSymbolWithLoc()), |
| 1531 | }); |
| 1547 | 1532 | |
| 1548 | 1533 | const code = Atom.getAtomCode(self, atom_index); |
| 1549 | 1534 | const relocs = Atom.getAtomRelocs(self, atom_index); |
| ... | ... | @@ -1639,8 +1624,8 @@ pub const Zld = struct { |
| 1639 | 1624 | log.debug("collecting bind data", .{}); |
| 1640 | 1625 | |
| 1641 | 1626 | // First, unpack GOT section |
| 1642 | | if (self.getSectionByName("__DATA_CONST", "__got")) |sect_id| { |
| 1643 | | try self.collectBindDataFromContainer(sect_id, bind, self.got_entries); |
| 1627 | if (self.got_section_index) |sect_id| { |
| 1628 | try MachO.collectBindDataFromTableSection(self.gpa, self, sect_id, bind, self.got_table); |
| 1644 | 1629 | } |
| 1645 | 1630 | |
| 1646 | 1631 | // Next, unpack TLV pointers section |
| ... | ... | @@ -2237,7 +2222,7 @@ pub const Zld = struct { |
| 2237 | 2222 | fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void { |
| 2238 | 2223 | const gpa = self.gpa; |
| 2239 | 2224 | const nstubs = @as(u32, @intCast(self.stubs.items.len)); |
| 2240 | | const ngot_entries = @as(u32, @intCast(self.got_entries.items.len)); |
| 2225 | const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count())); |
| 2241 | 2226 | const nindirectsyms = nstubs * 2 + ngot_entries; |
| 2242 | 2227 | const iextdefsym = ctx.nlocalsym; |
| 2243 | 2228 | const iundefsym = iextdefsym + ctx.nextdefsym; |
| ... | ... | @@ -2266,13 +2251,14 @@ pub const Zld = struct { |
| 2266 | 2251 | } |
| 2267 | 2252 | } |
| 2268 | 2253 | |
| 2269 | | if (self.getSectionByName("__DATA_CONST", "__got")) |sect_id| { |
| 2254 | if (self.got_section_index) |sect_id| { |
| 2270 | 2255 | const got = &self.sections.items(.header)[sect_id]; |
| 2271 | 2256 | got.reserved1 = nstubs; |
| 2272 | | for (self.got_entries.items) |entry| { |
| 2273 | | const target_sym = entry.getTargetSymbol(self); |
| 2257 | for (self.got_table.entries.items) |entry| { |
| 2258 | if (!self.got_table.lookup.contains(entry)) continue; |
| 2259 | const target_sym = self.getSymbol(entry); |
| 2274 | 2260 | if (target_sym.undf()) { |
| 2275 | | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?); |
| 2261 | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?); |
| 2276 | 2262 | } else { |
| 2277 | 2263 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 2278 | 2264 | } |
| ... | ... | @@ -2496,12 +2482,10 @@ pub const Zld = struct { |
| 2496 | 2482 | } |
| 2497 | 2483 | } |
| 2498 | 2484 | |
| 2499 | | /// Returns GOT atom that references `sym_with_loc` if one exists. |
| 2500 | | /// Returns null otherwise. |
| 2501 | | pub fn getGotAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex { |
| 2502 | | const index = self.got_table.get(sym_with_loc) orelse return null; |
| 2503 | | const entry = self.got_entries.items[index]; |
| 2504 | | return entry.atom_index; |
| 2485 | pub fn getGotEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 { |
| 2486 | const index = self.got_table.lookup.get(sym_with_loc) orelse return null; |
| 2487 | const header = self.sections.items(.header)[self.got_section_index.?]; |
| 2488 | return header.addr + @sizeOf(u64) * index; |
| 2505 | 2489 | } |
| 2506 | 2490 | |
| 2507 | 2491 | /// Returns stubs atom that references `sym_with_loc` if one exists. |
| ... | ... | @@ -2849,26 +2833,7 @@ pub const Zld = struct { |
| 2849 | 2833 | } |
| 2850 | 2834 | |
| 2851 | 2835 | scoped_log.debug("GOT entries:", .{}); |
| 2852 | | for (self.got_entries.items, 0..) |entry, i| { |
| 2853 | | const atom_sym = entry.getAtomSymbol(self); |
| 2854 | | const target_sym = entry.getTargetSymbol(self); |
| 2855 | | const target_sym_name = entry.getTargetSymbolName(self); |
| 2856 | | if (target_sym.undf()) { |
| 2857 | | scoped_log.debug(" {d}@{x} => import('{s}')", .{ |
| 2858 | | i, |
| 2859 | | atom_sym.n_value, |
| 2860 | | target_sym_name, |
| 2861 | | }); |
| 2862 | | } else { |
| 2863 | | scoped_log.debug(" {d}@{x} => local(%{d}) in object({?}) {s}", .{ |
| 2864 | | i, |
| 2865 | | atom_sym.n_value, |
| 2866 | | entry.target.sym_index, |
| 2867 | | entry.target.file, |
| 2868 | | logSymAttributes(target_sym, buf[0..4]), |
| 2869 | | }); |
| 2870 | | } |
| 2871 | | } |
| 2836 | scoped_log.debug("{}", .{self.got_table}); |
| 2872 | 2837 | |
| 2873 | 2838 | scoped_log.debug("__thread_ptrs entries:", .{}); |
| 2874 | 2839 | for (self.tlv_ptr_entries.items, 0..) |entry, i| { |
| ... | ... | @@ -3470,6 +3435,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3470 | 3435 | } |
| 3471 | 3436 | |
| 3472 | 3437 | try zld.writeAtoms(); |
| 3438 | try zld.writeGotEntries(); |
| 3473 | 3439 | try eh_frame.write(&zld, &unwind_info); |
| 3474 | 3440 | try unwind_info.write(&zld); |
| 3475 | 3441 | try zld.writeLinkeditSegmentData(); |