authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-21 09:39:12+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-22 16:58:21+02:00
log7345976261d4381ed48807f2003709e7ff609b0c
tree4b0e53886309a219f9818c2e49dd4f9633970090
parent39df241df4ac177503d899dd8b53a632e4e29334

macho: sort subsection symbols by seniority


2 files changed, 133 insertions(+), 90 deletions(-)

src/link/MachO.zig+90-75
...@@ -2940,12 +2940,6 @@ fn createTentativeDefAtoms(self: *MachO) !void {...@@ -2940,12 +2940,6 @@ fn createTentativeDefAtoms(self: *MachO) !void {
29402940
2941 if (global.file) |file| {2941 if (global.file) |file| {
2942 const object = &self.objects.items[file];2942 const object = &self.objects.items[file];
2943
2944 try atom.contained.append(gpa, .{
2945 .sym_index = global.sym_index,
2946 .offset = 0,
2947 });
2948
2949 try object.managed_atoms.append(gpa, atom);2943 try object.managed_atoms.append(gpa, atom);
2950 try object.atom_by_index_table.putNoClobber(gpa, global.sym_index, atom);2944 try object.atom_by_index_table.putNoClobber(gpa, global.sym_index, atom);
2951 } else {2945 } else {
...@@ -5594,6 +5588,7 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {...@@ -5594,6 +5588,7 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
55945588
5595 const global = atom.getSymbolWithLoc();5589 const global = atom.getSymbolWithLoc();
5596 const sym = atom.getSymbolPtr(self);5590 const sym = atom.getSymbolPtr(self);
5591 const match = self.getMatchingSectionFromOrdinal(sym.n_sect);
55975592
5598 if (sym.n_desc == N_DESC_GCED) continue;5593 if (sym.n_desc == N_DESC_GCED) continue;
5599 if (!sym.ext()) {5594 if (!sym.ext()) {
...@@ -5605,15 +5600,6 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {...@@ -5605,15 +5600,6 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
5605 } else continue;5600 } else continue;
5606 }5601 }
56075602
5608 loop = true;
5609 const match = self.getMatchingSectionFromOrdinal(sym.n_sect);
5610
5611 // TODO don't dedup eh_frame info yet until we actually implement parsing unwind records
5612 if (match.eql(.{
5613 .seg = self.text_segment_cmd_index,
5614 .sect = self.eh_frame_section_index,
5615 })) continue;
5616
5617 self.logAtom(atom);5603 self.logAtom(atom);
5618 sym.n_desc = N_DESC_GCED;5604 sym.n_desc = N_DESC_GCED;
5619 self.removeAtomFromSection(atom, match);5605 self.removeAtomFromSection(atom, match);
...@@ -5644,6 +5630,8 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {...@@ -5644,6 +5630,8 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
5644 const tlv_ptr_sym = tlv_ptr_atom.getSymbolPtr(self);5630 const tlv_ptr_sym = tlv_ptr_atom.getSymbolPtr(self);
5645 tlv_ptr_sym.n_desc = N_DESC_GCED;5631 tlv_ptr_sym.n_desc = N_DESC_GCED;
5646 }5632 }
5633
5634 loop = true;
5647 }5635 }
5648 }5636 }
5649 }5637 }
...@@ -6831,7 +6819,6 @@ pub fn generateSymbolStabs(...@@ -6831,7 +6819,6 @@ pub fn generateSymbolStabs(
6831 };6819 };
6832 const tu_name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name);6820 const tu_name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name);
6833 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir);6821 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir);
6834 const source_symtab = object.getSourceSymtab();
68356822
6836 // Open scope6823 // Open scope
6837 try locals.ensureUnusedCapacity(3);6824 try locals.ensureUnusedCapacity(3);
...@@ -6857,71 +6844,27 @@ pub fn generateSymbolStabs(...@@ -6857,71 +6844,27 @@ pub fn generateSymbolStabs(
6857 .n_value = object.mtime,6844 .n_value = object.mtime,
6858 });6845 });
68596846
6847 var stabs_buf: [4]macho.nlist_64 = undefined;
6848
6860 for (object.managed_atoms.items) |atom| {6849 for (object.managed_atoms.items) |atom| {
6850 const stabs = try self.generateSymbolStabsForSymbol(
6851 atom.getSymbolWithLoc(),
6852 debug_info,
6853 &stabs_buf,
6854 );
6855 try locals.appendSlice(stabs);
6856
6861 for (atom.contained.items) |sym_at_off| {6857 for (atom.contained.items) |sym_at_off| {
6862 const sym_loc = SymbolWithLoc{6858 const sym_loc = SymbolWithLoc{
6863 .sym_index = sym_at_off.sym_index,6859 .sym_index = sym_at_off.sym_index,
6864 .file = atom.file,6860 .file = atom.file,
6865 };6861 };
6866 const sym = self.getSymbol(sym_loc);6862 const contained_stabs = try self.generateSymbolStabsForSymbol(
6867 const sym_name = self.getSymbolName(sym_loc);6863 sym_loc,
6868 if (sym.n_strx == 0) continue;6864 debug_info,
6869 if (sym.n_desc == N_DESC_GCED) continue;6865 &stabs_buf,
6870 if (self.symbolIsTemp(sym_loc)) continue;6866 );
6871 if (sym_at_off.sym_index >= source_symtab.len) continue; // synthetic, linker generated6867 try locals.appendSlice(contained_stabs);
6872
6873 const source_sym = source_symtab[sym_at_off.sym_index];
6874 const size: ?u64 = size: {
6875 if (source_sym.tentative()) break :size null;
6876 for (debug_info.inner.func_list.items) |func| {
6877 if (func.pc_range) |range| {
6878 if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {
6879 break :size range.end - range.start;
6880 }
6881 }
6882 }
6883 break :size null;
6884 };
6885
6886 if (size) |ss| {
6887 try locals.ensureUnusedCapacity(4);
6888 locals.appendAssumeCapacity(.{
6889 .n_strx = 0,
6890 .n_type = macho.N_BNSYM,
6891 .n_sect = sym.n_sect,
6892 .n_desc = 0,
6893 .n_value = sym.n_value,
6894 });
6895 locals.appendAssumeCapacity(.{
6896 .n_strx = try self.strtab.insert(gpa, sym_name),
6897 .n_type = macho.N_FUN,
6898 .n_sect = sym.n_sect,
6899 .n_desc = 0,
6900 .n_value = sym.n_value,
6901 });
6902 locals.appendAssumeCapacity(.{
6903 .n_strx = 0,
6904 .n_type = macho.N_FUN,
6905 .n_sect = 0,
6906 .n_desc = 0,
6907 .n_value = ss,
6908 });
6909 locals.appendAssumeCapacity(.{
6910 .n_strx = 0,
6911 .n_type = macho.N_ENSYM,
6912 .n_sect = sym.n_sect,
6913 .n_desc = 0,
6914 .n_value = ss,
6915 });
6916 } else {
6917 try locals.append(.{
6918 .n_strx = try self.strtab.insert(gpa, sym_name),
6919 .n_type = macho.N_STSYM,
6920 .n_sect = sym.n_sect,
6921 .n_desc = 0,
6922 .n_value = sym.n_value,
6923 });
6924 }
6925 }6868 }
6926 }6869 }
69276870
...@@ -6935,6 +6878,78 @@ pub fn generateSymbolStabs(...@@ -6935,6 +6878,78 @@ pub fn generateSymbolStabs(
6935 });6878 });
6936}6879}
69376880
6881fn generateSymbolStabsForSymbol(
6882 self: *MachO,
6883 sym_loc: SymbolWithLoc,
6884 debug_info: DebugInfo,
6885 buf: *[4]macho.nlist_64,
6886) ![]const macho.nlist_64 {
6887 const gpa = self.base.allocator;
6888 const object = self.objects.items[sym_loc.file.?];
6889 const source_symtab = object.getSourceSymtab();
6890 const sym = self.getSymbol(sym_loc);
6891 const sym_name = self.getSymbolName(sym_loc);
6892
6893 if (sym.n_strx == 0) return buf[0..0];
6894 if (sym.n_desc == N_DESC_GCED) return buf[0..0];
6895 if (self.symbolIsTemp(sym_loc)) return buf[0..0];
6896 if (sym_loc.sym_index >= source_symtab.len) return buf[0..0]; // synthetic, linker generated
6897
6898 const source_sym = source_symtab[sym_loc.sym_index];
6899 const size: ?u64 = size: {
6900 if (source_sym.tentative()) break :size null;
6901 for (debug_info.inner.func_list.items) |func| {
6902 if (func.pc_range) |range| {
6903 if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {
6904 break :size range.end - range.start;
6905 }
6906 }
6907 }
6908 break :size null;
6909 };
6910
6911 if (size) |ss| {
6912 buf[0] = .{
6913 .n_strx = 0,
6914 .n_type = macho.N_BNSYM,
6915 .n_sect = sym.n_sect,
6916 .n_desc = 0,
6917 .n_value = sym.n_value,
6918 };
6919 buf[1] = .{
6920 .n_strx = try self.strtab.insert(gpa, sym_name),
6921 .n_type = macho.N_FUN,
6922 .n_sect = sym.n_sect,
6923 .n_desc = 0,
6924 .n_value = sym.n_value,
6925 };
6926 buf[2] = .{
6927 .n_strx = 0,
6928 .n_type = macho.N_FUN,
6929 .n_sect = 0,
6930 .n_desc = 0,
6931 .n_value = ss,
6932 };
6933 buf[3] = .{
6934 .n_strx = 0,
6935 .n_type = macho.N_ENSYM,
6936 .n_sect = sym.n_sect,
6937 .n_desc = 0,
6938 .n_value = ss,
6939 };
6940 return buf;
6941 } else {
6942 buf[0] = .{
6943 .n_strx = try self.strtab.insert(gpa, sym_name),
6944 .n_type = macho.N_STSYM,
6945 .n_sect = sym.n_sect,
6946 .n_desc = 0,
6947 .n_value = sym.n_value,
6948 };
6949 return buf[0..1];
6950 }
6951}
6952
6938fn snapshotState(self: *MachO) !void {6953fn snapshotState(self: *MachO) !void {
6939 const emit = self.base.options.emit orelse {6954 const emit = self.base.options.emit orelse {
6940 log.debug("no emit directory found; skipping snapshot...", .{});6955 log.debug("no emit directory found; skipping snapshot...", .{});
src/link/MachO/Object.zig+43-15
...@@ -197,11 +197,9 @@ const SymbolAtIndex = struct {...@@ -197,11 +197,9 @@ const SymbolAtIndex = struct {
197 return mem.sliceTo(@ptrCast([*:0]const u8, ctx.strtab.ptr + sym.n_strx), 0);197 return mem.sliceTo(@ptrCast([*:0]const u8, ctx.strtab.ptr + sym.n_strx), 0);
198 }198 }
199199
200 /// Returns whether lhs is less than rhs by allocated address in object file.
201 /// Undefined symbols are pushed to the back (always evaluate to true).
200 fn lessThan(ctx: Context, lhs_index: SymbolAtIndex, rhs_index: SymbolAtIndex) bool {202 fn lessThan(ctx: Context, lhs_index: SymbolAtIndex, rhs_index: SymbolAtIndex) bool {
201 // We sort by type: defined < undefined, and
202 // afterwards by address in each group. Normally, dysymtab should
203 // be enough to guarantee the sort, but turns out not every compiler
204 // is kind enough to specify the symbols in the correct order.
205 const lhs = lhs_index.getSymbol(ctx);203 const lhs = lhs_index.getSymbol(ctx);
206 const rhs = rhs_index.getSymbol(ctx);204 const rhs = rhs_index.getSymbol(ctx);
207 if (lhs.sect()) {205 if (lhs.sect()) {
...@@ -215,6 +213,29 @@ const SymbolAtIndex = struct {...@@ -215,6 +213,29 @@ const SymbolAtIndex = struct {
215 return false;213 return false;
216 }214 }
217 }215 }
216
217 /// Returns whether lhs is less senior than rhs. The rules are:
218 /// 1. ext
219 /// 2. weak
220 /// 3. local
221 /// 4. temp (local starting with `l` prefix).
222 fn lessThanBySeniority(ctx: Context, lhs_index: SymbolAtIndex, rhs_index: SymbolAtIndex) bool {
223 const lhs = lhs_index.getSymbol(ctx);
224 const rhs = rhs_index.getSymbol(ctx);
225 if (!rhs.ext()) {
226 const lhs_name = lhs_index.getSymbolName(ctx);
227 return mem.startsWith(u8, lhs_name, "l") or mem.startsWith(u8, lhs_name, "L");
228 } else if (rhs.pext() or rhs.weakDef()) {
229 return !lhs.ext();
230 } else {
231 return false;
232 }
233 }
234
235 /// Like lessThanBySeniority but negated.
236 fn greaterThanBySeniority(ctx: Context, lhs_index: SymbolAtIndex, rhs_index: SymbolAtIndex) bool {
237 return !lessThanBySeniority(ctx, lhs_index, rhs_index);
238 }
218};239};
219240
220fn filterSymbolsByAddress(241fn filterSymbolsByAddress(
...@@ -295,6 +316,10 @@ pub fn splitIntoAtomsOneShot(...@@ -295,6 +316,10 @@ pub fn splitIntoAtomsOneShot(
295 sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) });316 sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) });
296 }317 }
297318
319 // We sort by type: defined < undefined, and
320 // afterwards by address in each group. Normally, dysymtab should
321 // be enough to guarantee the sort, but turns out not every compiler
322 // is kind enough to specify the symbols in the correct order.
298 sort.sort(SymbolAtIndex, sorted_all_syms.items, context, SymbolAtIndex.lessThan);323 sort.sort(SymbolAtIndex, sorted_all_syms.items, context, SymbolAtIndex.lessThan);
299324
300 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we325 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
...@@ -409,10 +434,18 @@ pub fn splitIntoAtomsOneShot(...@@ -409,10 +434,18 @@ pub fn splitIntoAtomsOneShot(
409 );434 );
410 next_sym_count += atom_syms.len;435 next_sym_count += atom_syms.len;
411436
437 // We want to bubble up the first externally defined symbol here.
412 assert(atom_syms.len > 0);438 assert(atom_syms.len > 0);
413 const sym_index = for (atom_syms) |atom_sym| {439 var sorted_atom_syms = std.ArrayList(SymbolAtIndex).init(gpa);
414 if (atom_sym.getSymbol(context).ext()) break atom_sym.index;440 defer sorted_atom_syms.deinit();
415 } else atom_syms[0].index;441 try sorted_atom_syms.appendSlice(atom_syms);
442 sort.sort(
443 SymbolAtIndex,
444 sorted_atom_syms.items,
445 context,
446 SymbolAtIndex.greaterThanBySeniority,
447 );
448
416 const atom_size = blk: {449 const atom_size = blk: {
417 const end_addr = if (next_sym_count < filtered_syms.len)450 const end_addr = if (next_sym_count < filtered_syms.len)
418 filtered_syms[next_sym_count].getSymbol(context).n_value451 filtered_syms[next_sym_count].getSymbol(context).n_value
...@@ -432,12 +465,12 @@ pub fn splitIntoAtomsOneShot(...@@ -432,12 +465,12 @@ pub fn splitIntoAtomsOneShot(
432 const atom = try self.createAtomFromSubsection(465 const atom = try self.createAtomFromSubsection(
433 macho_file,466 macho_file,
434 object_id,467 object_id,
435 sym_index,468 sorted_atom_syms.items[0].index,
436 atom_size,469 atom_size,
437 atom_align,470 atom_align,
438 atom_code,471 atom_code,
439 relocs,472 relocs,
440 atom_syms[1..],473 sorted_atom_syms.items[1..],
441 match,474 match,
442 sect,475 sect,
443 gc_roots,476 gc_roots,
...@@ -552,12 +585,7 @@ fn createAtomFromSubsection(...@@ -552,12 +585,7 @@ fn createAtomFromSubsection(
552 // the filtered symbols and note which symbol is contained within so that585 // the filtered symbols and note which symbol is contained within so that
553 // we can properly allocate addresses down the line.586 // we can properly allocate addresses down the line.
554 // While we're at it, we need to update segment,section mapping of each symbol too.587 // While we're at it, we need to update segment,section mapping of each symbol too.
555 try atom.contained.ensureTotalCapacity(gpa, indexes.len + 1);588 try atom.contained.ensureTotalCapacity(gpa, indexes.len);
556 atom.contained.appendAssumeCapacity(.{
557 .sym_index = sym_index,
558 .offset = 0,
559 });
560
561 for (indexes) |inner_sym_index| {589 for (indexes) |inner_sym_index| {
562 const inner_sym = &self.symtab.items[inner_sym_index.index];590 const inner_sym = &self.symtab.items[inner_sym_index.index];
563 inner_sym.n_sect = macho_file.getSectionOrdinal(match);591 inner_sym.n_sect = macho_file.getSectionOrdinal(match);