| author | |
| committer | |
| log | d6e095de2c7b2c625a09e50b11e546191dc6e7bd |
| tree | a7280d808b153741d04b4d84d8ca5420c53b2799 |
| parent | 4d7dd1689fb1e7344fa9e4ca80394369569d0379 |
This solves the nuance case of compiling hand-crafted assembly files
which do not feature `MH_SUBSECTIONS_VIA_SYMBOLS` flag resulting in
input `Atom`s encompassing multiple symbols each with unique unwind
information.6 files changed, 403 insertions(+), 332 deletions(-)
src/link/MachO/Object.zig+23-19| ... | @@ -75,11 +75,11 @@ exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{}, | ... | @@ -75,11 +75,11 @@ exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{}, |
| 75 | 75 | ||
| 76 | eh_frame_sect_id: ?u8 = null, | 76 | eh_frame_sect_id: ?u8 = null, |
| 77 | eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{}, | 77 | eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{}, |
| 78 | eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(AtomIndex, u32) = .{}, | 78 | eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 79 | 79 | ||
| 80 | unwind_info_sect_id: ?u8 = null, | 80 | unwind_info_sect_id: ?u8 = null, |
| 81 | unwind_relocs_lookup: []Record = undefined, | 81 | unwind_relocs_lookup: []Record = undefined, |
| 82 | unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{}, | 82 | unwind_records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 83 | 83 | ||
| 84 | const Entry = struct { | 84 | const Entry = struct { |
| 85 | start: u32 = 0, | 85 | start: u32 = 0, |
| ... | @@ -274,11 +274,11 @@ const SymbolAtIndex = struct { | ... | @@ -274,11 +274,11 @@ const SymbolAtIndex = struct { |
| 274 | const sym = self.getSymbol(ctx); | 274 | const sym = self.getSymbol(ctx); |
| 275 | if (!sym.ext()) { | 275 | if (!sym.ext()) { |
| 276 | const sym_name = self.getSymbolName(ctx); | 276 | const sym_name = self.getSymbolName(ctx); |
| 277 | if (mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L")) return 0; | 277 | if (mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L")) return 3; |
| 278 | return 1; | 278 | return 2; |
| 279 | } | 279 | } |
| 280 | if (sym.weakDef() or sym.pext()) return 2; | 280 | if (sym.weakDef() or sym.pext()) return 1; |
| 281 | return 3; | 281 | return 0; |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | /// Performs lexicographic-like check. | 284 | /// Performs lexicographic-like check. |
| ... | @@ -423,8 +423,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -423,8 +423,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { |
| 423 | zld, | 423 | zld, |
| 424 | object_id, | 424 | object_id, |
| 425 | sym_index, | 425 | sym_index, |
| 426 | 0, | 426 | sym_index, |
| 427 | 0, | 427 | 1, |
| 428 | sect.size, | 428 | sect.size, |
| 429 | sect.@"align", | 429 | sect.@"align", |
| 430 | out_sect_id, | 430 | out_sect_id, |
| ... | @@ -502,8 +502,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -502,8 +502,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { |
| 502 | zld, | 502 | zld, |
| 503 | object_id, | 503 | object_id, |
| 504 | sym_index, | 504 | sym_index, |
| 505 | 0, | 505 | sym_index, |
| 506 | 0, | 506 | 1, |
| 507 | atom_size, | 507 | atom_size, |
| 508 | sect.@"align", | 508 | sect.@"align", |
| 509 | out_sect_id, | 509 | out_sect_id, |
| ... | @@ -521,7 +521,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -521,7 +521,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { |
| 521 | const atom_loc = filterSymbolsByAddress(symtab[next_sym_index..], addr, addr + 1); | 521 | const atom_loc = filterSymbolsByAddress(symtab[next_sym_index..], addr, addr + 1); |
| 522 | assert(atom_loc.len > 0); | 522 | assert(atom_loc.len > 0); |
| 523 | const atom_sym_index = atom_loc.index + next_sym_index; | 523 | const atom_sym_index = atom_loc.index + next_sym_index; |
| 524 | const nsyms_trailing = atom_loc.len - 1; | 524 | const nsyms_trailing = atom_loc.len; |
| 525 | next_sym_index += atom_loc.len; | 525 | next_sym_index += atom_loc.len; |
| 526 | 526 | ||
| 527 | const atom_size = if (next_sym_index < sect_start_index + sect_loc.len) | 527 | const atom_size = if (next_sym_index < sect_start_index + sect_loc.len) |
| ... | @@ -538,7 +538,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -538,7 +538,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void { |
| 538 | zld, | 538 | zld, |
| 539 | object_id, | 539 | object_id, |
| 540 | atom_sym_index, | 540 | atom_sym_index, |
| 541 | atom_sym_index + 1, | 541 | atom_sym_index, |
| 542 | nsyms_trailing, | 542 | nsyms_trailing, |
| 543 | atom_size, | 543 | atom_size, |
| 544 | atom_align, | 544 | atom_align, |
| ... | @@ -772,8 +772,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -772,8 +772,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void { |
| 772 | if (target.getFile() != object_id) { | 772 | if (target.getFile() != object_id) { |
| 773 | self.eh_frame_relocs_lookup.getPtr(offset).?.dead = true; | 773 | self.eh_frame_relocs_lookup.getPtr(offset).?.dead = true; |
| 774 | } else { | 774 | } else { |
| 775 | const atom_index = self.getAtomIndexForSymbol(target.sym_index).?; | 775 | self.eh_frame_records_lookup.putAssumeCapacityNoClobber(target, offset); |
| 776 | self.eh_frame_records_lookup.putAssumeCapacityNoClobber(atom_index, offset); | ||
| 777 | } | 776 | } |
| 778 | } | 777 | } |
| 779 | } | 778 | } |
| ... | @@ -802,10 +801,10 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -802,10 +801,10 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { |
| 802 | _ = try zld.initSection("__TEXT", "__unwind_info", .{}); | 801 | _ = try zld.initSection("__TEXT", "__unwind_info", .{}); |
| 803 | } | 802 | } |
| 804 | 803 | ||
| 805 | try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(self.exec_atoms.items.len))); | ||
| 806 | |||
| 807 | const unwind_records = self.getUnwindRecords(); | 804 | const unwind_records = self.getUnwindRecords(); |
| 808 | 805 | ||
| 806 | try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(unwind_records.len))); | ||
| 807 | |||
| 809 | const needs_eh_frame = for (unwind_records) |record| { | 808 | const needs_eh_frame = for (unwind_records) |record| { |
| 810 | if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true; | 809 | if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true; |
| 811 | } else false; | 810 | } else false; |
| ... | @@ -844,8 +843,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { | ... | @@ -844,8 +843,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { |
| 844 | if (target.getFile() != object_id) { | 843 | if (target.getFile() != object_id) { |
| 845 | self.unwind_relocs_lookup[record_id].dead = true; | 844 | self.unwind_relocs_lookup[record_id].dead = true; |
| 846 | } else { | 845 | } else { |
| 847 | const atom_index = self.getAtomIndexForSymbol(target.sym_index).?; | 846 | self.unwind_records_lookup.putAssumeCapacityNoClobber(target, @as(u32, @intCast(record_id))); |
| 848 | self.unwind_records_lookup.putAssumeCapacityNoClobber(atom_index, @as(u32, @intCast(record_id))); | ||
| 849 | } | 847 | } |
| 850 | } | 848 | } |
| 851 | } | 849 | } |
| ... | @@ -1012,7 +1010,13 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 { | ... | @@ -1012,7 +1010,13 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 { |
| 1012 | Predicate{ .addr = @as(i64, @intCast(addr)) }, | 1010 | Predicate{ .addr = @as(i64, @intCast(addr)) }, |
| 1013 | ); | 1011 | ); |
| 1014 | if (target_sym_index > 0) { | 1012 | if (target_sym_index > 0) { |
| 1015 | return @as(u32, @intCast(lookup.start + target_sym_index - 1)); | 1013 | // Hone in on the most senior alias of the target symbol. |
| 1014 | // See SymbolAtIndex.lessThan for more context. | ||
| 1015 | var start = target_sym_index - 1; | ||
| 1016 | while (start > 0 and | ||
| 1017 | self.source_address_lookup[lookup.start..][start - 1] == addr) : (start -= 1) | ||
| 1018 | {} | ||
| 1019 | return @as(u32, @intCast(lookup.start + start)); | ||
| 1016 | } | 1020 | } |
| 1017 | } | 1021 | } |
| 1018 | return self.getSectionAliasSymbolIndex(sect_id); | 1022 | return self.getSectionAliasSymbolIndex(sect_id); |
src/link/MachO/UnwindInfo.zig+109-89| ... | @@ -26,7 +26,7 @@ gpa: Allocator, | ... | @@ -26,7 +26,7 @@ gpa: Allocator, |
| 26 | /// List of all unwind records gathered from all objects and sorted | 26 | /// List of all unwind records gathered from all objects and sorted |
| 27 | /// by source function address. | 27 | /// by source function address. |
| 28 | records: std.ArrayListUnmanaged(macho.compact_unwind_entry) = .{}, | 28 | records: std.ArrayListUnmanaged(macho.compact_unwind_entry) = .{}, |
| 29 | records_lookup: std.AutoHashMapUnmanaged(AtomIndex, RecordIndex) = .{}, | 29 | records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, RecordIndex) = .{}, |
| 30 | 30 | ||
| 31 | /// List of all personalities referenced by either unwind info entries | 31 | /// List of all personalities referenced by either unwind info entries |
| 32 | /// or __eh_frame entries. | 32 | /// or __eh_frame entries. |
| ... | @@ -211,23 +211,22 @@ pub fn scanRelocs(zld: *Zld) !void { | ... | @@ -211,23 +211,22 @@ pub fn scanRelocs(zld: *Zld) !void { |
| 211 | for (zld.objects.items, 0..) |*object, object_id| { | 211 | for (zld.objects.items, 0..) |*object, object_id| { |
| 212 | const unwind_records = object.getUnwindRecords(); | 212 | const unwind_records = object.getUnwindRecords(); |
| 213 | for (object.exec_atoms.items) |atom_index| { | 213 | for (object.exec_atoms.items) |atom_index| { |
| 214 | const record_id = object.unwind_records_lookup.get(atom_index) orelse continue; | 214 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 215 | if (object.unwind_relocs_lookup[record_id].dead) continue; | 215 | while (inner_syms_it.next()) |sym| { |
| 216 | const record = unwind_records[record_id]; | 216 | const record_id = object.unwind_records_lookup.get(sym) orelse continue; |
| 217 | if (!UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) { | 217 | if (object.unwind_relocs_lookup[record_id].dead) continue; |
| 218 | if (getPersonalityFunctionReloc( | 218 | const record = unwind_records[record_id]; |
| 219 | zld, | 219 | if (!UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) { |
| 220 | @as(u32, @intCast(object_id)), | 220 | if (getPersonalityFunctionReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| { |
| 221 | record_id, | 221 | // Personality function; add GOT pointer. |
| 222 | )) |rel| { | 222 | const target = Atom.parseRelocTarget(zld, .{ |
| 223 | // Personality function; add GOT pointer. | 223 | .object_id = @as(u32, @intCast(object_id)), |
| 224 | const target = Atom.parseRelocTarget(zld, .{ | 224 | .rel = rel, |
| 225 | .object_id = @as(u32, @intCast(object_id)), | 225 | .code = mem.asBytes(&record), |
| 226 | .rel = rel, | 226 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), |
| 227 | .code = mem.asBytes(&record), | 227 | }); |
| 228 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | 228 | try Atom.addGotEntry(zld, target); |
| 229 | }); | 229 | } |
| 230 | try Atom.addGotEntry(zld, target); | ||
| 231 | } | 230 | } |
| 232 | } | 231 | } |
| 233 | } | 232 | } |
| ... | @@ -242,8 +241,8 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { | ... | @@ -242,8 +241,8 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { |
| 242 | var records = std.ArrayList(macho.compact_unwind_entry).init(info.gpa); | 241 | var records = std.ArrayList(macho.compact_unwind_entry).init(info.gpa); |
| 243 | defer records.deinit(); | 242 | defer records.deinit(); |
| 244 | 243 | ||
| 245 | var atom_indexes = std.ArrayList(AtomIndex).init(info.gpa); | 244 | var sym_indexes = std.ArrayList(SymbolWithLoc).init(info.gpa); |
| 246 | defer atom_indexes.deinit(); | 245 | defer sym_indexes.deinit(); |
| 247 | 246 | ||
| 248 | // TODO handle dead stripping | 247 | // TODO handle dead stripping |
| 249 | for (zld.objects.items, 0..) |*object, object_id| { | 248 | for (zld.objects.items, 0..) |*object, object_id| { |
| ... | @@ -253,80 +252,101 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { | ... | @@ -253,80 +252,101 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { |
| 253 | // Contents of unwind records does not have to cover all symbol in executable section | 252 | // Contents of unwind records does not have to cover all symbol in executable section |
| 254 | // so we need insert them ourselves. | 253 | // so we need insert them ourselves. |
| 255 | try records.ensureUnusedCapacity(object.exec_atoms.items.len); | 254 | try records.ensureUnusedCapacity(object.exec_atoms.items.len); |
| 256 | try atom_indexes.ensureUnusedCapacity(object.exec_atoms.items.len); | 255 | try sym_indexes.ensureUnusedCapacity(object.exec_atoms.items.len); |
| 257 | 256 | ||
| 258 | for (object.exec_atoms.items) |atom_index| { | 257 | for (object.exec_atoms.items) |atom_index| { |
| 259 | var record = if (object.unwind_records_lookup.get(atom_index)) |record_id| blk: { | 258 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 260 | if (object.unwind_relocs_lookup[record_id].dead) continue; | 259 | var prev_symbol: ?SymbolWithLoc = null; |
| 261 | var record = unwind_records[record_id]; | 260 | while (inner_syms_it.next()) |symbol| { |
| 261 | var record = if (object.unwind_records_lookup.get(symbol)) |record_id| blk: { | ||
| 262 | if (object.unwind_relocs_lookup[record_id].dead) continue; | ||
| 263 | var record = unwind_records[record_id]; | ||
| 264 | |||
| 265 | if (UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) { | ||
| 266 | try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), symbol, &record); | ||
| 267 | } else { | ||
| 268 | if (getPersonalityFunctionReloc( | ||
| 269 | zld, | ||
| 270 | @as(u32, @intCast(object_id)), | ||
| 271 | record_id, | ||
| 272 | )) |rel| { | ||
| 273 | const target = Atom.parseRelocTarget(zld, .{ | ||
| 274 | .object_id = @as(u32, @intCast(object_id)), | ||
| 275 | .rel = rel, | ||
| 276 | .code = mem.asBytes(&record), | ||
| 277 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | ||
| 278 | }); | ||
| 279 | const personality_index = info.getPersonalityFunction(target) orelse inner: { | ||
| 280 | const personality_index = info.personalities_count; | ||
| 281 | info.personalities[personality_index] = target; | ||
| 282 | info.personalities_count += 1; | ||
| 283 | break :inner personality_index; | ||
| 284 | }; | ||
| 285 | |||
| 286 | record.personalityFunction = personality_index + 1; | ||
| 287 | UnwindEncoding.setPersonalityIndex(&record.compactUnwindEncoding, personality_index + 1); | ||
| 288 | } | ||
| 262 | 289 | ||
| 263 | if (UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) { | 290 | if (getLsdaReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| { |
| 264 | try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), atom_index, &record); | 291 | const target = Atom.parseRelocTarget(zld, .{ |
| 265 | } else { | 292 | .object_id = @as(u32, @intCast(object_id)), |
| 266 | if (getPersonalityFunctionReloc( | 293 | .rel = rel, |
| 267 | zld, | 294 | .code = mem.asBytes(&record), |
| 268 | @as(u32, @intCast(object_id)), | 295 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), |
| 269 | record_id, | 296 | }); |
| 270 | )) |rel| { | 297 | record.lsda = @as(u64, @bitCast(target)); |
| 271 | const target = Atom.parseRelocTarget(zld, .{ | 298 | } |
| 272 | .object_id = @as(u32, @intCast(object_id)), | ||
| 273 | .rel = rel, | ||
| 274 | .code = mem.asBytes(&record), | ||
| 275 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | ||
| 276 | }); | ||
| 277 | const personality_index = info.getPersonalityFunction(target) orelse inner: { | ||
| 278 | const personality_index = info.personalities_count; | ||
| 279 | info.personalities[personality_index] = target; | ||
| 280 | info.personalities_count += 1; | ||
| 281 | break :inner personality_index; | ||
| 282 | }; | ||
| 283 | |||
| 284 | record.personalityFunction = personality_index + 1; | ||
| 285 | UnwindEncoding.setPersonalityIndex(&record.compactUnwindEncoding, personality_index + 1); | ||
| 286 | } | 299 | } |
| 287 | 300 | break :blk record; | |
| 288 | if (getLsdaReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| { | 301 | } else blk: { |
| 289 | const target = Atom.parseRelocTarget(zld, .{ | 302 | const sym = zld.getSymbol(symbol); |
| 290 | .object_id = @as(u32, @intCast(object_id)), | 303 | if (sym.n_desc == N_DEAD) continue; |
| 291 | .rel = rel, | 304 | if (prev_symbol) |prev_sym| { |
| 292 | .code = mem.asBytes(&record), | 305 | const prev_addr = object.getSourceSymbol(prev_sym.sym_index).?.n_value; |
| 293 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | 306 | const curr_addr = object.getSourceSymbol(symbol.sym_index).?.n_value; |
| 294 | }); | 307 | if (prev_addr == curr_addr) continue; |
| 295 | record.lsda = @as(u64, @bitCast(target)); | ||
| 296 | } | 308 | } |
| 297 | } | 309 | |
| 298 | break :blk record; | 310 | if (!object.hasUnwindRecords()) { |
| 299 | } else blk: { | 311 | if (object.eh_frame_records_lookup.get(symbol)) |fde_offset| { |
| 300 | const atom = zld.getAtom(atom_index); | 312 | if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue; |
| 301 | const sym = zld.getSymbol(atom.getSymbolWithLoc()); | 313 | var record = nullRecord(); |
| 302 | if (sym.n_desc == N_DEAD) continue; | 314 | try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), symbol, &record); |
| 303 | 315 | switch (cpu_arch) { | |
| 304 | if (!object.hasUnwindRecords()) { | 316 | .aarch64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_ARM64_MODE.DWARF), |
| 305 | if (object.eh_frame_records_lookup.get(atom_index)) |fde_offset| { | 317 | .x86_64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_X86_64_MODE.DWARF), |
| 306 | if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue; | 318 | else => unreachable, |
| 307 | var record = nullRecord(); | 319 | } |
| 308 | try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), atom_index, &record); | 320 | break :blk record; |
| 309 | switch (cpu_arch) { | ||
| 310 | .aarch64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_ARM64_MODE.DWARF), | ||
| 311 | .x86_64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_X86_64_MODE.DWARF), | ||
| 312 | else => unreachable, | ||
| 313 | } | 321 | } |
| 314 | break :blk record; | ||
| 315 | } | 322 | } |
| 316 | } | ||
| 317 | |||
| 318 | break :blk nullRecord(); | ||
| 319 | }; | ||
| 320 | 323 | ||
| 321 | const atom = zld.getAtom(atom_index); | 324 | break :blk nullRecord(); |
| 322 | const sym_loc = atom.getSymbolWithLoc(); | 325 | }; |
| 323 | const sym = zld.getSymbol(sym_loc); | ||
| 324 | assert(sym.n_desc != N_DEAD); | ||
| 325 | record.rangeStart = sym.n_value; | ||
| 326 | record.rangeLength = @as(u32, @intCast(atom.size)); | ||
| 327 | 326 | ||
| 328 | records.appendAssumeCapacity(record); | 327 | const atom = zld.getAtom(atom_index); |
| 329 | atom_indexes.appendAssumeCapacity(atom_index); | 328 | const sym = zld.getSymbol(symbol); |
| 329 | assert(sym.n_desc != N_DEAD); | ||
| 330 | const size = if (inner_syms_it.next()) |next_sym| blk: { | ||
| 331 | // All this trouble to account for symbol aliases. | ||
| 332 | // TODO I think that remodelling the linker so that a Symbol references an Atom | ||
| 333 | // is the way to go, kinda like we do for ELF. We might also want to perhaps tag | ||
| 334 | // symbol aliases somehow so that they are excluded from everything except relocation | ||
| 335 | // resolution. | ||
| 336 | defer inner_syms_it.pos -= 1; | ||
| 337 | const curr_addr = object.getSourceSymbol(symbol.sym_index).?.n_value; | ||
| 338 | const next_addr = object.getSourceSymbol(next_sym.sym_index).?.n_value; | ||
| 339 | if (next_addr > curr_addr) break :blk next_addr - curr_addr; | ||
| 340 | break :blk zld.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value; | ||
| 341 | } else zld.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value; | ||
| 342 | record.rangeStart = sym.n_value; | ||
| 343 | record.rangeLength = @as(u32, @intCast(size)); | ||
| 344 | |||
| 345 | try records.append(record); | ||
| 346 | try sym_indexes.append(symbol); | ||
| 347 | |||
| 348 | prev_symbol = symbol; | ||
| 349 | } | ||
| 330 | } | 350 | } |
| 331 | } | 351 | } |
| 332 | 352 | ||
| ... | @@ -339,7 +359,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { | ... | @@ -339,7 +359,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { |
| 339 | 359 | ||
| 340 | // Fold records | 360 | // Fold records |
| 341 | try info.records.ensureTotalCapacity(info.gpa, records.items.len); | 361 | try info.records.ensureTotalCapacity(info.gpa, records.items.len); |
| 342 | try info.records_lookup.ensureTotalCapacity(info.gpa, @as(u32, @intCast(atom_indexes.items.len))); | 362 | try info.records_lookup.ensureTotalCapacity(info.gpa, @as(u32, @intCast(sym_indexes.items.len))); |
| 343 | 363 | ||
| 344 | var maybe_prev: ?macho.compact_unwind_entry = null; | 364 | var maybe_prev: ?macho.compact_unwind_entry = null; |
| 345 | for (records.items, 0..) |record, i| { | 365 | for (records.items, 0..) |record, i| { |
| ... | @@ -365,7 +385,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { | ... | @@ -365,7 +385,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void { |
| 365 | break :blk record_id; | 385 | break :blk record_id; |
| 366 | } | 386 | } |
| 367 | }; | 387 | }; |
| 368 | info.records_lookup.putAssumeCapacityNoClobber(atom_indexes.items[i], record_id); | 388 | info.records_lookup.putAssumeCapacityNoClobber(sym_indexes.items[i], record_id); |
| 369 | } | 389 | } |
| 370 | 390 | ||
| 371 | // Calculate common encodings | 391 | // Calculate common encodings |
| ... | @@ -501,12 +521,12 @@ fn collectPersonalityFromDwarf( | ... | @@ -501,12 +521,12 @@ fn collectPersonalityFromDwarf( |
| 501 | info: *UnwindInfo, | 521 | info: *UnwindInfo, |
| 502 | zld: *Zld, | 522 | zld: *Zld, |
| 503 | object_id: u32, | 523 | object_id: u32, |
| 504 | atom_index: u32, | 524 | sym_loc: SymbolWithLoc, |
| 505 | record: *macho.compact_unwind_entry, | 525 | record: *macho.compact_unwind_entry, |
| 506 | ) !void { | 526 | ) !void { |
| 507 | const object = &zld.objects.items[object_id]; | 527 | const object = &zld.objects.items[object_id]; |
| 508 | var it = object.getEhFrameRecordsIterator(); | 528 | var it = object.getEhFrameRecordsIterator(); |
| 509 | const fde_offset = object.eh_frame_records_lookup.get(atom_index).?; | 529 | const fde_offset = object.eh_frame_records_lookup.get(sym_loc).?; |
| 510 | it.seekTo(fde_offset); | 530 | it.seekTo(fde_offset); |
| 511 | const fde = (try it.next()).?; | 531 | const fde = (try it.next()).?; |
| 512 | const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset); | 532 | const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset); |
src/link/MachO/ZldAtom.zig+7-11| ... | @@ -84,14 +84,14 @@ pub inline fn getSymbolWithLoc(self: Atom) SymbolWithLoc { | ... | @@ -84,14 +84,14 @@ pub inline fn getSymbolWithLoc(self: Atom) SymbolWithLoc { |
| 84 | 84 | ||
| 85 | const InnerSymIterator = struct { | 85 | const InnerSymIterator = struct { |
| 86 | sym_index: u32, | 86 | sym_index: u32, |
| 87 | count: u32, | 87 | nsyms: u32, |
| 88 | file: u32, | 88 | file: u32, |
| 89 | pos: u32 = 0, | ||
| 89 | 90 | ||
| 90 | pub fn next(it: *@This()) ?SymbolWithLoc { | 91 | pub fn next(it: *@This()) ?SymbolWithLoc { |
| 91 | if (it.count == 0) return null; | 92 | if (it.pos == it.nsyms) return null; |
| 92 | const res = SymbolWithLoc{ .sym_index = it.sym_index, .file = it.file }; | 93 | const res = SymbolWithLoc{ .sym_index = it.sym_index + it.pos, .file = it.file }; |
| 93 | it.sym_index += 1; | 94 | it.pos += 1; |
| 94 | it.count -= 1; | ||
| 95 | return res; | 95 | return res; |
| 96 | } | 96 | } |
| 97 | }; | 97 | }; |
| ... | @@ -103,7 +103,7 @@ pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: AtomIndex) InnerSymIterato | ... | @@ -103,7 +103,7 @@ pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: AtomIndex) InnerSymIterato |
| 103 | assert(atom.getFile() != null); | 103 | assert(atom.getFile() != null); |
| 104 | return .{ | 104 | return .{ |
| 105 | .sym_index = atom.inner_sym_index, | 105 | .sym_index = atom.inner_sym_index, |
| 106 | .count = atom.inner_nsyms_trailing, | 106 | .nsyms = atom.inner_nsyms_trailing, |
| 107 | .file = atom.file, | 107 | .file = atom.file, |
| 108 | }; | 108 | }; |
| 109 | } | 109 | } |
| ... | @@ -228,11 +228,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct { | ... | @@ -228,11 +228,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct { |
| 228 | 228 | ||
| 229 | // Find containing atom | 229 | // Find containing atom |
| 230 | log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id }); | 230 | log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id }); |
| 231 | const candidate = object.getSymbolByAddress(address_in_section, sect_id); | 231 | break :sym_index object.getSymbolByAddress(address_in_section, sect_id); |
| 232 | // Make sure we are not dealing with a local alias. | ||
| 233 | const atom_index = object.getAtomIndexForSymbol(candidate) orelse break :sym_index candidate; | ||
| 234 | const atom = zld.getAtom(atom_index); | ||
| 235 | break :sym_index atom.sym_index; | ||
| 236 | } else object.reverse_symtab_lookup[ctx.rel.r_symbolnum]; | 232 | } else object.reverse_symtab_lookup[ctx.rel.r_symbolnum]; |
| 237 | 233 | ||
| 238 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 }; | 234 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 }; |
src/link/MachO/dead_strip.zig+101-94| ... | @@ -294,124 +294,131 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void { | ... | @@ -294,124 +294,131 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void { |
| 294 | const unwind_records = object.getUnwindRecords(); | 294 | const unwind_records = object.getUnwindRecords(); |
| 295 | 295 | ||
| 296 | for (object.exec_atoms.items) |atom_index| { | 296 | for (object.exec_atoms.items) |atom_index| { |
| 297 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); | ||
| 298 | |||
| 297 | if (!object.hasUnwindRecords()) { | 299 | if (!object.hasUnwindRecords()) { |
| 298 | if (object.eh_frame_records_lookup.get(atom_index)) |fde_offset| { | 300 | if (alive.contains(atom_index)) { |
| 299 | const ptr = object.eh_frame_relocs_lookup.getPtr(fde_offset).?; | 301 | // Mark references live and continue. |
| 300 | if (ptr.dead) continue; // already marked | 302 | try markEhFrameRecords(zld, object_id, atom_index, alive); |
| 301 | if (!alive.contains(atom_index)) { | 303 | } else { |
| 302 | // Mark dead and continue. | 304 | while (inner_syms_it.next()) |sym| { |
| 303 | ptr.dead = true; | 305 | if (object.eh_frame_records_lookup.get(sym)) |fde_offset| { |
| 304 | } else { | 306 | // Mark dead and continue. |
| 305 | // Mark references live and continue. | 307 | object.eh_frame_relocs_lookup.getPtr(fde_offset).?.dead = true; |
| 306 | try markEhFrameRecord(zld, object_id, atom_index, alive); | 308 | } |
| 307 | } | 309 | } |
| 308 | continue; | ||
| 309 | } | 310 | } |
| 311 | continue; | ||
| 310 | } | 312 | } |
| 311 | 313 | ||
| 312 | const record_id = object.unwind_records_lookup.get(atom_index) orelse continue; | 314 | while (inner_syms_it.next()) |sym| { |
| 313 | if (object.unwind_relocs_lookup[record_id].dead) continue; // already marked, nothing to do | 315 | const record_id = object.unwind_records_lookup.get(sym) orelse continue; |
| 314 | if (!alive.contains(atom_index)) { | 316 | if (object.unwind_relocs_lookup[record_id].dead) continue; // already marked, nothing to do |
| 315 | // Mark the record dead and continue. | 317 | if (!alive.contains(atom_index)) { |
| 316 | object.unwind_relocs_lookup[record_id].dead = true; | 318 | // Mark the record dead and continue. |
| 317 | if (object.eh_frame_records_lookup.get(atom_index)) |fde_offset| { | 319 | object.unwind_relocs_lookup[record_id].dead = true; |
| 318 | object.eh_frame_relocs_lookup.getPtr(fde_offset).?.dead = true; | 320 | if (object.eh_frame_records_lookup.get(sym)) |fde_offset| { |
| 321 | object.eh_frame_relocs_lookup.getPtr(fde_offset).?.dead = true; | ||
| 322 | } | ||
| 323 | continue; | ||
| 319 | } | 324 | } |
| 320 | continue; | ||
| 321 | } | ||
| 322 | 325 | ||
| 323 | const record = unwind_records[record_id]; | 326 | const record = unwind_records[record_id]; |
| 324 | if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) { | 327 | if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) { |
| 325 | try markEhFrameRecord(zld, object_id, atom_index, alive); | 328 | try markEhFrameRecords(zld, object_id, atom_index, alive); |
| 326 | } else { | 329 | } else { |
| 327 | if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| { | 330 | if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| { |
| 328 | const target = Atom.parseRelocTarget(zld, .{ | 331 | const target = Atom.parseRelocTarget(zld, .{ |
| 329 | .object_id = object_id, | 332 | .object_id = object_id, |
| 330 | .rel = rel, | 333 | .rel = rel, |
| 331 | .code = mem.asBytes(&record), | 334 | .code = mem.asBytes(&record), |
| 332 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | 335 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), |
| 333 | }); | 336 | }); |
| 334 | const target_sym = zld.getSymbol(target); | 337 | const target_sym = zld.getSymbol(target); |
| 335 | if (!target_sym.undf()) { | 338 | if (!target_sym.undf()) { |
| 339 | const target_object = zld.objects.items[target.getFile().?]; | ||
| 340 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; | ||
| 341 | markLive(zld, target_atom_index, alive); | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| { | ||
| 346 | const target = Atom.parseRelocTarget(zld, .{ | ||
| 347 | .object_id = object_id, | ||
| 348 | .rel = rel, | ||
| 349 | .code = mem.asBytes(&record), | ||
| 350 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | ||
| 351 | }); | ||
| 336 | const target_object = zld.objects.items[target.getFile().?]; | 352 | const target_object = zld.objects.items[target.getFile().?]; |
| 337 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; | 353 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; |
| 338 | markLive(zld, target_atom_index, alive); | 354 | markLive(zld, target_atom_index, alive); |
| 339 | } | 355 | } |
| 340 | } | 356 | } |
| 341 | |||
| 342 | if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| { | ||
| 343 | const target = Atom.parseRelocTarget(zld, .{ | ||
| 344 | .object_id = object_id, | ||
| 345 | .rel = rel, | ||
| 346 | .code = mem.asBytes(&record), | ||
| 347 | .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))), | ||
| 348 | }); | ||
| 349 | const target_object = zld.objects.items[target.getFile().?]; | ||
| 350 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; | ||
| 351 | markLive(zld, target_atom_index, alive); | ||
| 352 | } | ||
| 353 | } | 357 | } |
| 354 | } | 358 | } |
| 355 | } | 359 | } |
| 356 | 360 | ||
| 357 | fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *AtomTable) !void { | 361 | fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *AtomTable) !void { |
| 358 | const cpu_arch = zld.options.target.cpu.arch; | 362 | const cpu_arch = zld.options.target.cpu.arch; |
| 359 | const object = &zld.objects.items[object_id]; | 363 | const object = &zld.objects.items[object_id]; |
| 360 | var it = object.getEhFrameRecordsIterator(); | 364 | var it = object.getEhFrameRecordsIterator(); |
| 361 | 365 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); | |
| 362 | const fde_offset = object.eh_frame_records_lookup.get(atom_index).?; | 366 | |
| 363 | it.seekTo(fde_offset); | 367 | while (inner_syms_it.next()) |sym| { |
| 364 | const fde = (try it.next()).?; | 368 | const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue; // Continue in case we hit a temp symbol alias |
| 365 | 369 | it.seekTo(fde_offset); | |
| 366 | const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset); | 370 | const fde = (try it.next()).?; |
| 367 | const cie_offset = fde_offset + 4 - cie_ptr; | 371 | |
| 368 | it.seekTo(cie_offset); | 372 | const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset); |
| 369 | const cie = (try it.next()).?; | 373 | const cie_offset = fde_offset + 4 - cie_ptr; |
| 370 | 374 | it.seekTo(cie_offset); | |
| 371 | switch (cpu_arch) { | 375 | const cie = (try it.next()).?; |
| 372 | .aarch64 => { | 376 | |
| 373 | // Mark FDE references which should include any referenced LSDA record | 377 | switch (cpu_arch) { |
| 374 | const relocs = eh_frame.getRelocs(zld, object_id, fde_offset); | 378 | .aarch64 => { |
| 375 | for (relocs) |rel| { | 379 | // Mark FDE references which should include any referenced LSDA record |
| 376 | const target = Atom.parseRelocTarget(zld, .{ | 380 | const relocs = eh_frame.getRelocs(zld, object_id, fde_offset); |
| 377 | .object_id = object_id, | 381 | for (relocs) |rel| { |
| 378 | .rel = rel, | 382 | const target = Atom.parseRelocTarget(zld, .{ |
| 379 | .code = fde.data, | 383 | .object_id = object_id, |
| 380 | .base_offset = @as(i32, @intCast(fde_offset)) + 4, | 384 | .rel = rel, |
| 385 | .code = fde.data, | ||
| 386 | .base_offset = @as(i32, @intCast(fde_offset)) + 4, | ||
| 387 | }); | ||
| 388 | const target_sym = zld.getSymbol(target); | ||
| 389 | if (!target_sym.undf()) blk: { | ||
| 390 | const target_object = zld.objects.items[target.getFile().?]; | ||
| 391 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index) orelse | ||
| 392 | break :blk; | ||
| 393 | markLive(zld, target_atom_index, alive); | ||
| 394 | } | ||
| 395 | } | ||
| 396 | }, | ||
| 397 | .x86_64 => { | ||
| 398 | const sect = object.getSourceSection(object.eh_frame_sect_id.?); | ||
| 399 | const lsda_ptr = try fde.getLsdaPointer(cie, .{ | ||
| 400 | .base_addr = sect.addr, | ||
| 401 | .base_offset = fde_offset, | ||
| 381 | }); | 402 | }); |
| 382 | const target_sym = zld.getSymbol(target); | 403 | if (lsda_ptr) |lsda_address| { |
| 383 | if (!target_sym.undf()) blk: { | 404 | // Mark LSDA record as live |
| 384 | const target_object = zld.objects.items[target.getFile().?]; | 405 | const sym_index = object.getSymbolByAddress(lsda_address, null); |
| 385 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index) orelse | 406 | const target_atom_index = object.getAtomIndexForSymbol(sym_index).?; |
| 386 | break :blk; | ||
| 387 | markLive(zld, target_atom_index, alive); | 407 | markLive(zld, target_atom_index, alive); |
| 388 | } | 408 | } |
| 389 | } | 409 | }, |
| 390 | }, | 410 | else => unreachable, |
| 391 | .x86_64 => { | 411 | } |
| 392 | const sect = object.getSourceSection(object.eh_frame_sect_id.?); | 412 | |
| 393 | const lsda_ptr = try fde.getLsdaPointer(cie, .{ | 413 | // Mark CIE references which should include any referenced personalities |
| 394 | .base_addr = sect.addr, | 414 | // that are defined locally. |
| 395 | .base_offset = fde_offset, | 415 | if (cie.getPersonalityPointerReloc(zld, object_id, cie_offset)) |target| { |
| 396 | }); | 416 | const target_sym = zld.getSymbol(target); |
| 397 | if (lsda_ptr) |lsda_address| { | 417 | if (!target_sym.undf()) { |
| 398 | // Mark LSDA record as live | 418 | const target_object = zld.objects.items[target.getFile().?]; |
| 399 | const sym_index = object.getSymbolByAddress(lsda_address, null); | 419 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; |
| 400 | const target_atom_index = object.getAtomIndexForSymbol(sym_index).?; | ||
| 401 | markLive(zld, target_atom_index, alive); | 420 | markLive(zld, target_atom_index, alive); |
| 402 | } | 421 | } |
| 403 | }, | ||
| 404 | else => unreachable, | ||
| 405 | } | ||
| 406 | |||
| 407 | // Mark CIE references which should include any referenced personalities | ||
| 408 | // that are defined locally. | ||
| 409 | if (cie.getPersonalityPointerReloc(zld, object_id, cie_offset)) |target| { | ||
| 410 | const target_sym = zld.getSymbol(target); | ||
| 411 | if (!target_sym.undf()) { | ||
| 412 | const target_object = zld.objects.items[target.getFile().?]; | ||
| 413 | const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?; | ||
| 414 | markLive(zld, target_atom_index, alive); | ||
| 415 | } | 422 | } |
| 416 | } | 423 | } |
| 417 | } | 424 | } |
src/link/MachO/eh_frame.zig+127-119| ... | @@ -24,19 +24,22 @@ pub fn scanRelocs(zld: *Zld) !void { | ... | @@ -24,19 +24,22 @@ pub fn scanRelocs(zld: *Zld) !void { |
| 24 | var it = object.getEhFrameRecordsIterator(); | 24 | var it = object.getEhFrameRecordsIterator(); |
| 25 | 25 | ||
| 26 | for (object.exec_atoms.items) |atom_index| { | 26 | for (object.exec_atoms.items) |atom_index| { |
| 27 | const fde_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue; | 27 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 28 | if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue; | 28 | while (inner_syms_it.next()) |sym| { |
| 29 | it.seekTo(fde_offset); | 29 | const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue; |
| 30 | const fde = (try it.next()).?; | 30 | if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue; |
| 31 | 31 | it.seekTo(fde_offset); | |
| 32 | const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset); | 32 | const fde = (try it.next()).?; |
| 33 | const cie_offset = fde_offset + 4 - cie_ptr; | 33 | |
| 34 | 34 | const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset); | |
| 35 | if (!cies.contains(cie_offset)) { | 35 | const cie_offset = fde_offset + 4 - cie_ptr; |
| 36 | try cies.putNoClobber(cie_offset, {}); | 36 | |
| 37 | it.seekTo(cie_offset); | 37 | if (!cies.contains(cie_offset)) { |
| 38 | const cie = (try it.next()).?; | 38 | try cies.putNoClobber(cie_offset, {}); |
| 39 | try cie.scanRelocs(zld, @as(u32, @intCast(object_id)), cie_offset); | 39 | it.seekTo(cie_offset); |
| 40 | const cie = (try it.next()).?; | ||
| 41 | try cie.scanRelocs(zld, @as(u32, @intCast(object_id)), cie_offset); | ||
| 42 | } | ||
| 40 | } | 43 | } |
| 41 | } | 44 | } |
| 42 | } | 45 | } |
| ... | @@ -59,35 +62,38 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void { | ... | @@ -59,35 +62,38 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void { |
| 59 | var eh_it = object.getEhFrameRecordsIterator(); | 62 | var eh_it = object.getEhFrameRecordsIterator(); |
| 60 | 63 | ||
| 61 | for (object.exec_atoms.items) |atom_index| { | 64 | for (object.exec_atoms.items) |atom_index| { |
| 62 | const fde_record_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue; | 65 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 63 | if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue; | 66 | while (inner_syms_it.next()) |sym| { |
| 64 | 67 | const fde_record_offset = object.eh_frame_records_lookup.get(sym) orelse continue; | |
| 65 | const record_id = unwind_info.records_lookup.get(atom_index) orelse continue; | 68 | if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue; |
| 66 | const record = unwind_info.records.items[record_id]; | 69 | |
| 67 | 70 | const record_id = unwind_info.records_lookup.get(sym) orelse continue; | |
| 68 | // TODO skip this check if no __compact_unwind is present | 71 | const record = unwind_info.records.items[record_id]; |
| 69 | const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch); | 72 | |
| 70 | if (!is_dwarf) continue; | 73 | // TODO skip this check if no __compact_unwind is present |
| 71 | 74 | const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch); | |
| 72 | eh_it.seekTo(fde_record_offset); | 75 | if (!is_dwarf) continue; |
| 73 | const source_fde_record = (try eh_it.next()).?; | 76 | |
| 74 | 77 | eh_it.seekTo(fde_record_offset); | |
| 75 | const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset); | 78 | const source_fde_record = (try eh_it.next()).?; |
| 76 | const cie_offset = fde_record_offset + 4 - cie_ptr; | 79 | |
| 80 | const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset); | ||
| 81 | const cie_offset = fde_record_offset + 4 - cie_ptr; | ||
| 82 | |||
| 83 | const gop = try cies.getOrPut(cie_offset); | ||
| 84 | if (!gop.found_existing) { | ||
| 85 | eh_it.seekTo(cie_offset); | ||
| 86 | const source_cie_record = (try eh_it.next()).?; | ||
| 87 | gop.value_ptr.* = size; | ||
| 88 | size += source_cie_record.getSize(); | ||
| 89 | } | ||
| 77 | 90 | ||
| 78 | const gop = try cies.getOrPut(cie_offset); | 91 | size += source_fde_record.getSize(); |
| 79 | if (!gop.found_existing) { | ||
| 80 | eh_it.seekTo(cie_offset); | ||
| 81 | const source_cie_record = (try eh_it.next()).?; | ||
| 82 | gop.value_ptr.* = size; | ||
| 83 | size += source_cie_record.getSize(); | ||
| 84 | } | 92 | } |
| 85 | |||
| 86 | size += source_fde_record.getSize(); | ||
| 87 | } | 93 | } |
| 88 | } | ||
| 89 | 94 | ||
| 90 | sect.size = size; | 95 | sect.size = size; |
| 96 | } | ||
| 91 | } | 97 | } |
| 92 | 98 | ||
| 93 | pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void { | 99 | pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void { |
| ... | @@ -118,97 +124,99 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void { | ... | @@ -118,97 +124,99 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void { |
| 118 | var eh_it = object.getEhFrameRecordsIterator(); | 124 | var eh_it = object.getEhFrameRecordsIterator(); |
| 119 | 125 | ||
| 120 | for (object.exec_atoms.items) |atom_index| { | 126 | for (object.exec_atoms.items) |atom_index| { |
| 121 | const fde_record_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue; | 127 | var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index); |
| 122 | if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue; | 128 | while (inner_syms_it.next()) |target| { |
| 123 | 129 | const fde_record_offset = object.eh_frame_records_lookup.get(target) orelse continue; | |
| 124 | const record_id = unwind_info.records_lookup.get(atom_index) orelse continue; | 130 | if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue; |
| 125 | const record = &unwind_info.records.items[record_id]; | 131 | |
| 126 | 132 | const record_id = unwind_info.records_lookup.get(target) orelse continue; | |
| 127 | // TODO skip this check if no __compact_unwind is present | 133 | const record = &unwind_info.records.items[record_id]; |
| 128 | const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch); | 134 | |
| 129 | if (!is_dwarf) continue; | 135 | // TODO skip this check if no __compact_unwind is present |
| 130 | 136 | const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch); | |
| 131 | eh_it.seekTo(fde_record_offset); | 137 | if (!is_dwarf) continue; |
| 132 | const source_fde_record = (try eh_it.next()).?; | 138 | |
| 133 | 139 | eh_it.seekTo(fde_record_offset); | |
| 134 | const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset); | 140 | const source_fde_record = (try eh_it.next()).?; |
| 135 | const cie_offset = fde_record_offset + 4 - cie_ptr; | 141 | |
| 142 | const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset); | ||
| 143 | const cie_offset = fde_record_offset + 4 - cie_ptr; | ||
| 144 | |||
| 145 | const gop = try cies.getOrPut(cie_offset); | ||
| 146 | if (!gop.found_existing) { | ||
| 147 | eh_it.seekTo(cie_offset); | ||
| 148 | const source_cie_record = (try eh_it.next()).?; | ||
| 149 | var cie_record = try source_cie_record.toOwned(gpa); | ||
| 150 | try cie_record.relocate(zld, @as(u32, @intCast(object_id)), .{ | ||
| 151 | .source_offset = cie_offset, | ||
| 152 | .out_offset = eh_frame_offset, | ||
| 153 | .sect_addr = sect.addr, | ||
| 154 | }); | ||
| 155 | eh_records.putAssumeCapacityNoClobber(eh_frame_offset, cie_record); | ||
| 156 | gop.value_ptr.* = eh_frame_offset; | ||
| 157 | eh_frame_offset += cie_record.getSize(); | ||
| 158 | } | ||
| 136 | 159 | ||
| 137 | const gop = try cies.getOrPut(cie_offset); | 160 | var fde_record = try source_fde_record.toOwned(gpa); |
| 138 | if (!gop.found_existing) { | 161 | try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{ |
| 139 | eh_it.seekTo(cie_offset); | 162 | .source_offset = fde_record_offset, |
| 140 | const source_cie_record = (try eh_it.next()).?; | ||
| 141 | var cie_record = try source_cie_record.toOwned(gpa); | ||
| 142 | try cie_record.relocate(zld, @as(u32, @intCast(object_id)), .{ | ||
| 143 | .source_offset = cie_offset, | ||
| 144 | .out_offset = eh_frame_offset, | 163 | .out_offset = eh_frame_offset, |
| 145 | .sect_addr = sect.addr, | 164 | .sect_addr = sect.addr, |
| 146 | }); | 165 | }); |
| 147 | eh_records.putAssumeCapacityNoClobber(eh_frame_offset, cie_record); | 166 | fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*); |
| 148 | gop.value_ptr.* = eh_frame_offset; | ||
| 149 | eh_frame_offset += cie_record.getSize(); | ||
| 150 | } | ||
| 151 | |||
| 152 | var fde_record = try source_fde_record.toOwned(gpa); | ||
| 153 | try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{ | ||
| 154 | .source_offset = fde_record_offset, | ||
| 155 | .out_offset = eh_frame_offset, | ||
| 156 | .sect_addr = sect.addr, | ||
| 157 | }); | ||
| 158 | fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*); | ||
| 159 | |||
| 160 | switch (cpu_arch) { | ||
| 161 | .aarch64 => {}, // relocs take care of LSDA pointers | ||
| 162 | .x86_64 => { | ||
| 163 | // We need to relocate target symbol address ourselves. | ||
| 164 | const atom = zld.getAtom(atom_index); | ||
| 165 | const atom_sym = zld.getSymbol(atom.getSymbolWithLoc()); | ||
| 166 | try fde_record.setTargetSymbolAddress(atom_sym.n_value, .{ | ||
| 167 | .base_addr = sect.addr, | ||
| 168 | .base_offset = eh_frame_offset, | ||
| 169 | }); | ||
| 170 | 167 | ||
| 171 | // We need to parse LSDA pointer and relocate ourselves. | 168 | switch (cpu_arch) { |
| 172 | const cie_record = eh_records.get( | 169 | .aarch64 => {}, // relocs take care of LSDA pointers |
| 173 | eh_frame_offset + 4 - fde_record.getCiePointer(), | 170 | .x86_64 => { |
| 174 | ).?; | 171 | // We need to relocate target symbol address ourselves. |
| 175 | const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?); | 172 | const atom_sym = zld.getSymbol(target); |
| 176 | const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{ | 173 | try fde_record.setTargetSymbolAddress(atom_sym.n_value, .{ |
| 177 | .base_addr = eh_frame_sect.addr, | ||
| 178 | .base_offset = fde_record_offset, | ||
| 179 | }); | ||
| 180 | if (source_lsda_ptr) |ptr| { | ||
| 181 | const sym_index = object.getSymbolByAddress(ptr, null); | ||
| 182 | const sym = object.symtab[sym_index]; | ||
| 183 | try fde_record.setLsdaPointer(cie_record, sym.n_value, .{ | ||
| 184 | .base_addr = sect.addr, | 174 | .base_addr = sect.addr, |
| 185 | .base_offset = eh_frame_offset, | 175 | .base_offset = eh_frame_offset, |
| 186 | }); | 176 | }); |
| 187 | } | ||
| 188 | }, | ||
| 189 | else => unreachable, | ||
| 190 | } | ||
| 191 | 177 | ||
| 192 | eh_records.putAssumeCapacityNoClobber(eh_frame_offset, fde_record); | 178 | // We need to parse LSDA pointer and relocate ourselves. |
| 193 | 179 | const cie_record = eh_records.get( | |
| 194 | UnwindInfo.UnwindEncoding.setDwarfSectionOffset( | 180 | eh_frame_offset + 4 - fde_record.getCiePointer(), |
| 195 | &record.compactUnwindEncoding, | 181 | ).?; |
| 196 | cpu_arch, | 182 | const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?); |
| 197 | @as(u24, @intCast(eh_frame_offset)), | 183 | const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{ |
| 198 | ); | 184 | .base_addr = eh_frame_sect.addr, |
| 199 | 185 | .base_offset = fde_record_offset, | |
| 200 | const cie_record = eh_records.get( | 186 | }); |
| 201 | eh_frame_offset + 4 - fde_record.getCiePointer(), | 187 | if (source_lsda_ptr) |ptr| { |
| 202 | ).?; | 188 | const sym_index = object.getSymbolByAddress(ptr, null); |
| 203 | const lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{ | 189 | const sym = object.symtab[sym_index]; |
| 204 | .base_addr = sect.addr, | 190 | try fde_record.setLsdaPointer(cie_record, sym.n_value, .{ |
| 205 | .base_offset = eh_frame_offset, | 191 | .base_addr = sect.addr, |
| 206 | }); | 192 | .base_offset = eh_frame_offset, |
| 207 | if (lsda_ptr) |ptr| { | 193 | }); |
| 208 | record.lsda = ptr - seg.vmaddr; | 194 | } |
| 209 | } | 195 | }, |
| 196 | else => unreachable, | ||
| 197 | } | ||
| 198 | |||
| 199 | eh_records.putAssumeCapacityNoClobber(eh_frame_offset, fde_record); | ||
| 200 | |||
| 201 | UnwindInfo.UnwindEncoding.setDwarfSectionOffset( | ||
| 202 | &record.compactUnwindEncoding, | ||
| 203 | cpu_arch, | ||
| 204 | @as(u24, @intCast(eh_frame_offset)), | ||
| 205 | ); | ||
| 210 | 206 | ||
| 211 | eh_frame_offset += fde_record.getSize(); | 207 | const cie_record = eh_records.get( |
| 208 | eh_frame_offset + 4 - fde_record.getCiePointer(), | ||
| 209 | ).?; | ||
| 210 | const lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{ | ||
| 211 | .base_addr = sect.addr, | ||
| 212 | .base_offset = eh_frame_offset, | ||
| 213 | }); | ||
| 214 | if (lsda_ptr) |ptr| { | ||
| 215 | record.lsda = ptr - seg.vmaddr; | ||
| 216 | } | ||
| 217 | |||
| 218 | eh_frame_offset += fde_record.getSize(); | ||
| 219 | } | ||
| 212 | } | 220 | } |
| 213 | } | 221 | } |
| 214 | 222 |
src/link/MachO/zld.zig+36| ... | @@ -1492,6 +1492,42 @@ pub const Zld = struct { | ... | @@ -1492,6 +1492,42 @@ pub const Zld = struct { |
| 1492 | try thunks.createThunks(self, @as(u8, @intCast(sect_id))); | 1492 | try thunks.createThunks(self, @as(u8, @intCast(sect_id))); |
| 1493 | } | 1493 | } |
| 1494 | } | 1494 | } |
| 1495 | |||
| 1496 | // Update offsets of all symbols contained within each Atom. | ||
| 1497 | // We need to do this since our unwind info synthesiser relies on | ||
| 1498 | // traversing the symbols when synthesising unwind info and DWARF CFI records. | ||
| 1499 | for (slice.items(.first_atom_index)) |first_atom_index| { | ||
| 1500 | if (first_atom_index == 0) continue; | ||
| 1501 | var atom_index = first_atom_index; | ||
| 1502 | |||
| 1503 | while (true) { | ||
| 1504 | const atom = self.getAtom(atom_index); | ||
| 1505 | const sym = self.getSymbol(atom.getSymbolWithLoc()); | ||
| 1506 | |||
| 1507 | if (atom.getFile() != null) { | ||
| 1508 | // Update each symbol contained within the atom | ||
| 1509 | var it = Atom.getInnerSymbolsIterator(self, atom_index); | ||
| 1510 | while (it.next()) |sym_loc| { | ||
| 1511 | const inner_sym = self.getSymbolPtr(sym_loc); | ||
| 1512 | inner_sym.n_value = sym.n_value + Atom.calcInnerSymbolOffset( | ||
| 1513 | self, | ||
| 1514 | atom_index, | ||
| 1515 | sym_loc.sym_index, | ||
| 1516 | ); | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | // If there is a section alias, update it now too | ||
| 1520 | if (Atom.getSectionAlias(self, atom_index)) |sym_loc| { | ||
| 1521 | const alias = self.getSymbolPtr(sym_loc); | ||
| 1522 | alias.n_value = sym.n_value; | ||
| 1523 | } | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | if (atom.next_index) |next_index| { | ||
| 1527 | atom_index = next_index; | ||
| 1528 | } else break; | ||
| 1529 | } | ||
| 1530 | } | ||
| 1495 | } | 1531 | } |
| 1496 | 1532 | ||
| 1497 | fn allocateSegments(self: *Zld) !void { | 1533 | fn allocateSegments(self: *Zld) !void { |