| ... | ... | @@ -1416,6 +1416,51 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { |
| 1416 | 1416 | seg.segName(), |
| 1417 | 1417 | }); |
| 1418 | 1418 | } |
| 1419 | |
| 1420 | for (self.globals.items) |global| { |
| 1421 | const sym = self.getSymbolPtr(global); |
| 1422 | if (sym.n_desc != N_BOUNDARY) continue; |
| 1423 | if (self.getSectionBoundarySymbol(global)) |bsym| { |
| 1424 | const sect_id = self.getSectionByName(bsym.segname, bsym.sectname) orelse { |
| 1425 | try self.reportUnresolvedBoundarySymbol(self.getSymbolName(global), "section not found: {s},{s}", .{ |
| 1426 | bsym.segname, bsym.sectname, |
| 1427 | }); |
| 1428 | continue; |
| 1429 | }; |
| 1430 | const sect = self.sections.items(.header)[sect_id]; |
| 1431 | sym.n_sect = sect_id + 1; |
| 1432 | sym.n_value = switch (bsym.kind) { |
| 1433 | .start => sect.addr, |
| 1434 | .stop => sect.addr + sect.size, |
| 1435 | }; |
| 1436 | |
| 1437 | log.debug("allocating {s} at @0x{x} sect({d})", .{ |
| 1438 | self.getSymbolName(global), |
| 1439 | sym.n_value, |
| 1440 | sym.n_sect, |
| 1441 | }); |
| 1442 | |
| 1443 | continue; |
| 1444 | } |
| 1445 | if (self.getSegmentBoundarySymbol(global)) |bsym| { |
| 1446 | const seg_id = self.getSegmentByName(bsym.segname) orelse { |
| 1447 | try self.reportUnresolvedBoundarySymbol(self.getSymbolName(global), "segment not found: {s}", .{ |
| 1448 | bsym.segname, |
| 1449 | }); |
| 1450 | |
| 1451 | continue; |
| 1452 | }; |
| 1453 | const seg = self.segments.items[seg_id]; |
| 1454 | sym.n_value = switch (bsym.kind) { |
| 1455 | .start => seg.vmaddr, |
| 1456 | .stop => seg.vmaddr + seg.vmsize, |
| 1457 | }; |
| 1458 | |
| 1459 | log.debug("allocating {s} at @0x{x} ", .{ self.getSymbolName(global), sym.n_value }); |
| 1460 | |
| 1461 | continue; |
| 1462 | } |
| 1463 | } |
| 1419 | 1464 | } |
| 1420 | 1465 | |
| 1421 | 1466 | const CreateAtomOpts = struct { |
| ... | ... | @@ -1442,6 +1487,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void { |
| 1442 | 1487 | const sym = self.getSymbolPtr(global); |
| 1443 | 1488 | if (!sym.tentative()) continue; |
| 1444 | 1489 | if (sym.n_desc == N_DEAD) continue; |
| 1490 | if (sym.n_desc == N_BOUNDARY) continue; |
| 1445 | 1491 | |
| 1446 | 1492 | log.debug("creating tentative definition for ATOM(%{d}, '{s}') in object({?})", .{ |
| 1447 | 1493 | global.sym_index, self.getSymbolName(global), global.file, |
| ... | ... | @@ -1630,6 +1676,13 @@ pub fn resolveSymbols(self: *MachO) !void { |
| 1630 | 1676 | try self.createMhExecuteHeaderSymbol(); |
| 1631 | 1677 | try self.createDsoHandleSymbol(); |
| 1632 | 1678 | try self.resolveSymbolsAtLoading(); |
| 1679 | |
| 1680 | // Final stop, check if unresolved contain any of the special magic boundary symbols |
| 1681 | // * section$start$ |
| 1682 | // * section$stop$ |
| 1683 | // * segment$start$ |
| 1684 | // * segment$stop$ |
| 1685 | try self.resolveBoundarySymbols(); |
| 1633 | 1686 | } |
| 1634 | 1687 | |
| 1635 | 1688 | fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void { |
| ... | ... | @@ -1845,6 +1898,34 @@ fn resolveSymbolsAtLoading(self: *MachO) !void { |
| 1845 | 1898 | } |
| 1846 | 1899 | } |
| 1847 | 1900 | |
| 1901 | fn resolveBoundarySymbols(self: *MachO) !void { |
| 1902 | var next_sym: usize = 0; |
| 1903 | while (next_sym < self.unresolved.count()) { |
| 1904 | const global_index = self.unresolved.keys()[next_sym]; |
| 1905 | const global = &self.globals.items[global_index]; |
| 1906 | |
| 1907 | if (self.getSectionBoundarySymbol(global.*) != null or self.getSegmentBoundarySymbol(global.*) != null) { |
| 1908 | const sym_index = try self.allocateSymbol(); |
| 1909 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; |
| 1910 | const sym = self.getSymbolPtr(sym_loc); |
| 1911 | sym.* = .{ |
| 1912 | .n_strx = try self.strtab.insert(self.base.allocator, self.getSymbolName(global.*)), |
| 1913 | .n_type = macho.N_SECT | macho.N_EXT, |
| 1914 | .n_sect = 0, |
| 1915 | .n_desc = N_BOUNDARY, |
| 1916 | .n_value = 0, |
| 1917 | }; |
| 1918 | if (global.getFile()) |file| { |
| 1919 | const global_object = &self.objects.items[file]; |
| 1920 | global_object.globals_lookup[global.sym_index] = global_index; |
| 1921 | } |
| 1922 | global.* = sym_loc; |
| 1923 | _ = self.unresolved.swapRemove(global_index); |
| 1924 | continue; |
| 1925 | } |
| 1926 | } |
| 1927 | } |
| 1928 | |
| 1848 | 1929 | pub fn deinit(self: *MachO) void { |
| 1849 | 1930 | const gpa = self.base.allocator; |
| 1850 | 1931 | |
| ... | ... | @@ -3565,6 +3646,7 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void { |
| 3565 | 3646 | const atom = self.getAtom(atom_index); |
| 3566 | 3647 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 3567 | 3648 | if (sym.n_desc == N_DEAD) continue; |
| 3649 | if (sym.n_desc == N_BOUNDARY) continue; |
| 3568 | 3650 | |
| 3569 | 3651 | const sect_id = sym.n_sect - 1; |
| 3570 | 3652 | const section = self.sections.items(.header)[sect_id]; |
| ... | ... | @@ -3719,6 +3801,7 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void { |
| 3719 | 3801 | const atom = self.getAtom(atom_index); |
| 3720 | 3802 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 3721 | 3803 | if (sym.n_desc == N_DEAD) continue; |
| 3804 | if (sym.n_desc == N_BOUNDARY) continue; |
| 3722 | 3805 | |
| 3723 | 3806 | const sect_id = sym.n_sect - 1; |
| 3724 | 3807 | const section = self.sections.items(.header)[sect_id]; |
| ... | ... | @@ -3819,6 +3902,7 @@ fn collectExportData(self: *MachO, trie: *Trie) !void { |
| 3819 | 3902 | if (sym.undf()) continue; |
| 3820 | 3903 | assert(sym.ext()); |
| 3821 | 3904 | if (sym.n_desc == N_DEAD) continue; |
| 3905 | if (sym.n_desc == N_BOUNDARY) continue; |
| 3822 | 3906 | |
| 3823 | 3907 | const sym_name = self.getSymbolName(global); |
| 3824 | 3908 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); |
| ... | ... | @@ -3953,7 +4037,8 @@ const asc_u64 = std.sort.asc(u64); |
| 3953 | 4037 | fn addSymbolToFunctionStarts(self: *MachO, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void { |
| 3954 | 4038 | const sym = self.getSymbol(sym_loc); |
| 3955 | 4039 | if (sym.n_strx == 0) return; |
| 3956 | | if (sym.n_desc == MachO.N_DEAD) return; |
| 4040 | if (sym.n_desc == N_DEAD) return; |
| 4041 | if (sym.n_desc == N_BOUNDARY) return; |
| 3957 | 4042 | if (self.symbolIsTemp(sym_loc)) return; |
| 3958 | 4043 | try addresses.append(sym.n_value); |
| 3959 | 4044 | } |
| ... | ... | @@ -4061,7 +4146,8 @@ pub fn writeDataInCode(self: *MachO) !void { |
| 4061 | 4146 | for (object.exec_atoms.items) |atom_index| { |
| 4062 | 4147 | const atom = self.getAtom(atom_index); |
| 4063 | 4148 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 4064 | | if (sym.n_desc == MachO.N_DEAD) continue; |
| 4149 | if (sym.n_desc == N_DEAD) continue; |
| 4150 | if (sym.n_desc == N_BOUNDARY) return; |
| 4065 | 4151 | |
| 4066 | 4152 | const source_addr = if (object.getSourceSymbol(atom.sym_index)) |source_sym| |
| 4067 | 4153 | source_sym.n_value |
| ... | ... | @@ -4119,7 +4205,8 @@ fn writeSymtabs(self: *MachO) !void { |
| 4119 | 4205 | fn addLocalToSymtab(self: *MachO, sym_loc: SymbolWithLoc, locals: *std.ArrayList(macho.nlist_64)) !void { |
| 4120 | 4206 | const sym = self.getSymbol(sym_loc); |
| 4121 | 4207 | if (sym.n_strx == 0) return; // no name, skip |
| 4122 | | if (sym.n_desc == MachO.N_DEAD) return; // garbage-collected, skip |
| 4208 | if (sym.n_desc == N_DEAD) return; // garbage-collected, skip |
| 4209 | if (sym.n_desc == N_BOUNDARY) return; // boundary symbol, skip |
| 4123 | 4210 | if (sym.ext()) return; // an export lands in its own symtab section, skip |
| 4124 | 4211 | if (self.symbolIsTemp(sym_loc)) return; // local temp symbol, skip |
| 4125 | 4212 | var out_sym = sym; |
| ... | ... | @@ -4157,6 +4244,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx { |
| 4157 | 4244 | const sym = self.getSymbol(global); |
| 4158 | 4245 | if (sym.undf()) continue; // import, skip |
| 4159 | 4246 | if (sym.n_desc == N_DEAD) continue; |
| 4247 | if (sym.n_desc == N_BOUNDARY) continue; |
| 4160 | 4248 | var out_sym = sym; |
| 4161 | 4249 | out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(global)); |
| 4162 | 4250 | try exports.append(out_sym); |
| ... | ... | @@ -4172,6 +4260,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx { |
| 4172 | 4260 | if (sym.n_strx == 0) continue; // no name, skip |
| 4173 | 4261 | if (!sym.undf()) continue; // not an import, skip |
| 4174 | 4262 | if (sym.n_desc == N_DEAD) continue; |
| 4263 | if (sym.n_desc == N_BOUNDARY) continue; |
| 4175 | 4264 | const new_index = @as(u32, @intCast(imports.items.len)); |
| 4176 | 4265 | var out_sym = sym; |
| 4177 | 4266 | out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(global)); |
| ... | ... | @@ -4842,6 +4931,55 @@ pub fn getSymbolName(self: *const MachO, sym_with_loc: SymbolWithLoc) []const u8 |
| 4842 | 4931 | } |
| 4843 | 4932 | } |
| 4844 | 4933 | |
| 4934 | const BoundarySymbolKind = enum { |
| 4935 | start, |
| 4936 | stop, |
| 4937 | }; |
| 4938 | |
| 4939 | const SectionBoundarySymbol = struct { |
| 4940 | kind: BoundarySymbolKind, |
| 4941 | segname: []const u8, |
| 4942 | sectname: []const u8, |
| 4943 | }; |
| 4944 | |
| 4945 | pub fn getSectionBoundarySymbol(self: *const MachO, sym_with_loc: SymbolWithLoc) ?SectionBoundarySymbol { |
| 4946 | const sym_name = self.getSymbolName(sym_with_loc); |
| 4947 | if (mem.startsWith(u8, sym_name, "section$")) { |
| 4948 | const trailing = sym_name["section$".len..]; |
| 4949 | const kind: BoundarySymbolKind = kind: { |
| 4950 | if (mem.startsWith(u8, trailing, "start$")) break :kind .start; |
| 4951 | if (mem.startsWith(u8, trailing, "stop$")) break :kind .stop; |
| 4952 | return null; |
| 4953 | }; |
| 4954 | const names = trailing[@tagName(kind).len + 1 ..]; |
| 4955 | const sep_idx = mem.indexOf(u8, names, "$") orelse return null; |
| 4956 | const segname = names[0..sep_idx]; |
| 4957 | const sectname = names[sep_idx + 1 ..]; |
| 4958 | return .{ .kind = kind, .segname = segname, .sectname = sectname }; |
| 4959 | } |
| 4960 | return null; |
| 4961 | } |
| 4962 | |
| 4963 | const SegmentBoundarySymbol = struct { |
| 4964 | kind: BoundarySymbolKind, |
| 4965 | segname: []const u8, |
| 4966 | }; |
| 4967 | |
| 4968 | pub fn getSegmentBoundarySymbol(self: *const MachO, sym_with_loc: SymbolWithLoc) ?SegmentBoundarySymbol { |
| 4969 | const sym_name = self.getSymbolName(sym_with_loc); |
| 4970 | if (mem.startsWith(u8, sym_name, "segment$")) { |
| 4971 | const trailing = sym_name["segment$".len..]; |
| 4972 | const kind: BoundarySymbolKind = kind: { |
| 4973 | if (mem.startsWith(u8, trailing, "start$")) break :kind .start; |
| 4974 | if (mem.startsWith(u8, trailing, "stop$")) break :kind .stop; |
| 4975 | return null; |
| 4976 | }; |
| 4977 | const segname = trailing[@tagName(kind).len + 1 ..]; |
| 4978 | return .{ .kind = kind, .segname = segname }; |
| 4979 | } |
| 4980 | return null; |
| 4981 | } |
| 4982 | |
| 4845 | 4983 | /// Returns pointer to the global entry for `name` if one exists. |
| 4846 | 4984 | pub fn getGlobalPtr(self: *MachO, name: []const u8) ?*SymbolWithLoc { |
| 4847 | 4985 | const global_index = self.resolver.get(name) orelse return null; |
| ... | ... | @@ -5137,6 +5275,23 @@ pub fn reportParseError( |
| 5137 | 5275 | }); |
| 5138 | 5276 | } |
| 5139 | 5277 | |
| 5278 | pub fn reportUnresolvedBoundarySymbol( |
| 5279 | self: *MachO, |
| 5280 | sym_name: []const u8, |
| 5281 | comptime format: []const u8, |
| 5282 | args: anytype, |
| 5283 | ) error{OutOfMemory}!void { |
| 5284 | const gpa = self.base.allocator; |
| 5285 | try self.misc_errors.ensureUnusedCapacity(gpa, 1); |
| 5286 | var notes = try gpa.alloc(File.ErrorMsg, 1); |
| 5287 | errdefer gpa.free(notes); |
| 5288 | notes[0] = .{ .msg = try std.fmt.allocPrint(gpa, "while resolving {s}", .{sym_name}) }; |
| 5289 | self.misc_errors.appendAssumeCapacity(.{ |
| 5290 | .msg = try std.fmt.allocPrint(gpa, format, args), |
| 5291 | .notes = notes, |
| 5292 | }); |
| 5293 | } |
| 5294 | |
| 5140 | 5295 | pub fn reportUndefined(self: *MachO) error{OutOfMemory}!void { |
| 5141 | 5296 | const gpa = self.base.allocator; |
| 5142 | 5297 | const count = self.unresolved.count(); |
| ... | ... | @@ -5340,7 +5495,8 @@ pub fn logSymtab(self: *MachO) void { |
| 5340 | 5495 | for (self.globals.items, 0..) |global, i| { |
| 5341 | 5496 | const sym = self.getSymbol(global); |
| 5342 | 5497 | if (sym.undf()) continue; |
| 5343 | | if (sym.n_desc == MachO.N_DEAD) continue; |
| 5498 | if (sym.n_desc == N_DEAD) continue; |
| 5499 | if (sym.n_desc == N_BOUNDARY) continue; |
| 5344 | 5500 | scoped_log.debug(" %{d}: {s} @{x} in sect({d}), {s} (def in object({?}))", .{ |
| 5345 | 5501 | i, |
| 5346 | 5502 | self.getSymbolName(global), |
| ... | ... | @@ -5355,7 +5511,8 @@ pub fn logSymtab(self: *MachO) void { |
| 5355 | 5511 | for (self.globals.items, 0..) |global, i| { |
| 5356 | 5512 | const sym = self.getSymbol(global); |
| 5357 | 5513 | if (!sym.undf()) continue; |
| 5358 | | if (sym.n_desc == MachO.N_DEAD) continue; |
| 5514 | if (sym.n_desc == N_DEAD) continue; |
| 5515 | if (sym.n_desc == N_BOUNDARY) continue; |
| 5359 | 5516 | const ord = @divTrunc(sym.n_desc, macho.N_SYMBOL_RESOLVER); |
| 5360 | 5517 | scoped_log.debug(" %{d}: {s} @{x} in ord({d}), {s}", .{ |
| 5361 | 5518 | i, |
| ... | ... | @@ -5466,6 +5623,7 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index, logger: anytype) void { |
| 5466 | 5623 | |
| 5467 | 5624 | pub const base_tag: File.Tag = File.Tag.macho; |
| 5468 | 5625 | pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1))); |
| 5626 | pub const N_BOUNDARY: u16 = @as(u16, @bitCast(@as(i16, -2))); |
| 5469 | 5627 | |
| 5470 | 5628 | /// Mode of operation of the linker. |
| 5471 | 5629 | pub const Mode = enum { |