authorgravatar for vprodan@proton.meVadym Prodan <vprodan@proton.me> 2026-01-12 23:42:25+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-15 19:45:17+01:00
logeaa3a4299bab65fa011a4c818d971ebb9eda236c
tree9b5892de7c7f8cfbb2ce3ef480549fd614d1e7e4
parent4f16e80ceadc19c50c5be67dd9cc2c2f9aa4beb8

link/MachO: enhance unwind info size calculation and add page size handling


1 files changed, 29 insertions(+), 11 deletions(-)

src/link/MachO/UnwindInfo.zig+29-11
......@@ -255,6 +255,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
255255 page.kind = .compressed;
256256 }
257257
258 page.size = page.calcSize();
259
258260 log.debug("{f}", .{page.fmt(info.*)});
259261
260262 try info.pages.append(gpa, page);
......@@ -285,7 +287,9 @@ pub fn calcSize(info: UnwindInfo) usize {
285287 total_size += @as(usize, @intCast(info.personalities_count)) * @sizeOf(u32);
286288 total_size += (info.pages.items.len + 1) * @sizeOf(macho.unwind_info_section_header_index_entry);
287289 total_size += info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry);
288 total_size += info.pages.items.len * second_level_page_bytes;
290 for (info.pages.items) |page| {
291 total_size += page.size;
292 }
289293 return total_size;
290294}
291295
......@@ -318,18 +322,27 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
318322 try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
319323 }
320324
321 const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));
325 // Calculate total size of all pages
326 var total_pages_size: u32 = 0;
327 for (info.pages.items) |page| {
328 total_pages_size += page.size;
329 }
330
331 const pages_base_offset = @as(u32, @intCast(header.size - total_pages_size));
322332 const lsda_base_offset = @as(u32, @intCast(pages_base_offset -
323333 (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry))));
324 for (info.pages.items, 0..) |page, i| {
334
335 var page_offset: u32 = pages_base_offset;
336 for (info.pages.items) |page| {
325337 assert(page.count > 0);
326338 const rec = info.records.items[page.start].getUnwindRecord(macho_file);
327339 try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
328340 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
329 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
341 .secondLevelPagesSectionOffset = page_offset,
330342 .lsdaIndexArraySectionOffset = lsda_base_offset +
331343 info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
332344 }), .little);
345 page_offset += page.size;
333346 }
334347
335348 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 {
350363 }
351364
352365 for (info.pages.items) |page| {
353 const start = writer.end;
354366 try page.write(info, macho_file, &writer);
355 const nwritten = writer.end - start;
356 if (nwritten < second_level_page_bytes) {
357 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
358 try writer.splatByteAll(0, padding);
359 }
360367 }
361368
362 @memset(buffer[writer.end..], 0);
369 assert(writer.end == header.size);
363370}
364371
365372fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
......@@ -567,6 +574,7 @@ const Page = struct {
567574 count: u16,
568575 page_encodings: [max_compact_encodings]Encoding = undefined,
569576 page_encodings_count: u9 = 0,
577 size: u32 = 0,
570578
571579 fn appendPageEncoding(page: *Page, enc: Encoding) void {
572580 assert(page.page_encodings_count <= max_compact_encodings);
......@@ -585,6 +593,16 @@ const Page = struct {
585593 return null;
586594 }
587595
596 fn calcSize(page: Page) u32 {
597 return switch (page.kind) {
598 .regular => @sizeOf(macho.unwind_info_regular_second_level_page_header) +
599 @as(u32, page.count) * @sizeOf(macho.unwind_info_regular_second_level_entry),
600 .compressed => @sizeOf(macho.unwind_info_compressed_second_level_page_header) +
601 @as(u32, page.page_encodings_count) * @sizeOf(u32) +
602 @as(u32, page.count) * @sizeOf(u32),
603 };
604 }
605
588606 const Format = struct {
589607 page: Page,
590608 info: UnwindInfo,