| author | |
| committer | |
| log | 7e4c386f6ab5546898b94d80f54e88d45dc6c7b9 |
| tree | a856f1921d6353ad0e0034a731d3b39c817fdea9 |
| parent | f1267e02c49f5d571420d687a6337a85ab76767d |
| parent | e835b864e8e5d2ff33b9f59f9f65c74f86093dfc |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30768
Reviewed-by: Andrew Kelley <andrew@ziglang.org>4 files changed, 58 insertions(+), 14 deletions(-)
src/link/MachO.zig+3-1| ... | @@ -1707,7 +1707,9 @@ fn initSyntheticSections(self: *MachO) !void { | ... | @@ -1707,7 +1707,9 @@ fn initSyntheticSections(self: *MachO) !void { |
| 1707 | } else false; | 1707 | } else false; |
| 1708 | if (needs_eh_frame) { | 1708 | if (needs_eh_frame) { |
| 1709 | assert(needs_unwind_info); | 1709 | assert(needs_unwind_info); |
| 1710 | self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{}); | 1710 | self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{ |
| 1711 | .flags = macho.S_COALESCED | macho.S_ATTR_NO_TOC | macho.S_ATTR_STRIP_STATIC_SYMS | macho.S_ATTR_LIVE_SUPPORT, | ||
| 1712 | }); | ||
| 1711 | } | 1713 | } |
| 1712 | 1714 | ||
| 1713 | if (self.getInternalObject()) |obj| { | 1715 | if (self.getInternalObject()) |obj| { |
src/link/MachO/Object.zig+45-9| ... | @@ -1298,10 +1298,18 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target. | ... | @@ -1298,10 +1298,18 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target. |
| 1298 | superposition.getPtr(addr).?.cu = rec_index; | 1298 | superposition.getPtr(addr).?.cu = rec_index; |
| 1299 | } | 1299 | } |
| 1300 | 1300 | ||
| 1301 | const FdeRange = struct { start: u64, end: u64 }; | ||
| 1302 | var fde_ranges = try std.ArrayList(FdeRange).initCapacity(allocator, self.fdes.items.len); | ||
| 1303 | defer fde_ranges.deinit(allocator); | ||
| 1304 | |||
| 1301 | for (self.fdes.items, 0..) |fde, fde_index| { | 1305 | for (self.fdes.items, 0..) |fde, fde_index| { |
| 1302 | const atom = fde.getAtom(macho_file); | 1306 | const atom = fde.getAtom(macho_file); |
| 1303 | const addr = atom.getInputAddress(macho_file) + fde.atom_offset; | 1307 | const addr = atom.getInputAddress(macho_file) + fde.atom_offset; |
| 1304 | superposition.getPtr(addr).?.fde = @intCast(fde_index); | 1308 | superposition.getPtr(addr).?.fde = @intCast(fde_index); |
| 1309 | |||
| 1310 | // Build FDE range for coverage check | ||
| 1311 | const pc_range = fde.pc_range; | ||
| 1312 | fde_ranges.appendAssumeCapacity(.{ .start = addr, .end = addr + pc_range }); | ||
| 1305 | } | 1313 | } |
| 1306 | 1314 | ||
| 1307 | for (superposition.keys(), superposition.values()) |addr, meta| { | 1315 | for (superposition.keys(), superposition.values()) |addr, meta| { |
| ... | @@ -1333,15 +1341,43 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target. | ... | @@ -1333,15 +1341,43 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target. |
| 1333 | } | 1341 | } |
| 1334 | } | 1342 | } |
| 1335 | } else if (meta.cu == null and meta.fde == null) { | 1343 | } else if (meta.cu == null and meta.fde == null) { |
| 1336 | // Create a null record | 1344 | // Check if this address is covered by an existing FDE. |
| 1337 | const rec_index = try self.addUnwindRecord(allocator); | 1345 | // If so, don't create a null record - let the unwinder fall back to DWARF. |
| 1338 | const rec = self.getUnwindRecord(rec_index); | 1346 | // This is important for local labels within a function that has DWARF unwind info. |
| 1339 | const atom = self.getAtom(meta.atom).?; | 1347 | const is_covered_by_fde = blk: { |
| 1340 | try self.unwind_records_indexes.append(allocator, rec_index); | 1348 | if (fde_ranges.items.len == 0) break :blk false; |
| 1341 | rec.length = @intCast(meta.size); | 1349 | |
| 1342 | rec.atom = meta.atom; | 1350 | // Binary search: find the last FDE where start <= addr |
| 1343 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); | 1351 | var left: usize = 0; |
| 1344 | rec.file = self.index; | 1352 | var right: usize = fde_ranges.items.len; |
| 1353 | while (left < right) { | ||
| 1354 | const mid = left + (right - left) / 2; | ||
| 1355 | if (fde_ranges.items[mid].start <= addr) { | ||
| 1356 | left = mid + 1; | ||
| 1357 | } else { | ||
| 1358 | right = mid; | ||
| 1359 | } | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | // Check if the FDE before insertion point covers this address | ||
| 1363 | if (left > 0) { | ||
| 1364 | const range = fde_ranges.items[left - 1]; | ||
| 1365 | break :blk addr < range.end; | ||
| 1366 | } | ||
| 1367 | break :blk false; | ||
| 1368 | }; | ||
| 1369 | |||
| 1370 | if (!is_covered_by_fde) { | ||
| 1371 | // Create a null record only if not covered by DWARF | ||
| 1372 | const rec_index = try self.addUnwindRecord(allocator); | ||
| 1373 | const rec = self.getUnwindRecord(rec_index); | ||
| 1374 | const atom = self.getAtom(meta.atom).?; | ||
| 1375 | try self.unwind_records_indexes.append(allocator, rec_index); | ||
| 1376 | rec.length = @intCast(meta.size); | ||
| 1377 | rec.atom = meta.atom; | ||
| 1378 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); | ||
| 1379 | rec.file = self.index; | ||
| 1380 | } | ||
| 1345 | } | 1381 | } |
| 1346 | } | 1382 | } |
| 1347 | 1383 |
src/link/MachO/eh_frame.zig+7-3| ... | @@ -116,6 +116,7 @@ pub const Fde = struct { | ... | @@ -116,6 +116,7 @@ pub const Fde = struct { |
| 116 | cie: Cie.Index, | 116 | cie: Cie.Index, |
| 117 | atom: Atom.Index = 0, | 117 | atom: Atom.Index = 0, |
| 118 | atom_offset: u32 = 0, | 118 | atom_offset: u32 = 0, |
| 119 | pc_range: u64 = 0, | ||
| 119 | lsda: Atom.Index = 0, | 120 | lsda: Atom.Index = 0, |
| 120 | lsda_offset: u32 = 0, | 121 | lsda_offset: u32 = 0, |
| 121 | lsda_ptr_offset: u32 = 0, | 122 | lsda_ptr_offset: u32 = 0, |
| ... | @@ -142,6 +143,9 @@ pub const Fde = struct { | ... | @@ -142,6 +143,9 @@ pub const Fde = struct { |
| 142 | const atom = fde.getAtom(macho_file); | 143 | const atom = fde.getAtom(macho_file); |
| 143 | fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file)); | 144 | fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file)); |
| 144 | 145 | ||
| 146 | // Parse pc_range (function size) | ||
| 147 | fde.pc_range = std.mem.readInt(u64, data[16..][0..8], .little); | ||
| 148 | |||
| 145 | // Associate with a CIE | 149 | // Associate with a CIE |
| 146 | const cie_ptr = std.mem.readInt(u32, data[4..8], .little); | 150 | const cie_ptr = std.mem.readInt(u32, data[4..8], .little); |
| 147 | const cie_offset = fde.offset + 4 - cie_ptr; | 151 | const cie_offset = fde.offset + 4 - cie_ptr; |
| ... | @@ -350,7 +354,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { | ... | @@ -350,7 +354,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { |
| 350 | std.mem.writeInt( | 354 | std.mem.writeInt( |
| 351 | i32, | 355 | i32, |
| 352 | buffer[offset..][0..4], | 356 | buffer[offset..][0..4], |
| 353 | @intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)) + addend), | 357 | @intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr))), |
| 354 | .little, | 358 | .little, |
| 355 | ); | 359 | ); |
| 356 | } | 360 | } |
| ... | @@ -373,7 +377,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { | ... | @@ -373,7 +377,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { |
| 373 | { | 377 | { |
| 374 | const offset = fde.out_offset + 8; | 378 | const offset = fde.out_offset + 8; |
| 375 | const saddr = sect.addr + offset; | 379 | const saddr = sect.addr + offset; |
| 376 | const taddr = fde.getAtom(macho_file).getAddress(macho_file); | 380 | const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset; |
| 377 | std.mem.writeInt( | 381 | std.mem.writeInt( |
| 378 | i64, | 382 | i64, |
| 379 | buffer[offset..][0..8], | 383 | buffer[offset..][0..8], |
| ... | @@ -460,7 +464,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_in | ... | @@ -460,7 +464,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_in |
| 460 | { | 464 | { |
| 461 | const offset = fde.out_offset + 8; | 465 | const offset = fde.out_offset + 8; |
| 462 | const saddr = sect.addr + offset; | 466 | const saddr = sect.addr + offset; |
| 463 | const taddr = fde.getAtom(macho_file).getAddress(macho_file); | 467 | const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset; |
| 464 | std.mem.writeInt( | 468 | std.mem.writeInt( |
| 465 | i64, | 469 | i64, |
| 466 | code[offset..][0..8], | 470 | code[offset..][0..8], |
src/link/MachO/relocatable.zig+3-1| ... | @@ -289,7 +289,9 @@ fn initOutputSections(macho_file: *MachO) !void { | ... | @@ -289,7 +289,9 @@ fn initOutputSections(macho_file: *MachO) !void { |
| 289 | } else false; | 289 | } else false; |
| 290 | if (needs_eh_frame) { | 290 | if (needs_eh_frame) { |
| 291 | assert(needs_unwind_info); | 291 | assert(needs_unwind_info); |
| 292 | macho_file.eh_frame_sect_index = try macho_file.addSection("__TEXT", "__eh_frame", .{}); | 292 | macho_file.eh_frame_sect_index = try macho_file.addSection("__TEXT", "__eh_frame", .{ |
| 293 | .flags = std.macho.S_COALESCED | std.macho.S_ATTR_NO_TOC | std.macho.S_ATTR_STRIP_STATIC_SYMS | std.macho.S_ATTR_LIVE_SUPPORT, | ||
| 294 | }); | ||
| 293 | } | 295 | } |
| 294 | } | 296 | } |
| 295 | 297 |