authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-02 22:28:02-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-08-02 22:28:02-07:00
loge85a46cb84c80a7a97316f066b77e45649ce97fb
tree5209cbbcaa201fde6b74bc3f89eda77174be7d02
parenta61495a988c9e1a68ee595cafab5025a314f0e40
parent26adbf2cb7377730b63a0ef182a402060eb732d3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16656 from ziglang/issue-16628

macho: track unwind/dwarf cfi records by symbol rather than atom

11 files changed, 525 insertions(+), 334 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) = .{},
7575
76eh_frame_sect_id: ?u8 = null,76eh_frame_sect_id: ?u8 = null,
77eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},77eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},
78eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(AtomIndex, u32) = .{},78eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{},
7979
80unwind_info_sect_id: ?u8 = null,80unwind_info_sect_id: ?u8 = null,
81unwind_relocs_lookup: []Record = undefined,81unwind_relocs_lookup: []Record = undefined,
82unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},82unwind_records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
8383
84const Entry = struct {84const 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 }
283283
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;
526526
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 }
804803
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();
808805
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 sorted26/// List of all unwind records gathered from all objects and sorted
27/// by source function address.27/// by source function address.
28records: std.ArrayListUnmanaged(macho.compact_unwind_entry) = .{},28records: std.ArrayListUnmanaged(macho.compact_unwind_entry) = .{},
29records_lookup: std.AutoHashMapUnmanaged(AtomIndex, RecordIndex) = .{},29records_lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, RecordIndex) = .{},
3030
31/// List of all personalities referenced by either unwind info entries31/// 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();
244243
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();
247246
248 // TODO handle dead stripping247 // 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 section252 // 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);
257256
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 }
262289
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 }
287300 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);
303315 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 };
320323
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));
327326
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 }
332352
...@@ -339,7 +359,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {...@@ -339,7 +359,7 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
339359
340 // Fold records360 // 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)));
343363
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 }
370390
371 // Calculate common encodings391 // 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 {
8484
85const InnerSymIterator = struct {85const 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,
8990
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 {
228228
229 // Find containing atom229 // 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];
237233
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+103-96
...@@ -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();
295295
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 marked302 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 }
311313
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 do315 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 }
322325
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}
356360
357fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *AtomTable) !void {361fn 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();
361365 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
365369 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;
370374 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 record377 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) orelse406 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 live418 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}
...@@ -458,8 +465,8 @@ fn prune(zld: *Zld, alive: AtomTable) void {...@@ -458,8 +465,8 @@ fn prune(zld: *Zld, alive: AtomTable) void {
458 section.last_atom_index = prev_index;465 section.last_atom_index = prev_index;
459 } else {466 } else {
460 assert(section.header.size == 0);467 assert(section.header.size == 0);
461 section.first_atom_index = undefined;468 section.first_atom_index = 0;
462 section.last_atom_index = undefined;469 section.last_atom_index = 0;
463 }470 }
464 }471 }
465472
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();
2525
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;
3131 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
3434 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();
6063
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| {
6467 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
6770 const record_id = unwind_info.records_lookup.get(sym) orelse continue;
68 // TODO skip this check if no __compact_unwind is present71 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
7174 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
7477 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 }
7790
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 }
8994
90 sect.size = size;95 sect.size = size;
96 }
91}97}
9298
93pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {99pub 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();
119125
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| {
123129 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
126132 const record_id = unwind_info.records_lookup.get(target) orelse continue;
127 // TODO skip this check if no __compact_unwind is present133 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
130136 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
133139 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 }
136159
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 });
170167
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 }
191177
192 eh_records.putAssumeCapacityNoClobber(eh_frame_offset, fde_record);178 // We need to parse LSDA pointer and relocate ourselves.
193179 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,
199185 .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 );
210206
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 }
214222
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 }
14961532
1497 fn allocateSegments(self: *Zld) !void {1533 fn allocateSegments(self: *Zld) !void {
test/link.zig+4
...@@ -96,6 +96,10 @@ pub const cases = [_]Case{...@@ -96,6 +96,10 @@ pub const cases = [_]Case{
96 .build_root = "test/link/macho/bugs/16308",96 .build_root = "test/link/macho/bugs/16308",
97 .import = @import("link/macho/bugs/16308/build.zig"),97 .import = @import("link/macho/bugs/16308/build.zig"),
98 },98 },
99 .{
100 .build_root = "test/link/macho/bugs/16628",
101 .import = @import("link/macho/bugs/16628/build.zig"),
102 },
99 .{103 .{
100 .build_root = "test/link/macho/dead_strip",104 .build_root = "test/link/macho/dead_strip",
101 .import = @import("link/macho/dead_strip/build.zig"),105 .import = @import("link/macho/dead_strip/build.zig"),
test/link/macho/bugs/16628/a_arm64.s created+37
...@@ -0,0 +1,37 @@
1.globl _foo
2.align 4
3_foo:
4 .cfi_startproc
5 stp x29, x30, [sp, #-32]!
6 .cfi_def_cfa_offset 32
7 .cfi_offset w30, -24
8 .cfi_offset w29, -32
9 mov x29, sp
10 .cfi_def_cfa w29, 32
11 bl _bar
12 ldp x29, x30, [sp], #32
13 .cfi_restore w29
14 .cfi_restore w30
15 .cfi_def_cfa_offset 0
16 ret
17 .cfi_endproc
18
19.globl _bar
20.align 4
21_bar:
22 .cfi_startproc
23 sub sp, sp, #32
24 .cfi_def_cfa_offset -32
25 stp x29, x30, [sp, #16]
26 .cfi_offset w30, -24
27 .cfi_offset w29, -32
28 mov x29, sp
29 .cfi_def_cfa w29, 32
30 mov w0, #4
31 ldp x29, x30, [sp, #16]
32 .cfi_restore w29
33 .cfi_restore w30
34 add sp, sp, #32
35 .cfi_def_cfa_offset 0
36 ret
37 .cfi_endproc
test/link/macho/bugs/16628/a_x64.s created+29
...@@ -0,0 +1,29 @@
1.globl _foo
2_foo:
3 .cfi_startproc
4 push %rbp
5 .cfi_def_cfa_offset 8
6 .cfi_offset %rbp, -8
7 mov %rsp, %rbp
8 .cfi_def_cfa_register %rbp
9 call _bar
10 pop %rbp
11 .cfi_restore %rbp
12 .cfi_def_cfa_offset 0
13 ret
14 .cfi_endproc
15
16.globl _bar
17_bar:
18 .cfi_startproc
19 push %rbp
20 .cfi_def_cfa_offset 8
21 .cfi_offset %rbp, -8
22 mov %rsp, %rbp
23 .cfi_def_cfa_register %rbp
24 mov $4, %rax
25 pop %rbp
26 .cfi_restore %rbp
27 .cfi_def_cfa_offset 0
28 ret
29 .cfi_endproc
test/link/macho/bugs/16628/build.zig created+42
...@@ -0,0 +1,42 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4pub const requires_symlinks = true;
5pub const requires_macos_sdk = false;
6
7pub fn build(b: *std.Build) void {
8 const test_step = b.step("test", "Test it");
9 b.default_step = test_step;
10
11 add(b, test_step, .Debug);
12 add(b, test_step, .ReleaseFast);
13 add(b, test_step, .ReleaseSmall);
14 add(b, test_step, .ReleaseSafe);
15}
16
17fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
18 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
19
20 const exe = b.addExecutable(.{
21 .name = "test",
22 .optimize = optimize,
23 .target = target,
24 });
25 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} });
26 switch (builtin.cpu.arch) {
27 .aarch64 => {
28 exe.addCSourceFile(.{ .file = .{ .path = "a_arm64.s" }, .flags = &[0][]const u8{} });
29 },
30 .x86_64 => {
31 exe.addCSourceFile(.{ .file = .{ .path = "a_x64.s" }, .flags = &[0][]const u8{} });
32 },
33 else => unreachable,
34 }
35 exe.linkLibC();
36
37 const run = b.addRunArtifact(exe);
38 run.skip_foreign_checks = true;
39 run.expectStdOutEqual("4\n");
40
41 test_step.dependOn(&run.step);
42}
test/link/macho/bugs/16628/main.c created+8
...@@ -0,0 +1,8 @@
1#include <stdio.h>
2
3int foo();
4
5int main() {
6 printf("%d\n", foo());
7 return 0;
8}