| ... | @@ -42,8 +42,12 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { | ... | @@ -42,8 +42,12 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 42 | const object = zld.objects.items[global.getFile().?]; | 42 | const object = zld.objects.items[global.getFile().?]; |
| 43 | const atom_index = object.getAtomIndexForSymbol(global.sym_index).?; // panic here means fatal error | 43 | const atom_index = object.getAtomIndexForSymbol(global.sym_index).?; // panic here means fatal error |
| 44 | _ = try roots.getOrPut(atom_index); | 44 | _ = try roots.getOrPut(atom_index); |
| 45 | log.debug("adding root", .{}); | 45 | |
| 46 | zld.logAtom(atom_index, log); | 46 | log.debug("root(ATOM({d}, %{d}, {d}))", .{ |
| | 47 | atom_index, |
| | 48 | zld.getAtom(atom_index).sym_index, |
| | 49 | zld.getAtom(atom_index).file, |
| | 50 | }); |
| 47 | }, | 51 | }, |
| 48 | else => |other| { | 52 | else => |other| { |
| 49 | assert(other == .Lib); | 53 | assert(other == .Lib); |
| ... | @@ -55,8 +59,12 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { | ... | @@ -55,8 +59,12 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 55 | const object = zld.objects.items[global.getFile().?]; | 59 | const object = zld.objects.items[global.getFile().?]; |
| 56 | const atom_index = object.getAtomIndexForSymbol(global.sym_index).?; // panic here means fatal error | 60 | const atom_index = object.getAtomIndexForSymbol(global.sym_index).?; // panic here means fatal error |
| 57 | _ = try roots.getOrPut(atom_index); | 61 | _ = try roots.getOrPut(atom_index); |
| 58 | log.debug("adding root", .{}); | 62 | |
| 59 | zld.logAtom(atom_index, log); | 63 | log.debug("root(ATOM({d}, %{d}, {d}))", .{ |
| | 64 | atom_index, |
| | 65 | zld.getAtom(atom_index).sym_index, |
| | 66 | zld.getAtom(atom_index).file, |
| | 67 | }); |
| 60 | } | 68 | } |
| 61 | }, | 69 | }, |
| 62 | } | 70 | } |
| ... | @@ -67,28 +75,36 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { | ... | @@ -67,28 +75,36 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 67 | const object = zld.objects.items[global.getFile().?]; | 75 | const object = zld.objects.items[global.getFile().?]; |
| 68 | if (object.getAtomIndexForSymbol(global.sym_index)) |atom_index| { | 76 | if (object.getAtomIndexForSymbol(global.sym_index)) |atom_index| { |
| 69 | _ = try roots.getOrPut(atom_index); | 77 | _ = try roots.getOrPut(atom_index); |
| 70 | log.debug("adding root", .{}); | 78 | |
| 71 | zld.logAtom(atom_index, log); | 79 | log.debug("root(ATOM({d}, %{d}, {d}))", .{ |
| | 80 | atom_index, |
| | 81 | zld.getAtom(atom_index).sym_index, |
| | 82 | zld.getAtom(atom_index).file, |
| | 83 | }); |
| 72 | } | 84 | } |
| 73 | break; | 85 | break; |
| 74 | } | 86 | } |
| 75 | } | 87 | } |
| 76 | | 88 | |
| 77 | for (zld.objects.items) |object| { | 89 | for (zld.objects.items) |object| { |
| 78 | for (object.atoms.items) |atom_index| { | 90 | const has_subsections = object.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| 79 | const atom = zld.getAtom(atom_index); | | |
| 80 | | 91 | |
| 81 | const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym| | 92 | for (object.atoms.items) |atom_index| { |
| 82 | source_sym.n_sect - 1 | | |
| 83 | else blk: { | | |
| 84 | const nbase = @intCast(u32, object.in_symtab.?.len); | | |
| 85 | const sect_id = @intCast(u16, atom.sym_index - nbase); | | |
| 86 | break :blk sect_id; | | |
| 87 | }; | | |
| 88 | const source_sect = object.getSourceSection(sect_id); | | |
| 89 | const is_gc_root = blk: { | 93 | const is_gc_root = blk: { |
| | 94 | // Modelled after ld64 which treats each object file compiled without MH_SUBSECTIONS_VIA_SYMBOLS |
| | 95 | // as a root. |
| | 96 | if (!has_subsections) break :blk true; |
| | 97 | |
| | 98 | const atom = zld.getAtom(atom_index); |
| | 99 | const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym| |
| | 100 | source_sym.n_sect - 1 |
| | 101 | else sect_id: { |
| | 102 | const nbase = @intCast(u32, object.in_symtab.?.len); |
| | 103 | const sect_id = @intCast(u16, atom.sym_index - nbase); |
| | 104 | break :sect_id sect_id; |
| | 105 | }; |
| | 106 | const source_sect = object.getSourceSection(sect_id); |
| 90 | if (source_sect.isDontDeadStrip()) break :blk true; | 107 | if (source_sect.isDontDeadStrip()) break :blk true; |
| 91 | if (mem.eql(u8, "__StaticInit", source_sect.sectName())) break :blk true; | | |
| 92 | switch (source_sect.@"type"()) { | 108 | switch (source_sect.@"type"()) { |
| 93 | macho.S_MOD_INIT_FUNC_POINTERS, | 109 | macho.S_MOD_INIT_FUNC_POINTERS, |
| 94 | macho.S_MOD_TERM_FUNC_POINTERS, | 110 | macho.S_MOD_TERM_FUNC_POINTERS, |
| ... | @@ -96,10 +112,15 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { | ... | @@ -96,10 +112,15 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 96 | else => break :blk false, | 112 | else => break :blk false, |
| 97 | } | 113 | } |
| 98 | }; | 114 | }; |
| | 115 | |
| 99 | if (is_gc_root) { | 116 | if (is_gc_root) { |
| 100 | try roots.putNoClobber(atom_index, {}); | 117 | try roots.putNoClobber(atom_index, {}); |
| 101 | log.debug("adding root", .{}); | 118 | |
| 102 | zld.logAtom(atom_index, log); | 119 | log.debug("root(ATOM({d}, %{d}, {d}))", .{ |
| | 120 | atom_index, |
| | 121 | zld.getAtom(atom_index).sym_index, |
| | 122 | zld.getAtom(atom_index).file, |
| | 123 | }); |
| 103 | } | 124 | } |
| 104 | } | 125 | } |
| 105 | } | 126 | } |
| ... | @@ -111,17 +132,17 @@ fn markLive( | ... | @@ -111,17 +132,17 @@ fn markLive( |
| 111 | alive: *AtomTable, | 132 | alive: *AtomTable, |
| 112 | reverse_lookups: [][]u32, | 133 | reverse_lookups: [][]u32, |
| 113 | ) anyerror!void { | 134 | ) anyerror!void { |
| 114 | log.debug("mark(ATOM({d}))", .{atom_index}); | | |
| 115 | | | |
| 116 | if (alive.contains(atom_index)) return; | 135 | if (alive.contains(atom_index)) return; |
| 117 | | 136 | |
| 118 | alive.putAssumeCapacityNoClobber(atom_index, {}); | 137 | const atom = zld.getAtom(atom_index); |
| | 138 | const sym_loc = atom.getSymbolWithLoc(); |
| | 139 | |
| | 140 | log.debug("mark(ATOM({d}, %{d}, {d}))", .{ atom_index, sym_loc.sym_index, sym_loc.file }); |
| 119 | | 141 | |
| 120 | zld.logAtom(atom_index, log); | 142 | alive.putAssumeCapacityNoClobber(atom_index, {}); |
| 121 | | 143 | |
| 122 | const cpu_arch = zld.options.target.cpu.arch; | 144 | const cpu_arch = zld.options.target.cpu.arch; |
| 123 | | 145 | |
| 124 | const atom = zld.getAtom(atom_index); | | |
| 125 | const sym = zld.getSymbol(atom.getSymbolWithLoc()); | 146 | const sym = zld.getSymbol(atom.getSymbolWithLoc()); |
| 126 | const header = zld.sections.items(.header)[sym.n_sect - 1]; | 147 | const header = zld.sections.items(.header)[sym.n_sect - 1]; |
| 127 | if (header.isZerofill()) return; | 148 | if (header.isZerofill()) return; |
| ... | @@ -130,37 +151,30 @@ fn markLive( | ... | @@ -130,37 +151,30 @@ fn markLive( |
| 130 | const reverse_lookup = reverse_lookups[atom.getFile().?]; | 151 | const reverse_lookup = reverse_lookups[atom.getFile().?]; |
| 131 | for (relocs) |rel| { | 152 | for (relocs) |rel| { |
| 132 | const target = switch (cpu_arch) { | 153 | const target = switch (cpu_arch) { |
| 133 | .aarch64 => blk: { | 154 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { |
| 134 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 155 | .ARM64_RELOC_ADDEND => continue, |
| 135 | switch (rel_type) { | 156 | else => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 136 | .ARM64_RELOC_ADDEND => continue, | | |
| 137 | .ARM64_RELOC_SUBTRACTOR => { | | |
| 138 | const sym_index = reverse_lookup[rel.r_symbolnum]; | | |
| 139 | break :blk SymbolWithLoc{ | | |
| 140 | .sym_index = sym_index, | | |
| 141 | .file = atom.file, | | |
| 142 | }; | | |
| 143 | }, | | |
| 144 | else => break :blk try Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), | | |
| 145 | } | | |
| 146 | }, | | |
| 147 | .x86_64 => blk: { | | |
| 148 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | | |
| 149 | switch (rel_type) { | | |
| 150 | .X86_64_RELOC_SUBTRACTOR => { | | |
| 151 | const sym_index = reverse_lookup[rel.r_symbolnum]; | | |
| 152 | break :blk SymbolWithLoc{ | | |
| 153 | .sym_index = sym_index, | | |
| 154 | .file = atom.file, | | |
| 155 | }; | | |
| 156 | }, | | |
| 157 | else => break :blk try Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), | | |
| 158 | } | | |
| 159 | }, | 157 | }, |
| | 158 | .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 160 | else => unreachable, | 159 | else => unreachable, |
| 161 | }; | 160 | }; |
| 162 | | | |
| 163 | const target_sym = zld.getSymbol(target); | 161 | const target_sym = zld.getSymbol(target); |
| | 162 | |
| | 163 | if (rel.r_extern == 0) { |
| | 164 | // We are pessimistic and mark all atoms within the target section as live. |
| | 165 | // TODO: this can be improved by marking only the relevant atoms. |
| | 166 | const sect_id = target_sym.n_sect; |
| | 167 | const object = zld.objects.items[target.getFile().?]; |
| | 168 | for (object.atoms.items) |other_atom_index| { |
| | 169 | const other_atom = zld.getAtom(other_atom_index); |
| | 170 | const other_sym = zld.getSymbol(other_atom.getSymbolWithLoc()); |
| | 171 | if (other_sym.n_sect == sect_id) { |
| | 172 | try markLive(zld, other_atom_index, alive, reverse_lookups); |
| | 173 | } |
| | 174 | } |
| | 175 | continue; |
| | 176 | } |
| | 177 | |
| 164 | if (target_sym.undf()) continue; | 178 | if (target_sym.undf()) continue; |
| 165 | if (target.getFile() == null) { | 179 | if (target.getFile() == null) { |
| 166 | const target_sym_name = zld.getSymbolName(target); | 180 | const target_sym_name = zld.getSymbolName(target); |
| ... | @@ -172,51 +186,51 @@ fn markLive( | ... | @@ -172,51 +186,51 @@ fn markLive( |
| 172 | | 186 | |
| 173 | const object = zld.objects.items[target.getFile().?]; | 187 | const object = zld.objects.items[target.getFile().?]; |
| 174 | const target_atom_index = object.getAtomIndexForSymbol(target.sym_index).?; | 188 | const target_atom_index = object.getAtomIndexForSymbol(target.sym_index).?; |
| 175 | log.debug(" following ATOM({d})", .{target_atom_index}); | 189 | log.debug(" following ATOM({d}, %{d}, {d})", .{ |
| | 190 | target_atom_index, |
| | 191 | zld.getAtom(target_atom_index).sym_index, |
| | 192 | zld.getAtom(target_atom_index).file, |
| | 193 | }); |
| 176 | | 194 | |
| 177 | try markLive(zld, target_atom_index, alive, reverse_lookups); | 195 | try markLive(zld, target_atom_index, alive, reverse_lookups); |
| 178 | } | 196 | } |
| 179 | } | 197 | } |
| 180 | | 198 | |
| 181 | fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable, reverse_lookups: [][]u32) !bool { | 199 | fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable, reverse_lookups: [][]u32) !bool { |
| 182 | log.debug("refersLive(ATOM({d}))", .{atom_index}); | 200 | const atom = zld.getAtom(atom_index); |
| | 201 | const sym_loc = atom.getSymbolWithLoc(); |
| | 202 | |
| | 203 | log.debug("refersLive(ATOM({d}, %{d}, {d}))", .{ atom_index, sym_loc.sym_index, sym_loc.file }); |
| 183 | | 204 | |
| 184 | const cpu_arch = zld.options.target.cpu.arch; | 205 | const cpu_arch = zld.options.target.cpu.arch; |
| 185 | | 206 | |
| 186 | const atom = zld.getAtom(atom_index); | 207 | const sym = zld.getSymbol(sym_loc); |
| 187 | const sym = zld.getSymbol(atom.getSymbolWithLoc()); | | |
| 188 | const header = zld.sections.items(.header)[sym.n_sect - 1]; | 208 | const header = zld.sections.items(.header)[sym.n_sect - 1]; |
| 189 | if (header.isZerofill()) return false; | 209 | assert(!header.isZerofill()); |
| 190 | | 210 | |
| 191 | const relocs = Atom.getAtomRelocs(zld, atom_index); | 211 | const relocs = Atom.getAtomRelocs(zld, atom_index); |
| 192 | const reverse_lookup = reverse_lookups[atom.getFile().?]; | 212 | const reverse_lookup = reverse_lookups[atom.getFile().?]; |
| 193 | for (relocs) |rel| { | 213 | for (relocs) |rel| { |
| 194 | switch (cpu_arch) { | 214 | const target = switch (cpu_arch) { |
| 195 | .aarch64 => { | 215 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { |
| 196 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 216 | .ARM64_RELOC_ADDEND => continue, |
| 197 | switch (rel_type) { | 217 | else => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 198 | .ARM64_RELOC_ADDEND, .ARM64_RELOC_SUBTRACTOR => continue, | | |
| 199 | else => {}, | | |
| 200 | } | | |
| 201 | }, | | |
| 202 | .x86_64 => { | | |
| 203 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | | |
| 204 | switch (rel_type) { | | |
| 205 | .X86_64_RELOC_SUBTRACTOR => continue, | | |
| 206 | else => {}, | | |
| 207 | } | | |
| 208 | }, | 218 | }, |
| | 219 | .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 209 | else => unreachable, | 220 | else => unreachable, |
| 210 | } | 221 | }; |
| 211 | | 222 | |
| 212 | const target = try Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup); | | |
| 213 | const object = zld.objects.items[target.getFile().?]; | 223 | const object = zld.objects.items[target.getFile().?]; |
| 214 | const target_atom_index = object.getAtomIndexForSymbol(target.sym_index) orelse { | 224 | const target_atom_index = object.getAtomIndexForSymbol(target.sym_index) orelse { |
| 215 | log.debug("atom for symbol '{s}' not found; skipping...", .{zld.getSymbolName(target)}); | 225 | log.debug("atom for symbol '{s}' not found; skipping...", .{zld.getSymbolName(target)}); |
| 216 | continue; | 226 | continue; |
| 217 | }; | 227 | }; |
| 218 | if (alive.contains(target_atom_index)) { | 228 | if (alive.contains(target_atom_index)) { |
| 219 | log.debug(" refers live ATOM({d})", .{target_atom_index}); | 229 | log.debug(" refers live ATOM({d}, %{d}, {d})", .{ |
| | 230 | target_atom_index, |
| | 231 | zld.getAtom(target_atom_index).sym_index, |
| | 232 | zld.getAtom(target_atom_index).file, |
| | 233 | }); |
| 220 | return true; | 234 | return true; |
| 221 | } | 235 | } |
| 222 | } | 236 | } |
| ... | @@ -270,10 +284,16 @@ fn prune(zld: *Zld, alive: AtomTable) !void { | ... | @@ -270,10 +284,16 @@ fn prune(zld: *Zld, alive: AtomTable) !void { |
| 270 | continue; | 284 | continue; |
| 271 | } | 285 | } |
| 272 | | 286 | |
| 273 | zld.logAtom(atom_index, log); | | |
| 274 | | | |
| 275 | const atom = zld.getAtom(atom_index); | 287 | const atom = zld.getAtom(atom_index); |
| 276 | const sym_loc = atom.getSymbolWithLoc(); | 288 | const sym_loc = atom.getSymbolWithLoc(); |
| | 289 | |
| | 290 | log.debug("prune(ATOM({d}, %{d}, {d}))", .{ |
| | 291 | atom_index, |
| | 292 | sym_loc.sym_index, |
| | 293 | sym_loc.file, |
| | 294 | }); |
| | 295 | log.debug(" {s} in {s}", .{ zld.getSymbolName(sym_loc), object.name }); |
| | 296 | |
| 277 | const sym = zld.getSymbolPtr(sym_loc); | 297 | const sym = zld.getSymbolPtr(sym_loc); |
| 278 | const sect_id = sym.n_sect - 1; | 298 | const sect_id = sym.n_sect - 1; |
| 279 | var section = zld.sections.get(sect_id); | 299 | var section = zld.sections.get(sect_id); |
| ... | @@ -303,16 +323,17 @@ fn prune(zld: *Zld, alive: AtomTable) !void { | ... | @@ -303,16 +323,17 @@ fn prune(zld: *Zld, alive: AtomTable) !void { |
| 303 | zld.sections.set(sect_id, section); | 323 | zld.sections.set(sect_id, section); |
| 304 | _ = object.atoms.swapRemove(i); | 324 | _ = object.atoms.swapRemove(i); |
| 305 | | 325 | |
| 306 | if (sym.ext()) { | 326 | sym.n_desc = N_DEAD; |
| 307 | sym.n_desc = N_DEAD; | | |
| 308 | } | | |
| 309 | | 327 | |
| 310 | var inner_sym_it = Atom.getInnerSymbolsIterator(zld, atom_index); | 328 | var inner_sym_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 311 | while (inner_sym_it.next()) |inner| { | 329 | while (inner_sym_it.next()) |inner| { |
| 312 | const inner_sym = zld.getSymbolPtr(inner); | 330 | const inner_sym = zld.getSymbolPtr(inner); |
| 313 | if (inner_sym.ext()) { | 331 | inner_sym.n_desc = N_DEAD; |
| 314 | inner_sym.n_desc = N_DEAD; | 332 | } |
| 315 | } | 333 | |
| | 334 | if (Atom.getSectionAlias(zld, atom_index)) |alias| { |
| | 335 | const alias_sym = zld.getSymbolPtr(alias); |
| | 336 | alias_sym.n_desc = N_DEAD; |
| 316 | } | 337 | } |
| 317 | } | 338 | } |
| 318 | } | 339 | } |