Commit d6e095de2c
Changed files (6)
src/link/MachO/dead_strip.zig
@@ -294,124 +294,131 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
const unwind_records = object.getUnwindRecords();
for (object.exec_atoms.items) |atom_index| {
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+
if (!object.hasUnwindRecords()) {
- if (object.eh_frame_records_lookup.get(atom_index)) |fde_offset| {
- const ptr = object.eh_frame_relocs_lookup.getPtr(fde_offset).?;
- if (ptr.dead) continue; // already marked
- if (!alive.contains(atom_index)) {
- // Mark dead and continue.
- ptr.dead = true;
- } else {
- // Mark references live and continue.
- try markEhFrameRecord(zld, object_id, atom_index, alive);
+ if (alive.contains(atom_index)) {
+ // Mark references live and continue.
+ try markEhFrameRecords(zld, object_id, atom_index, alive);
+ } else {
+ while (inner_syms_it.next()) |sym| {
+ if (object.eh_frame_records_lookup.get(sym)) |fde_offset| {
+ // Mark dead and continue.
+ object.eh_frame_relocs_lookup.getPtr(fde_offset).?.dead = true;
+ }
}
- continue;
}
+ continue;
}
- const record_id = object.unwind_records_lookup.get(atom_index) orelse continue;
- if (object.unwind_relocs_lookup[record_id].dead) continue; // already marked, nothing to do
- if (!alive.contains(atom_index)) {
- // Mark the record dead and continue.
- object.unwind_relocs_lookup[record_id].dead = true;
- if (object.eh_frame_records_lookup.get(atom_index)) |fde_offset| {
- object.eh_frame_relocs_lookup.getPtr(fde_offset).?.dead = true;
+ while (inner_syms_it.next()) |sym| {
+ const record_id = object.unwind_records_lookup.get(sym) orelse continue;
+ if (object.unwind_relocs_lookup[record_id].dead) continue; // already marked, nothing to do
+ if (!alive.contains(atom_index)) {
+ // Mark the record dead and continue.
+ object.unwind_relocs_lookup[record_id].dead = true;
+ if (object.eh_frame_records_lookup.get(sym)) |fde_offset| {
+ object.eh_frame_relocs_lookup.getPtr(fde_offset).?.dead = true;
+ }
+ continue;
}
- continue;
- }
- const record = unwind_records[record_id];
- if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
- try markEhFrameRecord(zld, object_id, atom_index, alive);
- } else {
- if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {
- const target = Atom.parseRelocTarget(zld, .{
- .object_id = object_id,
- .rel = rel,
- .code = mem.asBytes(&record),
- .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
- });
- const target_sym = zld.getSymbol(target);
- if (!target_sym.undf()) {
+ const record = unwind_records[record_id];
+ if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
+ try markEhFrameRecords(zld, object_id, atom_index, alive);
+ } else {
+ if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
+ });
+ const target_sym = zld.getSymbol(target);
+ if (!target_sym.undf()) {
+ const target_object = zld.objects.items[target.getFile().?];
+ const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
+ markLive(zld, target_atom_index, alive);
+ }
+ }
+
+ if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
+ });
const target_object = zld.objects.items[target.getFile().?];
const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
markLive(zld, target_atom_index, alive);
}
}
-
- if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {
- const target = Atom.parseRelocTarget(zld, .{
- .object_id = object_id,
- .rel = rel,
- .code = mem.asBytes(&record),
- .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
- });
- const target_object = zld.objects.items[target.getFile().?];
- const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
- markLive(zld, target_atom_index, alive);
- }
}
}
}
-fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *AtomTable) !void {
+fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *AtomTable) !void {
const cpu_arch = zld.options.target.cpu.arch;
const object = &zld.objects.items[object_id];
var it = object.getEhFrameRecordsIterator();
-
- const fde_offset = object.eh_frame_records_lookup.get(atom_index).?;
- it.seekTo(fde_offset);
- const fde = (try it.next()).?;
-
- const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
- const cie_offset = fde_offset + 4 - cie_ptr;
- it.seekTo(cie_offset);
- const cie = (try it.next()).?;
-
- switch (cpu_arch) {
- .aarch64 => {
- // Mark FDE references which should include any referenced LSDA record
- const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);
- for (relocs) |rel| {
- const target = Atom.parseRelocTarget(zld, .{
- .object_id = object_id,
- .rel = rel,
- .code = fde.data,
- .base_offset = @as(i32, @intCast(fde_offset)) + 4,
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+
+ while (inner_syms_it.next()) |sym| {
+ const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue; // Continue in case we hit a temp symbol alias
+ it.seekTo(fde_offset);
+ const fde = (try it.next()).?;
+
+ const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
+ const cie_offset = fde_offset + 4 - cie_ptr;
+ it.seekTo(cie_offset);
+ const cie = (try it.next()).?;
+
+ switch (cpu_arch) {
+ .aarch64 => {
+ // Mark FDE references which should include any referenced LSDA record
+ const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);
+ for (relocs) |rel| {
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = object_id,
+ .rel = rel,
+ .code = fde.data,
+ .base_offset = @as(i32, @intCast(fde_offset)) + 4,
+ });
+ const target_sym = zld.getSymbol(target);
+ if (!target_sym.undf()) blk: {
+ const target_object = zld.objects.items[target.getFile().?];
+ const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index) orelse
+ break :blk;
+ markLive(zld, target_atom_index, alive);
+ }
+ }
+ },
+ .x86_64 => {
+ const sect = object.getSourceSection(object.eh_frame_sect_id.?);
+ const lsda_ptr = try fde.getLsdaPointer(cie, .{
+ .base_addr = sect.addr,
+ .base_offset = fde_offset,
});
- const target_sym = zld.getSymbol(target);
- if (!target_sym.undf()) blk: {
- const target_object = zld.objects.items[target.getFile().?];
- const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index) orelse
- break :blk;
+ if (lsda_ptr) |lsda_address| {
+ // Mark LSDA record as live
+ const sym_index = object.getSymbolByAddress(lsda_address, null);
+ const target_atom_index = object.getAtomIndexForSymbol(sym_index).?;
markLive(zld, target_atom_index, alive);
}
- }
- },
- .x86_64 => {
- const sect = object.getSourceSection(object.eh_frame_sect_id.?);
- const lsda_ptr = try fde.getLsdaPointer(cie, .{
- .base_addr = sect.addr,
- .base_offset = fde_offset,
- });
- if (lsda_ptr) |lsda_address| {
- // Mark LSDA record as live
- const sym_index = object.getSymbolByAddress(lsda_address, null);
- const target_atom_index = object.getAtomIndexForSymbol(sym_index).?;
+ },
+ else => unreachable,
+ }
+
+ // Mark CIE references which should include any referenced personalities
+ // that are defined locally.
+ if (cie.getPersonalityPointerReloc(zld, object_id, cie_offset)) |target| {
+ const target_sym = zld.getSymbol(target);
+ if (!target_sym.undf()) {
+ const target_object = zld.objects.items[target.getFile().?];
+ const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
markLive(zld, target_atom_index, alive);
}
- },
- else => unreachable,
- }
-
- // Mark CIE references which should include any referenced personalities
- // that are defined locally.
- if (cie.getPersonalityPointerReloc(zld, object_id, cie_offset)) |target| {
- const target_sym = zld.getSymbol(target);
- if (!target_sym.undf()) {
- const target_object = zld.objects.items[target.getFile().?];
- const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
- markLive(zld, target_atom_index, alive);
}
}
}
src/link/MachO/eh_frame.zig
@@ -24,19 +24,22 @@ pub fn scanRelocs(zld: *Zld) !void {
var it = object.getEhFrameRecordsIterator();
for (object.exec_atoms.items) |atom_index| {
- const fde_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue;
- if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
- it.seekTo(fde_offset);
- const fde = (try it.next()).?;
-
- const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset);
- const cie_offset = fde_offset + 4 - cie_ptr;
-
- if (!cies.contains(cie_offset)) {
- try cies.putNoClobber(cie_offset, {});
- it.seekTo(cie_offset);
- const cie = (try it.next()).?;
- try cie.scanRelocs(zld, @as(u32, @intCast(object_id)), cie_offset);
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+ while (inner_syms_it.next()) |sym| {
+ const fde_offset = object.eh_frame_records_lookup.get(sym) orelse continue;
+ if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
+ it.seekTo(fde_offset);
+ const fde = (try it.next()).?;
+
+ const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset);
+ const cie_offset = fde_offset + 4 - cie_ptr;
+
+ if (!cies.contains(cie_offset)) {
+ try cies.putNoClobber(cie_offset, {});
+ it.seekTo(cie_offset);
+ const cie = (try it.next()).?;
+ try cie.scanRelocs(zld, @as(u32, @intCast(object_id)), cie_offset);
+ }
}
}
}
@@ -59,35 +62,38 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void {
var eh_it = object.getEhFrameRecordsIterator();
for (object.exec_atoms.items) |atom_index| {
- const fde_record_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue;
- if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue;
-
- const record_id = unwind_info.records_lookup.get(atom_index) orelse continue;
- const record = unwind_info.records.items[record_id];
-
- // TODO skip this check if no __compact_unwind is present
- const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch);
- if (!is_dwarf) continue;
-
- eh_it.seekTo(fde_record_offset);
- const source_fde_record = (try eh_it.next()).?;
-
- const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
- const cie_offset = fde_record_offset + 4 - cie_ptr;
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+ while (inner_syms_it.next()) |sym| {
+ const fde_record_offset = object.eh_frame_records_lookup.get(sym) orelse continue;
+ if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue;
+
+ const record_id = unwind_info.records_lookup.get(sym) orelse continue;
+ const record = unwind_info.records.items[record_id];
+
+ // TODO skip this check if no __compact_unwind is present
+ const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch);
+ if (!is_dwarf) continue;
+
+ eh_it.seekTo(fde_record_offset);
+ const source_fde_record = (try eh_it.next()).?;
+
+ const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
+ const cie_offset = fde_record_offset + 4 - cie_ptr;
+
+ const gop = try cies.getOrPut(cie_offset);
+ if (!gop.found_existing) {
+ eh_it.seekTo(cie_offset);
+ const source_cie_record = (try eh_it.next()).?;
+ gop.value_ptr.* = size;
+ size += source_cie_record.getSize();
+ }
- const gop = try cies.getOrPut(cie_offset);
- if (!gop.found_existing) {
- eh_it.seekTo(cie_offset);
- const source_cie_record = (try eh_it.next()).?;
- gop.value_ptr.* = size;
- size += source_cie_record.getSize();
+ size += source_fde_record.getSize();
}
-
- size += source_fde_record.getSize();
}
- }
- sect.size = size;
+ sect.size = size;
+ }
}
pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
@@ -118,97 +124,99 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
var eh_it = object.getEhFrameRecordsIterator();
for (object.exec_atoms.items) |atom_index| {
- const fde_record_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue;
- if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue;
-
- const record_id = unwind_info.records_lookup.get(atom_index) orelse continue;
- const record = &unwind_info.records.items[record_id];
-
- // TODO skip this check if no __compact_unwind is present
- const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch);
- if (!is_dwarf) continue;
-
- eh_it.seekTo(fde_record_offset);
- const source_fde_record = (try eh_it.next()).?;
-
- const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
- const cie_offset = fde_record_offset + 4 - cie_ptr;
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+ while (inner_syms_it.next()) |target| {
+ const fde_record_offset = object.eh_frame_records_lookup.get(target) orelse continue;
+ if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue;
+
+ const record_id = unwind_info.records_lookup.get(target) orelse continue;
+ const record = &unwind_info.records.items[record_id];
+
+ // TODO skip this check if no __compact_unwind is present
+ const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch);
+ if (!is_dwarf) continue;
+
+ eh_it.seekTo(fde_record_offset);
+ const source_fde_record = (try eh_it.next()).?;
+
+ const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
+ const cie_offset = fde_record_offset + 4 - cie_ptr;
+
+ const gop = try cies.getOrPut(cie_offset);
+ if (!gop.found_existing) {
+ eh_it.seekTo(cie_offset);
+ const source_cie_record = (try eh_it.next()).?;
+ var cie_record = try source_cie_record.toOwned(gpa);
+ try cie_record.relocate(zld, @as(u32, @intCast(object_id)), .{
+ .source_offset = cie_offset,
+ .out_offset = eh_frame_offset,
+ .sect_addr = sect.addr,
+ });
+ eh_records.putAssumeCapacityNoClobber(eh_frame_offset, cie_record);
+ gop.value_ptr.* = eh_frame_offset;
+ eh_frame_offset += cie_record.getSize();
+ }
- const gop = try cies.getOrPut(cie_offset);
- if (!gop.found_existing) {
- eh_it.seekTo(cie_offset);
- const source_cie_record = (try eh_it.next()).?;
- var cie_record = try source_cie_record.toOwned(gpa);
- try cie_record.relocate(zld, @as(u32, @intCast(object_id)), .{
- .source_offset = cie_offset,
+ var fde_record = try source_fde_record.toOwned(gpa);
+ try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{
+ .source_offset = fde_record_offset,
.out_offset = eh_frame_offset,
.sect_addr = sect.addr,
});
- eh_records.putAssumeCapacityNoClobber(eh_frame_offset, cie_record);
- gop.value_ptr.* = eh_frame_offset;
- eh_frame_offset += cie_record.getSize();
- }
-
- var fde_record = try source_fde_record.toOwned(gpa);
- try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{
- .source_offset = fde_record_offset,
- .out_offset = eh_frame_offset,
- .sect_addr = sect.addr,
- });
- fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*);
-
- switch (cpu_arch) {
- .aarch64 => {}, // relocs take care of LSDA pointers
- .x86_64 => {
- // We need to relocate target symbol address ourselves.
- const atom = zld.getAtom(atom_index);
- const atom_sym = zld.getSymbol(atom.getSymbolWithLoc());
- try fde_record.setTargetSymbolAddress(atom_sym.n_value, .{
- .base_addr = sect.addr,
- .base_offset = eh_frame_offset,
- });
+ fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*);
- // We need to parse LSDA pointer and relocate ourselves.
- const cie_record = eh_records.get(
- eh_frame_offset + 4 - fde_record.getCiePointer(),
- ).?;
- const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?);
- const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
- .base_addr = eh_frame_sect.addr,
- .base_offset = fde_record_offset,
- });
- if (source_lsda_ptr) |ptr| {
- const sym_index = object.getSymbolByAddress(ptr, null);
- const sym = object.symtab[sym_index];
- try fde_record.setLsdaPointer(cie_record, sym.n_value, .{
+ switch (cpu_arch) {
+ .aarch64 => {}, // relocs take care of LSDA pointers
+ .x86_64 => {
+ // We need to relocate target symbol address ourselves.
+ const atom_sym = zld.getSymbol(target);
+ try fde_record.setTargetSymbolAddress(atom_sym.n_value, .{
.base_addr = sect.addr,
.base_offset = eh_frame_offset,
});
- }
- },
- else => unreachable,
- }
- eh_records.putAssumeCapacityNoClobber(eh_frame_offset, fde_record);
-
- UnwindInfo.UnwindEncoding.setDwarfSectionOffset(
- &record.compactUnwindEncoding,
- cpu_arch,
- @as(u24, @intCast(eh_frame_offset)),
- );
-
- const cie_record = eh_records.get(
- eh_frame_offset + 4 - fde_record.getCiePointer(),
- ).?;
- const lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
- .base_addr = sect.addr,
- .base_offset = eh_frame_offset,
- });
- if (lsda_ptr) |ptr| {
- record.lsda = ptr - seg.vmaddr;
- }
+ // We need to parse LSDA pointer and relocate ourselves.
+ const cie_record = eh_records.get(
+ eh_frame_offset + 4 - fde_record.getCiePointer(),
+ ).?;
+ const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?);
+ const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
+ .base_addr = eh_frame_sect.addr,
+ .base_offset = fde_record_offset,
+ });
+ if (source_lsda_ptr) |ptr| {
+ const sym_index = object.getSymbolByAddress(ptr, null);
+ const sym = object.symtab[sym_index];
+ try fde_record.setLsdaPointer(cie_record, sym.n_value, .{
+ .base_addr = sect.addr,
+ .base_offset = eh_frame_offset,
+ });
+ }
+ },
+ else => unreachable,
+ }
+
+ eh_records.putAssumeCapacityNoClobber(eh_frame_offset, fde_record);
+
+ UnwindInfo.UnwindEncoding.setDwarfSectionOffset(
+ &record.compactUnwindEncoding,
+ cpu_arch,
+ @as(u24, @intCast(eh_frame_offset)),
+ );
- eh_frame_offset += fde_record.getSize();
+ const cie_record = eh_records.get(
+ eh_frame_offset + 4 - fde_record.getCiePointer(),
+ ).?;
+ const lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
+ .base_addr = sect.addr,
+ .base_offset = eh_frame_offset,
+ });
+ if (lsda_ptr) |ptr| {
+ record.lsda = ptr - seg.vmaddr;
+ }
+
+ eh_frame_offset += fde_record.getSize();
+ }
}
}
src/link/MachO/Object.zig
@@ -75,11 +75,11 @@ exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{},
eh_frame_sect_id: ?u8 = null,
eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},
-eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(AtomIndex, u32) = .{},
+eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{},
unwind_info_sect_id: ?u8 = null,
unwind_relocs_lookup: []Record = undefined,
-unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},
+unwind_records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
const Entry = struct {
start: u32 = 0,
@@ -274,11 +274,11 @@ const SymbolAtIndex = struct {
const sym = self.getSymbol(ctx);
if (!sym.ext()) {
const sym_name = self.getSymbolName(ctx);
- if (mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L")) return 0;
- return 1;
+ if (mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L")) return 3;
+ return 2;
}
- if (sym.weakDef() or sym.pext()) return 2;
- return 3;
+ if (sym.weakDef() or sym.pext()) return 1;
+ return 0;
}
/// Performs lexicographic-like check.
@@ -423,8 +423,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
zld,
object_id,
sym_index,
- 0,
- 0,
+ sym_index,
+ 1,
sect.size,
sect.@"align",
out_sect_id,
@@ -502,8 +502,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
zld,
object_id,
sym_index,
- 0,
- 0,
+ sym_index,
+ 1,
atom_size,
sect.@"align",
out_sect_id,
@@ -521,7 +521,7 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
const atom_loc = filterSymbolsByAddress(symtab[next_sym_index..], addr, addr + 1);
assert(atom_loc.len > 0);
const atom_sym_index = atom_loc.index + next_sym_index;
- const nsyms_trailing = atom_loc.len - 1;
+ const nsyms_trailing = atom_loc.len;
next_sym_index += atom_loc.len;
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 {
zld,
object_id,
atom_sym_index,
- atom_sym_index + 1,
+ atom_sym_index,
nsyms_trailing,
atom_size,
atom_align,
@@ -772,8 +772,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
if (target.getFile() != object_id) {
self.eh_frame_relocs_lookup.getPtr(offset).?.dead = true;
} else {
- const atom_index = self.getAtomIndexForSymbol(target.sym_index).?;
- self.eh_frame_records_lookup.putAssumeCapacityNoClobber(atom_index, offset);
+ self.eh_frame_records_lookup.putAssumeCapacityNoClobber(target, offset);
}
}
}
@@ -802,10 +801,10 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
_ = try zld.initSection("__TEXT", "__unwind_info", .{});
}
- try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(self.exec_atoms.items.len)));
-
const unwind_records = self.getUnwindRecords();
+ try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(unwind_records.len)));
+
const needs_eh_frame = for (unwind_records) |record| {
if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true;
} else false;
@@ -844,8 +843,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
if (target.getFile() != object_id) {
self.unwind_relocs_lookup[record_id].dead = true;
} else {
- const atom_index = self.getAtomIndexForSymbol(target.sym_index).?;
- self.unwind_records_lookup.putAssumeCapacityNoClobber(atom_index, @as(u32, @intCast(record_id)));
+ self.unwind_records_lookup.putAssumeCapacityNoClobber(target, @as(u32, @intCast(record_id)));
}
}
}
@@ -1012,7 +1010,13 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
Predicate{ .addr = @as(i64, @intCast(addr)) },
);
if (target_sym_index > 0) {
- return @as(u32, @intCast(lookup.start + target_sym_index - 1));
+ // Hone in on the most senior alias of the target symbol.
+ // See SymbolAtIndex.lessThan for more context.
+ var start = target_sym_index - 1;
+ while (start > 0 and
+ self.source_address_lookup[lookup.start..][start - 1] == addr) : (start -= 1)
+ {}
+ return @as(u32, @intCast(lookup.start + start));
}
}
return self.getSectionAliasSymbolIndex(sect_id);
src/link/MachO/UnwindInfo.zig
@@ -26,7 +26,7 @@ gpa: Allocator,
/// List of all unwind records gathered from all objects and sorted
/// by source function address.
records: std.ArrayListUnmanaged(macho.compact_unwind_entry) = .{},
-records_lookup: std.AutoHashMapUnmanaged(AtomIndex, RecordIndex) = .{},
+records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, RecordIndex) = .{},
/// List of all personalities referenced by either unwind info entries
/// or __eh_frame entries.
@@ -211,23 +211,22 @@ pub fn scanRelocs(zld: *Zld) !void {
for (zld.objects.items, 0..) |*object, object_id| {
const unwind_records = object.getUnwindRecords();
for (object.exec_atoms.items) |atom_index| {
- const record_id = object.unwind_records_lookup.get(atom_index) orelse continue;
- if (object.unwind_relocs_lookup[record_id].dead) continue;
- const record = unwind_records[record_id];
- if (!UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
- if (getPersonalityFunctionReloc(
- zld,
- @as(u32, @intCast(object_id)),
- record_id,
- )) |rel| {
- // Personality function; add GOT pointer.
- const target = Atom.parseRelocTarget(zld, .{
- .object_id = @as(u32, @intCast(object_id)),
- .rel = rel,
- .code = mem.asBytes(&record),
- .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
- });
- try Atom.addGotEntry(zld, target);
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+ while (inner_syms_it.next()) |sym| {
+ const record_id = object.unwind_records_lookup.get(sym) orelse continue;
+ if (object.unwind_relocs_lookup[record_id].dead) continue;
+ const record = unwind_records[record_id];
+ if (!UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
+ if (getPersonalityFunctionReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| {
+ // Personality function; add GOT pointer.
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = @as(u32, @intCast(object_id)),
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
+ });
+ try Atom.addGotEntry(zld, target);
+ }
}
}
}
@@ -242,8 +241,8 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
var records = std.ArrayList(macho.compact_unwind_entry).init(info.gpa);
defer records.deinit();
- var atom_indexes = std.ArrayList(AtomIndex).init(info.gpa);
- defer atom_indexes.deinit();
+ var sym_indexes = std.ArrayList(SymbolWithLoc).init(info.gpa);
+ defer sym_indexes.deinit();
// TODO handle dead stripping
for (zld.objects.items, 0..) |*object, object_id| {
@@ -253,80 +252,101 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
// Contents of unwind records does not have to cover all symbol in executable section
// so we need insert them ourselves.
try records.ensureUnusedCapacity(object.exec_atoms.items.len);
- try atom_indexes.ensureUnusedCapacity(object.exec_atoms.items.len);
+ try sym_indexes.ensureUnusedCapacity(object.exec_atoms.items.len);
for (object.exec_atoms.items) |atom_index| {
- var record = if (object.unwind_records_lookup.get(atom_index)) |record_id| blk: {
- if (object.unwind_relocs_lookup[record_id].dead) continue;
- var record = unwind_records[record_id];
+ var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
+ var prev_symbol: ?SymbolWithLoc = null;
+ while (inner_syms_it.next()) |symbol| {
+ var record = if (object.unwind_records_lookup.get(symbol)) |record_id| blk: {
+ if (object.unwind_relocs_lookup[record_id].dead) continue;
+ var record = unwind_records[record_id];
+
+ if (UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
+ try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), symbol, &record);
+ } else {
+ if (getPersonalityFunctionReloc(
+ zld,
+ @as(u32, @intCast(object_id)),
+ record_id,
+ )) |rel| {
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = @as(u32, @intCast(object_id)),
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
+ });
+ const personality_index = info.getPersonalityFunction(target) orelse inner: {
+ const personality_index = info.personalities_count;
+ info.personalities[personality_index] = target;
+ info.personalities_count += 1;
+ break :inner personality_index;
+ };
+
+ record.personalityFunction = personality_index + 1;
+ UnwindEncoding.setPersonalityIndex(&record.compactUnwindEncoding, personality_index + 1);
+ }
- if (UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) {
- try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), atom_index, &record);
- } else {
- if (getPersonalityFunctionReloc(
- zld,
- @as(u32, @intCast(object_id)),
- record_id,
- )) |rel| {
- const target = Atom.parseRelocTarget(zld, .{
- .object_id = @as(u32, @intCast(object_id)),
- .rel = rel,
- .code = mem.asBytes(&record),
- .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
- });
- const personality_index = info.getPersonalityFunction(target) orelse inner: {
- const personality_index = info.personalities_count;
- info.personalities[personality_index] = target;
- info.personalities_count += 1;
- break :inner personality_index;
- };
-
- record.personalityFunction = personality_index + 1;
- UnwindEncoding.setPersonalityIndex(&record.compactUnwindEncoding, personality_index + 1);
+ if (getLsdaReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| {
+ const target = Atom.parseRelocTarget(zld, .{
+ .object_id = @as(u32, @intCast(object_id)),
+ .rel = rel,
+ .code = mem.asBytes(&record),
+ .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
+ });
+ record.lsda = @as(u64, @bitCast(target));
+ }
}
-
- if (getLsdaReloc(zld, @as(u32, @intCast(object_id)), record_id)) |rel| {
- const target = Atom.parseRelocTarget(zld, .{
- .object_id = @as(u32, @intCast(object_id)),
- .rel = rel,
- .code = mem.asBytes(&record),
- .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
- });
- record.lsda = @as(u64, @bitCast(target));
+ break :blk record;
+ } else blk: {
+ const sym = zld.getSymbol(symbol);
+ if (sym.n_desc == N_DEAD) continue;
+ if (prev_symbol) |prev_sym| {
+ const prev_addr = object.getSourceSymbol(prev_sym.sym_index).?.n_value;
+ const curr_addr = object.getSourceSymbol(symbol.sym_index).?.n_value;
+ if (prev_addr == curr_addr) continue;
}
- }
- break :blk record;
- } else blk: {
- const atom = zld.getAtom(atom_index);
- const sym = zld.getSymbol(atom.getSymbolWithLoc());
- if (sym.n_desc == N_DEAD) continue;
-
- if (!object.hasUnwindRecords()) {
- if (object.eh_frame_records_lookup.get(atom_index)) |fde_offset| {
- if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
- var record = nullRecord();
- try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), atom_index, &record);
- switch (cpu_arch) {
- .aarch64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_ARM64_MODE.DWARF),
- .x86_64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_X86_64_MODE.DWARF),
- else => unreachable,
+
+ if (!object.hasUnwindRecords()) {
+ if (object.eh_frame_records_lookup.get(symbol)) |fde_offset| {
+ if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue;
+ var record = nullRecord();
+ try info.collectPersonalityFromDwarf(zld, @as(u32, @intCast(object_id)), symbol, &record);
+ switch (cpu_arch) {
+ .aarch64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_ARM64_MODE.DWARF),
+ .x86_64 => UnwindEncoding.setMode(&record.compactUnwindEncoding, macho.UNWIND_X86_64_MODE.DWARF),
+ else => unreachable,
+ }
+ break :blk record;
}
- break :blk record;
}
- }
-
- break :blk nullRecord();
- };
- const atom = zld.getAtom(atom_index);
- const sym_loc = atom.getSymbolWithLoc();
- const sym = zld.getSymbol(sym_loc);
- assert(sym.n_desc != N_DEAD);
- record.rangeStart = sym.n_value;
- record.rangeLength = @as(u32, @intCast(atom.size));
+ break :blk nullRecord();
+ };
- records.appendAssumeCapacity(record);
- atom_indexes.appendAssumeCapacity(atom_index);
+ const atom = zld.getAtom(atom_index);
+ const sym = zld.getSymbol(symbol);
+ assert(sym.n_desc != N_DEAD);
+ const size = if (inner_syms_it.next()) |next_sym| blk: {
+ // All this trouble to account for symbol aliases.
+ // TODO I think that remodelling the linker so that a Symbol references an Atom
+ // is the way to go, kinda like we do for ELF. We might also want to perhaps tag
+ // symbol aliases somehow so that they are excluded from everything except relocation
+ // resolution.
+ defer inner_syms_it.pos -= 1;
+ const curr_addr = object.getSourceSymbol(symbol.sym_index).?.n_value;
+ const next_addr = object.getSourceSymbol(next_sym.sym_index).?.n_value;
+ if (next_addr > curr_addr) break :blk next_addr - curr_addr;
+ break :blk zld.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value;
+ } else zld.getSymbol(atom.getSymbolWithLoc()).n_value + atom.size - sym.n_value;
+ record.rangeStart = sym.n_value;
+ record.rangeLength = @as(u32, @intCast(size));
+
+ try records.append(record);
+ try sym_indexes.append(symbol);
+
+ prev_symbol = symbol;
+ }
}
}
@@ -339,7 +359,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
// Fold records
try info.records.ensureTotalCapacity(info.gpa, records.items.len);
- try info.records_lookup.ensureTotalCapacity(info.gpa, @as(u32, @intCast(atom_indexes.items.len)));
+ try info.records_lookup.ensureTotalCapacity(info.gpa, @as(u32, @intCast(sym_indexes.items.len)));
var maybe_prev: ?macho.compact_unwind_entry = null;
for (records.items, 0..) |record, i| {
@@ -365,7 +385,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
break :blk record_id;
}
};
- info.records_lookup.putAssumeCapacityNoClobber(atom_indexes.items[i], record_id);
+ info.records_lookup.putAssumeCapacityNoClobber(sym_indexes.items[i], record_id);
}
// Calculate common encodings
@@ -501,12 +521,12 @@ fn collectPersonalityFromDwarf(
info: *UnwindInfo,
zld: *Zld,
object_id: u32,
- atom_index: u32,
+ sym_loc: SymbolWithLoc,
record: *macho.compact_unwind_entry,
) !void {
const object = &zld.objects.items[object_id];
var it = object.getEhFrameRecordsIterator();
- const fde_offset = object.eh_frame_records_lookup.get(atom_index).?;
+ const fde_offset = object.eh_frame_records_lookup.get(sym_loc).?;
it.seekTo(fde_offset);
const fde = (try it.next()).?;
const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
src/link/MachO/zld.zig
@@ -1492,6 +1492,42 @@ pub const Zld = struct {
try thunks.createThunks(self, @as(u8, @intCast(sect_id)));
}
}
+
+ // Update offsets of all symbols contained within each Atom.
+ // We need to do this since our unwind info synthesiser relies on
+ // traversing the symbols when synthesising unwind info and DWARF CFI records.
+ for (slice.items(.first_atom_index)) |first_atom_index| {
+ if (first_atom_index == 0) continue;
+ var atom_index = first_atom_index;
+
+ while (true) {
+ const atom = self.getAtom(atom_index);
+ const sym = self.getSymbol(atom.getSymbolWithLoc());
+
+ if (atom.getFile() != null) {
+ // Update each symbol contained within the atom
+ var it = Atom.getInnerSymbolsIterator(self, atom_index);
+ while (it.next()) |sym_loc| {
+ const inner_sym = self.getSymbolPtr(sym_loc);
+ inner_sym.n_value = sym.n_value + Atom.calcInnerSymbolOffset(
+ self,
+ atom_index,
+ sym_loc.sym_index,
+ );
+ }
+
+ // If there is a section alias, update it now too
+ if (Atom.getSectionAlias(self, atom_index)) |sym_loc| {
+ const alias = self.getSymbolPtr(sym_loc);
+ alias.n_value = sym.n_value;
+ }
+ }
+
+ if (atom.next_index) |next_index| {
+ atom_index = next_index;
+ } else break;
+ }
+ }
}
fn allocateSegments(self: *Zld) !void {
src/link/MachO/ZldAtom.zig
@@ -84,14 +84,14 @@ pub inline fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
const InnerSymIterator = struct {
sym_index: u32,
- count: u32,
+ nsyms: u32,
file: u32,
+ pos: u32 = 0,
pub fn next(it: *@This()) ?SymbolWithLoc {
- if (it.count == 0) return null;
- const res = SymbolWithLoc{ .sym_index = it.sym_index, .file = it.file };
- it.sym_index += 1;
- it.count -= 1;
+ if (it.pos == it.nsyms) return null;
+ const res = SymbolWithLoc{ .sym_index = it.sym_index + it.pos, .file = it.file };
+ it.pos += 1;
return res;
}
};
@@ -103,7 +103,7 @@ pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: AtomIndex) InnerSymIterato
assert(atom.getFile() != null);
return .{
.sym_index = atom.inner_sym_index,
- .count = atom.inner_nsyms_trailing,
+ .nsyms = atom.inner_nsyms_trailing,
.file = atom.file,
};
}
@@ -228,11 +228,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
// Find containing atom
log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id });
- const candidate = object.getSymbolByAddress(address_in_section, sect_id);
- // Make sure we are not dealing with a local alias.
- const atom_index = object.getAtomIndexForSymbol(candidate) orelse break :sym_index candidate;
- const atom = zld.getAtom(atom_index);
- break :sym_index atom.sym_index;
+ break :sym_index object.getSymbolByAddress(address_in_section, sect_id);
} else object.reverse_symtab_lookup[ctx.rel.r_symbolnum];
const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };