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 {
29402940
29412941 if (global.file) |file| {
29422942 const object = &self.objects.items[file];
2943
2944 try atom.contained.append(gpa, .{
2945 .sym_index = global.sym_index,
2946 .offset = 0,
2947 });
2948
29492943 try object.managed_atoms.append(gpa, atom);
29502944 try object.atom_by_index_table.putNoClobber(gpa, global.sym_index, atom);
29512945 } else {
......@@ -5594,6 +5588,7 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
55945588
55955589 const global = atom.getSymbolWithLoc();
55965590 const sym = atom.getSymbolPtr(self);
5591 const match = self.getMatchingSectionFromOrdinal(sym.n_sect);
55975592
55985593 if (sym.n_desc == N_DESC_GCED) continue;
55995594 if (!sym.ext()) {
......@@ -5605,15 +5600,6 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
56055600 } else continue;
56065601 }
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
56175603 self.logAtom(atom);
56185604 sym.n_desc = N_DESC_GCED;
56195605 self.removeAtomFromSection(atom, match);
......@@ -5644,6 +5630,8 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
56445630 const tlv_ptr_sym = tlv_ptr_atom.getSymbolPtr(self);
56455631 tlv_ptr_sym.n_desc = N_DESC_GCED;
56465632 }
5633
5634 loop = true;
56475635 }
56485636 }
56495637 }
......@@ -6831,7 +6819,6 @@ pub fn generateSymbolStabs(
68316819 };
68326820 const tu_name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name);
68336821 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir);
6834 const source_symtab = object.getSourceSymtab();
68356822
68366823 // Open scope
68376824 try locals.ensureUnusedCapacity(3);
......@@ -6857,71 +6844,27 @@ pub fn generateSymbolStabs(
68576844 .n_value = object.mtime,
68586845 });
68596846
6847 var stabs_buf: [4]macho.nlist_64 = undefined;
6848
68606849 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
68616857 for (atom.contained.items) |sym_at_off| {
68626858 const sym_loc = SymbolWithLoc{
68636859 .sym_index = sym_at_off.sym_index,
68646860 .file = atom.file,
68656861 };
6866 const sym = self.getSymbol(sym_loc);
6867 const sym_name = self.getSymbolName(sym_loc);
6868 if (sym.n_strx == 0) continue;
6869 if (sym.n_desc == N_DESC_GCED) continue;
6870 if (self.symbolIsTemp(sym_loc)) continue;
6871 if (sym_at_off.sym_index >= source_symtab.len) continue; // synthetic, linker generated
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 }
6862 const contained_stabs = try self.generateSymbolStabsForSymbol(
6863 sym_loc,
6864 debug_info,
6865 &stabs_buf,
6866 );
6867 try locals.appendSlice(contained_stabs);
69256868 }
69266869 }
69276870
......@@ -6935,6 +6878,78 @@ pub fn generateSymbolStabs(
69356878 });
69366879}
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
69386953fn snapshotState(self: *MachO) !void {
69396954 const emit = self.base.options.emit orelse {
69406955 log.debug("no emit directory found; skipping snapshot...", .{});
src/link/MachO/Object.zig+43-15
......@@ -197,11 +197,9 @@ const SymbolAtIndex = struct {
197197 return mem.sliceTo(@ptrCast([*:0]const u8, ctx.strtab.ptr + sym.n_strx), 0);
198198 }
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).
200202 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.
205203 const lhs = lhs_index.getSymbol(ctx);
206204 const rhs = rhs_index.getSymbol(ctx);
207205 if (lhs.sect()) {
......@@ -215,6 +213,29 @@ const SymbolAtIndex = struct {
215213 return false;
216214 }
217215 }
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 }
218239};
219240
220241fn filterSymbolsByAddress(
......@@ -295,6 +316,10 @@ pub fn splitIntoAtomsOneShot(
295316 sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) });
296317 }
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.
298323 sort.sort(SymbolAtIndex, sorted_all_syms.items, context, SymbolAtIndex.lessThan);
299324
300325 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
......@@ -409,10 +434,18 @@ pub fn splitIntoAtomsOneShot(
409434 );
410435 next_sym_count += atom_syms.len;
411436
437 // We want to bubble up the first externally defined symbol here.
412438 assert(atom_syms.len > 0);
413 const sym_index = for (atom_syms) |atom_sym| {
414 if (atom_sym.getSymbol(context).ext()) break atom_sym.index;
415 } else atom_syms[0].index;
439 var sorted_atom_syms = std.ArrayList(SymbolAtIndex).init(gpa);
440 defer sorted_atom_syms.deinit();
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
416449 const atom_size = blk: {
417450 const end_addr = if (next_sym_count < filtered_syms.len)
418451 filtered_syms[next_sym_count].getSymbol(context).n_value
......@@ -432,12 +465,12 @@ pub fn splitIntoAtomsOneShot(
432465 const atom = try self.createAtomFromSubsection(
433466 macho_file,
434467 object_id,
435 sym_index,
468 sorted_atom_syms.items[0].index,
436469 atom_size,
437470 atom_align,
438471 atom_code,
439472 relocs,
440 atom_syms[1..],
473 sorted_atom_syms.items[1..],
441474 match,
442475 sect,
443476 gc_roots,
......@@ -552,12 +585,7 @@ fn createAtomFromSubsection(
552585 // the filtered symbols and note which symbol is contained within so that
553586 // we can properly allocate addresses down the line.
554587 // 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);
556 atom.contained.appendAssumeCapacity(.{
557 .sym_index = sym_index,
558 .offset = 0,
559 });
560
588 try atom.contained.ensureTotalCapacity(gpa, indexes.len);
561589 for (indexes) |inner_sym_index| {
562590 const inner_sym = &self.symtab.items[inner_sym_index.index];
563591 inner_sym.n_sect = macho_file.getSectionOrdinal(match);