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