mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #16656 from ziglang/issue-16628
macho: track unwind/dwarf cfi records by symbol rather than atom
This commit is contained in:
commit
e85a46cb84
11 changed files with 515 additions and 324 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)), 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;
|
||||
};
|
||||
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 (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 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,
|
||||
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));
|
||||
}
|
||||
break :blk record;
|
||||
}
|
||||
}
|
||||
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 nullRecord();
|
||||
};
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
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);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
|
||||
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;
|
||||
if (!object.hasUnwindRecords()) {
|
||||
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;
|
||||
}
|
||||
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
var inner_syms_it = Atom.getInnerSymbolsIterator(zld, atom_index);
|
||||
|
||||
const fde_offset = object.eh_frame_records_lookup.get(atom_index).?;
|
||||
it.seekTo(fde_offset);
|
||||
const fde = (try it.next()).?;
|
||||
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()).?;
|
||||
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,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -458,8 +465,8 @@ fn prune(zld: *Zld, alive: AtomTable) void {
|
|||
section.last_atom_index = prev_index;
|
||||
} else {
|
||||
assert(section.header.size == 0);
|
||||
section.first_atom_index = undefined;
|
||||
section.last_atom_index = undefined;
|
||||
section.first_atom_index = 0;
|
||||
section.last_atom_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()).?;
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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(atom_index) orelse continue;
|
||||
const record = unwind_info.records.items[record_id];
|
||||
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;
|
||||
// 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()).?;
|
||||
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 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;
|
||||
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(atom_index) orelse continue;
|
||||
const record = &unwind_info.records.items[record_id];
|
||||
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;
|
||||
// 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()).?;
|
||||
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 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,
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*);
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
// 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,
|
||||
|
||||
// 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)),
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
eh_frame_offset += fde_record.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ pub const cases = [_]Case{
|
|||
.build_root = "test/link/macho/bugs/16308",
|
||||
.import = @import("link/macho/bugs/16308/build.zig"),
|
||||
},
|
||||
.{
|
||||
.build_root = "test/link/macho/bugs/16628",
|
||||
.import = @import("link/macho/bugs/16628/build.zig"),
|
||||
},
|
||||
.{
|
||||
.build_root = "test/link/macho/dead_strip",
|
||||
.import = @import("link/macho/dead_strip/build.zig"),
|
||||
|
|
|
|||
37
test/link/macho/bugs/16628/a_arm64.s
Normal file
37
test/link/macho/bugs/16628/a_arm64.s
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
.globl _foo
|
||||
.align 4
|
||||
_foo:
|
||||
.cfi_startproc
|
||||
stp x29, x30, [sp, #-32]!
|
||||
.cfi_def_cfa_offset 32
|
||||
.cfi_offset w30, -24
|
||||
.cfi_offset w29, -32
|
||||
mov x29, sp
|
||||
.cfi_def_cfa w29, 32
|
||||
bl _bar
|
||||
ldp x29, x30, [sp], #32
|
||||
.cfi_restore w29
|
||||
.cfi_restore w30
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.globl _bar
|
||||
.align 4
|
||||
_bar:
|
||||
.cfi_startproc
|
||||
sub sp, sp, #32
|
||||
.cfi_def_cfa_offset -32
|
||||
stp x29, x30, [sp, #16]
|
||||
.cfi_offset w30, -24
|
||||
.cfi_offset w29, -32
|
||||
mov x29, sp
|
||||
.cfi_def_cfa w29, 32
|
||||
mov w0, #4
|
||||
ldp x29, x30, [sp, #16]
|
||||
.cfi_restore w29
|
||||
.cfi_restore w30
|
||||
add sp, sp, #32
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
29
test/link/macho/bugs/16628/a_x64.s
Normal file
29
test/link/macho/bugs/16628/a_x64.s
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
.globl _foo
|
||||
_foo:
|
||||
.cfi_startproc
|
||||
push %rbp
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_offset %rbp, -8
|
||||
mov %rsp, %rbp
|
||||
.cfi_def_cfa_register %rbp
|
||||
call _bar
|
||||
pop %rbp
|
||||
.cfi_restore %rbp
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
.globl _bar
|
||||
_bar:
|
||||
.cfi_startproc
|
||||
push %rbp
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_offset %rbp, -8
|
||||
mov %rsp, %rbp
|
||||
.cfi_def_cfa_register %rbp
|
||||
mov $4, %rax
|
||||
pop %rbp
|
||||
.cfi_restore %rbp
|
||||
.cfi_def_cfa_offset 0
|
||||
ret
|
||||
.cfi_endproc
|
||||
42
test/link/macho/bugs/16628/build.zig
Normal file
42
test/link/macho/bugs/16628/build.zig
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub const requires_symlinks = true;
|
||||
pub const requires_macos_sdk = false;
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const test_step = b.step("test", "Test it");
|
||||
b.default_step = test_step;
|
||||
|
||||
add(b, test_step, .Debug);
|
||||
add(b, test_step, .ReleaseFast);
|
||||
add(b, test_step, .ReleaseSmall);
|
||||
add(b, test_step, .ReleaseSafe);
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const target: std.zig.CrossTarget = .{ .os_tag = .macos };
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "test",
|
||||
.optimize = optimize,
|
||||
.target = target,
|
||||
});
|
||||
exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} });
|
||||
switch (builtin.cpu.arch) {
|
||||
.aarch64 => {
|
||||
exe.addCSourceFile(.{ .file = .{ .path = "a_arm64.s" }, .flags = &[0][]const u8{} });
|
||||
},
|
||||
.x86_64 => {
|
||||
exe.addCSourceFile(.{ .file = .{ .path = "a_x64.s" }, .flags = &[0][]const u8{} });
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
exe.linkLibC();
|
||||
|
||||
const run = b.addRunArtifact(exe);
|
||||
run.skip_foreign_checks = true;
|
||||
run.expectStdOutEqual("4\n");
|
||||
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
8
test/link/macho/bugs/16628/main.c
Normal file
8
test/link/macho/bugs/16628/main.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int foo();
|
||||
|
||||
int main() {
|
||||
printf("%d\n", foo());
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue