| ... | ... | @@ -42,8 +42,12 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 42 | 42 | const object = zld.objects.items[global.getFile().?]; |
| 43 | 43 | const atom_index = object.getAtomIndexForSymbol(global.sym_index).?; // panic here means fatal error |
| 44 | 44 | _ = try roots.getOrPut(atom_index); |
| 45 | | log.debug("adding root", .{}); |
| 46 | | zld.logAtom(atom_index, log); |
| 45 | |
| 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 | 52 | else => |other| { |
| 49 | 53 | assert(other == .Lib); |
| ... | ... | @@ -55,8 +59,12 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 55 | 59 | const object = zld.objects.items[global.getFile().?]; |
| 56 | 60 | const atom_index = object.getAtomIndexForSymbol(global.sym_index).?; // panic here means fatal error |
| 57 | 61 | _ = try roots.getOrPut(atom_index); |
| 58 | | log.debug("adding root", .{}); |
| 59 | | zld.logAtom(atom_index, log); |
| 62 | |
| 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 | 75 | const object = zld.objects.items[global.getFile().?]; |
| 68 | 76 | if (object.getAtomIndexForSymbol(global.sym_index)) |atom_index| { |
| 69 | 77 | _ = try roots.getOrPut(atom_index); |
| 70 | | log.debug("adding root", .{}); |
| 71 | | zld.logAtom(atom_index, log); |
| 78 | |
| 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 | 85 | break; |
| 74 | 86 | } |
| 75 | 87 | } |
| 76 | 88 | |
| 77 | 89 | for (zld.objects.items) |object| { |
| 78 | | for (object.atoms.items) |atom_index| { |
| 79 | | const atom = zld.getAtom(atom_index); |
| 90 | const has_subsections = object.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| 80 | 91 | |
| 81 | | const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym| |
| 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); |
| 92 | for (object.atoms.items) |atom_index| { |
| 89 | 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 | 107 | if (source_sect.isDontDeadStrip()) break :blk true; |
| 91 | | if (mem.eql(u8, "__StaticInit", source_sect.sectName())) break :blk true; |
| 92 | 108 | switch (source_sect.@"type"()) { |
| 93 | 109 | macho.S_MOD_INIT_FUNC_POINTERS, |
| 94 | 110 | macho.S_MOD_TERM_FUNC_POINTERS, |
| ... | ... | @@ -96,10 +112,15 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void { |
| 96 | 112 | else => break :blk false, |
| 97 | 113 | } |
| 98 | 114 | }; |
| 115 | |
| 99 | 116 | if (is_gc_root) { |
| 100 | 117 | try roots.putNoClobber(atom_index, {}); |
| 101 | | log.debug("adding root", .{}); |
| 102 | | zld.logAtom(atom_index, log); |
| 118 | |
| 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 | 132 | alive: *AtomTable, |
| 112 | 133 | reverse_lookups: [][]u32, |
| 113 | 134 | ) anyerror!void { |
| 114 | | log.debug("mark(ATOM({d}))", .{atom_index}); |
| 115 | | |
| 116 | 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 | 144 | const cpu_arch = zld.options.target.cpu.arch; |
| 123 | 145 | |
| 124 | | const atom = zld.getAtom(atom_index); |
| 125 | 146 | const sym = zld.getSymbol(atom.getSymbolWithLoc()); |
| 126 | 147 | const header = zld.sections.items(.header)[sym.n_sect - 1]; |
| 127 | 148 | if (header.isZerofill()) return; |
| ... | ... | @@ -130,37 +151,30 @@ fn markLive( |
| 130 | 151 | const reverse_lookup = reverse_lookups[atom.getFile().?]; |
| 131 | 152 | for (relocs) |rel| { |
| 132 | 153 | const target = switch (cpu_arch) { |
| 133 | | .aarch64 => blk: { |
| 134 | | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 135 | | switch (rel_type) { |
| 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 | | } |
| 154 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { |
| 155 | .ARM64_RELOC_ADDEND => continue, |
| 156 | else => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 159 | 157 | }, |
| 158 | .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 160 | 159 | else => unreachable, |
| 161 | 160 | }; |
| 162 | | |
| 163 | 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 | 178 | if (target_sym.undf()) continue; |
| 165 | 179 | if (target.getFile() == null) { |
| 166 | 180 | const target_sym_name = zld.getSymbolName(target); |
| ... | ... | @@ -172,51 +186,51 @@ fn markLive( |
| 172 | 186 | |
| 173 | 187 | const object = zld.objects.items[target.getFile().?]; |
| 174 | 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 | 195 | try markLive(zld, target_atom_index, alive, reverse_lookups); |
| 178 | 196 | } |
| 179 | 197 | } |
| 180 | 198 | |
| 181 | 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 | 205 | const cpu_arch = zld.options.target.cpu.arch; |
| 185 | 206 | |
| 186 | | const atom = zld.getAtom(atom_index); |
| 187 | | const sym = zld.getSymbol(atom.getSymbolWithLoc()); |
| 207 | const sym = zld.getSymbol(sym_loc); |
| 188 | 208 | const header = zld.sections.items(.header)[sym.n_sect - 1]; |
| 189 | | if (header.isZerofill()) return false; |
| 209 | assert(!header.isZerofill()); |
| 190 | 210 | |
| 191 | 211 | const relocs = Atom.getAtomRelocs(zld, atom_index); |
| 192 | 212 | const reverse_lookup = reverse_lookups[atom.getFile().?]; |
| 193 | 213 | for (relocs) |rel| { |
| 194 | | switch (cpu_arch) { |
| 195 | | .aarch64 => { |
| 196 | | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 197 | | switch (rel_type) { |
| 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 | | } |
| 214 | const target = switch (cpu_arch) { |
| 215 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { |
| 216 | .ARM64_RELOC_ADDEND => continue, |
| 217 | else => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 208 | 218 | }, |
| 219 | .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup), |
| 209 | 220 | else => unreachable, |
| 210 | | } |
| 221 | }; |
| 211 | 222 | |
| 212 | | const target = try Atom.parseRelocTarget(zld, atom_index, rel, reverse_lookup); |
| 213 | 223 | const object = zld.objects.items[target.getFile().?]; |
| 214 | 224 | const target_atom_index = object.getAtomIndexForSymbol(target.sym_index) orelse { |
| 215 | 225 | log.debug("atom for symbol '{s}' not found; skipping...", .{zld.getSymbolName(target)}); |
| 216 | 226 | continue; |
| 217 | 227 | }; |
| 218 | 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 | 234 | return true; |
| 221 | 235 | } |
| 222 | 236 | } |
| ... | ... | @@ -270,10 +284,16 @@ fn prune(zld: *Zld, alive: AtomTable) !void { |
| 270 | 284 | continue; |
| 271 | 285 | } |
| 272 | 286 | |
| 273 | | zld.logAtom(atom_index, log); |
| 274 | | |
| 275 | 287 | const atom = zld.getAtom(atom_index); |
| 276 | 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 | 297 | const sym = zld.getSymbolPtr(sym_loc); |
| 278 | 298 | const sect_id = sym.n_sect - 1; |
| 279 | 299 | var section = zld.sections.get(sect_id); |
| ... | ... | @@ -303,16 +323,17 @@ fn prune(zld: *Zld, alive: AtomTable) !void { |
| 303 | 323 | zld.sections.set(sect_id, section); |
| 304 | 324 | _ = object.atoms.swapRemove(i); |
| 305 | 325 | |
| 306 | | if (sym.ext()) { |
| 307 | | sym.n_desc = N_DEAD; |
| 308 | | } |
| 326 | sym.n_desc = N_DEAD; |
| 309 | 327 | |
| 310 | 328 | var inner_sym_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 311 | 329 | while (inner_sym_it.next()) |inner| { |
| 312 | 330 | const inner_sym = zld.getSymbolPtr(inner); |
| 313 | | if (inner_sym.ext()) { |
| 314 | | inner_sym.n_desc = N_DEAD; |
| 315 | | } |
| 331 | inner_sym.n_desc = N_DEAD; |
| 332 | } |
| 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 | } |