authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-10-12 00:04:33+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-12 02:53:15-07:00
log7e530c13b3ef9b61417a610c00fc1d37c11ff7ed
treea88fcad833f8413ddc753afec2dec8f35f70fe95
parent008acd0547751c43f42172eab4879c566698dce3

macho: create dummy atom of size 0 marking end of a section

Some compilers such as Go reference the end of a section (addr + size) which cannot be contained in any non-zero atom (since then this atom would exceed section boundaries). In order to facilitate this behaviour, we create a dummy zero-sized atom at section end (addr + size).

1 files changed, 34 insertions(+), 3 deletions(-)

src/link/MachO/Object.zig+34-3
...@@ -308,7 +308,7 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {...@@ -308,7 +308,7 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
308 } else nlists.len;308 } else nlists.len;
309309
310 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {310 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {
311 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() });311 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}$begin", .{ sect.segName(), sect.sectName() });
312 defer allocator.free(name);312 defer allocator.free(name);
313 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;313 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;
314 const atom_index = try self.addAtom(allocator, .{314 const atom_index = try self.addAtom(allocator, .{
...@@ -359,6 +359,25 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {...@@ -359,6 +359,25 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
359 self.symtab.items(.size)[nlists[i].idx] = size;359 self.symtab.items(.size)[nlists[i].idx] = size;
360 }360 }
361 }361 }
362
363 // Some compilers such as Go reference the end of a section (addr + size)
364 // which cannot be contained in any non-zero atom (since then this atom
365 // would exceed section boundaries). In order to facilitate this behaviour,
366 // we create a dummy zero-sized atom at section end (addr + size).
367 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}$end", .{ sect.segName(), sect.sectName() });
368 defer allocator.free(name);
369 const atom_index = try self.addAtom(allocator, .{
370 .name = try self.addString(allocator, name),
371 .n_sect = @intCast(n_sect),
372 .off = sect.size,
373 .size = 0,
374 .alignment = sect.@"align",
375 });
376 try self.atoms_indexes.append(allocator, atom_index);
377 try subsections.append(allocator, .{
378 .atom = atom_index,
379 .off = sect.size,
380 });
362 }381 }
363}382}
364383
...@@ -743,7 +762,7 @@ pub fn findAtom(self: Object, addr: u64) ?Atom.Index {...@@ -743,7 +762,7 @@ pub fn findAtom(self: Object, addr: u64) ?Atom.Index {
743 const slice = self.sections.slice();762 const slice = self.sections.slice();
744 for (slice.items(.header), slice.items(.subsections), 0..) |sect, subs, n_sect| {763 for (slice.items(.header), slice.items(.subsections), 0..) |sect, subs, n_sect| {
745 if (subs.items.len == 0) continue;764 if (subs.items.len == 0) continue;
746 if (sect.addr == addr) return subs.items[0].atom;765 if (addr == sect.addr) return subs.items[0].atom;
747 if (sect.addr < addr and addr < sect.addr + sect.size) {766 if (sect.addr < addr and addr < sect.addr + sect.size) {
748 return self.findAtomInSection(addr, @intCast(n_sect));767 return self.findAtomInSection(addr, @intCast(n_sect));
749 }768 }
...@@ -794,7 +813,19 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void {...@@ -794,7 +813,19 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void {
794 defer tracy.end();813 defer tracy.end();
795 for (self.symtab.items(.nlist), self.symtab.items(.atom)) |nlist, *atom| {814 for (self.symtab.items(.nlist), self.symtab.items(.atom)) |nlist, *atom| {
796 if (!nlist.stab() and nlist.sect()) {815 if (!nlist.stab() and nlist.sect()) {
797 if (self.findAtomInSection(nlist.n_value, nlist.n_sect - 1)) |atom_index| {816 const sect = self.sections.items(.header)[nlist.n_sect - 1];
817 const subs = self.sections.items(.subsections)[nlist.n_sect - 1].items;
818 if (nlist.n_value == sect.addr) {
819 // If the nlist address is the start of the section, return the first atom
820 // since it is guaranteed to always start at section's start address.
821 atom.* = subs[0].atom;
822 } else if (nlist.n_value == sect.addr + sect.size) {
823 // If the nlist address matches section's boundary (address + size),
824 // return the last atom since it is guaranteed to always point
825 // at the section's end boundary.
826 atom.* = subs[subs.len - 1].atom;
827 } else if (self.findAtomInSection(nlist.n_value, nlist.n_sect - 1)) |atom_index| {
828 // In all other cases, do a binary search to find a matching atom for the symbol.
798 atom.* = atom_index;829 atom.* = atom_index;
799 } else {830 } else {
800 try macho_file.reportParseError2(self.index, "symbol {s} not attached to any (sub)section", .{831 try macho_file.reportParseError2(self.index, "symbol {s} not attached to any (sub)section", .{