commit eaa3a4299bab65fa011a4c818d971ebb9eda236c (tree)
parent 4f16e80ceadc19c50c5be67dd9cc2c2f9aa4beb8
Author: Vadym Prodan <vprodan@proton.me>
Date: Mon, 12 Jan 2026 23:42:25 +0100
link/MachO: enhance unwind info size calculation and add page size handling
Diffstat:
1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig
@@ -255,6 +255,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
page.kind = .compressed;
}
+ page.size = page.calcSize();
+
log.debug("{f}", .{page.fmt(info.*)});
try info.pages.append(gpa, page);
@@ -285,7 +287,9 @@ pub fn calcSize(info: UnwindInfo) usize {
total_size += @as(usize, @intCast(info.personalities_count)) * @sizeOf(u32);
total_size += (info.pages.items.len + 1) * @sizeOf(macho.unwind_info_section_header_index_entry);
total_size += info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry);
- total_size += info.pages.items.len * second_level_page_bytes;
+ for (info.pages.items) |page| {
+ total_size += page.size;
+ }
return total_size;
}
@@ -318,18 +322,27 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
}
- const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));
+ // Calculate total size of all pages
+ var total_pages_size: u32 = 0;
+ for (info.pages.items) |page| {
+ total_pages_size += page.size;
+ }
+
+ const pages_base_offset = @as(u32, @intCast(header.size - total_pages_size));
const lsda_base_offset = @as(u32, @intCast(pages_base_offset -
(info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry))));
- for (info.pages.items, 0..) |page, i| {
+
+ var page_offset: u32 = pages_base_offset;
+ for (info.pages.items) |page| {
assert(page.count > 0);
const rec = info.records.items[page.start].getUnwindRecord(macho_file);
try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
.functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
- .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
+ .secondLevelPagesSectionOffset = page_offset,
.lsdaIndexArraySectionOffset = lsda_base_offset +
info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
}), .little);
+ page_offset += page.size;
}
const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
@@ -350,16 +363,10 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
}
for (info.pages.items) |page| {
- const start = writer.end;
try page.write(info, macho_file, &writer);
- const nwritten = writer.end - start;
- if (nwritten < second_level_page_bytes) {
- const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
- try writer.splatByteAll(0, padding);
- }
}
- @memset(buffer[writer.end..], 0);
+ assert(writer.end == header.size);
}
fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
@@ -567,6 +574,7 @@ const Page = struct {
count: u16,
page_encodings: [max_compact_encodings]Encoding = undefined,
page_encodings_count: u9 = 0,
+ size: u32 = 0,
fn appendPageEncoding(page: *Page, enc: Encoding) void {
assert(page.page_encodings_count <= max_compact_encodings);
@@ -585,6 +593,16 @@ const Page = struct {
return null;
}
+ fn calcSize(page: Page) u32 {
+ return switch (page.kind) {
+ .regular => @sizeOf(macho.unwind_info_regular_second_level_page_header) +
+ @as(u32, page.count) * @sizeOf(macho.unwind_info_regular_second_level_entry),
+ .compressed => @sizeOf(macho.unwind_info_compressed_second_level_page_header) +
+ @as(u32, page.page_encodings_count) * @sizeOf(u32) +
+ @as(u32, page.count) * @sizeOf(u32),
+ };
+ }
+
const Format = struct {
page: Page,
info: UnwindInfo,