authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-11 18:42:35+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:39+01:00
log8a1311733b313a59afa2ea354ca9b342a935d869
treed4d8438c087a3bd4d19c6369214e8b7e9b06b7da
parentb8f67d79850b0be1f2384dca0a9a946bfa6a75a6

macho: resolve symbols and mark files live


3 files changed, 73 insertions(+), 14 deletions(-)

src/link/MachO.zig+70-12
...@@ -497,6 +497,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -497,6 +497,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
497 }497 }
498498
499 try self.addUndefinedGlobals();499 try self.addUndefinedGlobals();
500 try self.resolveSymbols();
500501
501 state_log.debug("{}", .{self.dumpState()});502 state_log.debug("{}", .{self.dumpState()});
502503
...@@ -1157,6 +1158,63 @@ fn addUndefinedGlobals(self: *MachO) !void {...@@ -1157,6 +1158,63 @@ fn addUndefinedGlobals(self: *MachO) !void {
1157 }1158 }
1158}1159}
11591160
1161/// When resolving symbols, we approach the problem similarly to `mold`.
1162/// 1. Resolve symbols across all objects (including those preemptively extracted archives).
1163/// 2. Resolve symbols across all shared objects.
1164/// 3. Mark live objects (see `MachO.markLive`)
1165/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.
1166/// 5. Remove references to dead objects/shared objects
1167/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1168pub fn resolveSymbols(self: *MachO) !void {
1169 const tracy = trace(@src());
1170 defer tracy.end();
1171
1172 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1173 for (self.objects.items) |index| self.getFile(index).?.resolveSymbols(self);
1174 for (self.dylibs.items) |index| self.getFile(index).?.resolveSymbols(self);
1175
1176 // Mark live objects.
1177 self.markLive();
1178
1179 // Reset state of all globals after marking live objects.
1180 for (self.objects.items) |index| self.getFile(index).?.resetGlobals(self);
1181 for (self.dylibs.items) |index| self.getFile(index).?.resetGlobals(self);
1182
1183 // Prune dead objects.
1184 var i: usize = 0;
1185 while (i < self.objects.items.len) {
1186 const index = self.objects.items[i];
1187 if (!self.getFile(index).?.object.alive) {
1188 _ = self.objects.orderedRemove(i);
1189 } else i += 1;
1190 }
1191
1192 // Re-resolve the symbols.
1193 for (self.objects.items) |index| self.getFile(index).?.resolveSymbols(self);
1194 for (self.dylibs.items) |index| self.getFile(index).?.resolveSymbols(self);
1195}
1196
1197fn markLive(self: *MachO) void {
1198 const tracy = trace(@src());
1199 defer tracy.end();
1200
1201 for (self.undefined_symbols.items) |index| {
1202 if (self.getSymbol(index).getFile(self)) |file| {
1203 if (file == .object) file.object.alive = true;
1204 }
1205 }
1206 if (self.entry_index) |index| {
1207 const sym = self.getSymbol(index);
1208 if (sym.getFile(self)) |file| {
1209 if (file == .object) file.object.alive = true;
1210 }
1211 }
1212 for (self.objects.items) |index| {
1213 const object = self.getFile(index).?.object;
1214 if (object.alive) object.markLive(self);
1215 }
1216}
1217
1160fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {1218fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
1161 _ = self;1219 _ = self;
1162 _ = atom_index;1220 _ = atom_index;
...@@ -1791,18 +1849,18 @@ fn fmtDumpState(...@@ -1791,18 +1849,18 @@ fn fmtDumpState(
1791 object.fmtSymtab(self),1849 object.fmtSymtab(self),
1792 });1850 });
1793 }1851 }
1794 // for (self.dylibs.items) |index| {1852 for (self.dylibs.items) |index| {
1795 // const dylib = self.getFile(index).?.dylib;1853 const dylib = self.getFile(index).?.dylib;
1796 // try writer.print("dylib({d}) : {s} : needed({}) : weak({})", .{1854 try writer.print("dylib({d}) : {s} : needed({}) : weak({})", .{
1797 // index,1855 index,
1798 // dylib.path,1856 dylib.path,
1799 // dylib.needed,1857 dylib.needed,
1800 // dylib.weak,1858 dylib.weak,
1801 // });1859 });
1802 // if (!dylib.isAlive(self)) try writer.writeAll(" : ([*])");1860 if (!dylib.isAlive(self)) try writer.writeAll(" : ([*])");
1803 // try writer.writeByte('\n');1861 try writer.writeByte('\n');
1804 // try writer.print("{}\n", .{dylib.fmtSymtab(self)});1862 try writer.print("{}\n", .{dylib.fmtSymtab(self)});
1805 // }1863 }
1806 if (self.getInternalObject()) |internal| {1864 if (self.getInternalObject()) |internal| {
1807 try writer.print("internal({d}) : internal\n", .{internal.index});1865 try writer.print("internal({d}) : internal\n", .{internal.index});
1808 try writer.print("{}{}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });1866 try writer.print("{}{}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });
src/link/MachO/Dylib.zig+1-1
...@@ -530,7 +530,7 @@ pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void {...@@ -530,7 +530,7 @@ pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void {
530}530}
531531
532pub fn isAlive(self: Dylib, macho_file: *MachO) bool {532pub fn isAlive(self: Dylib, macho_file: *MachO) bool {
533 if (!macho_file.options.dead_strip_dylibs) return self.explicit or self.referenced or self.needed;533 if (!macho_file.dead_strip_dylibs) return self.explicit or self.referenced or self.needed;
534 return self.referenced or self.needed;534 return self.referenced or self.needed;
535}535}
536536
src/link/MachO/Object.zig+2-1
...@@ -1021,7 +1021,8 @@ pub fn resolveSymbols(self: *Object, macho_file: *MachO) void {...@@ -1021,7 +1021,8 @@ pub fn resolveSymbols(self: *Object, macho_file: *MachO) void {
1021 symbol.flags.weak_ref = false;1021 symbol.flags.weak_ref = false;
1022 symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0;1022 symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0;
1023 symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();1023 symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();
1024 symbol.flags.interposable = macho_file.options.dylib and macho_file.options.namespace == .flat and !nlist.pext();1024 // TODO: symbol.flags.interposable = macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext();
1025 symbol.flags.interposable = false;
10251026
1026 if (nlist.sect() and1027 if (nlist.sect() and
1027 self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)1028 self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)