authorgravatar for vshabanov88@gmail.comVladislav Shabanov <vshabanov88@gmail.com> 2026-01-15 19:48:16+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-15 19:48:16+01:00
log63f345a75afdf4f956b136c06776f109f5c567af
tree252675ac1d65d6e05bf8180146af257b0ebe4ddd
parenteaa3a4299bab65fa011a4c818d971ebb9eda236c

link.MachO: support sdata4 pointer encoding (#30846)

Fixes https://codeberg.org/ziglang/zig/issues/30669 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30846 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: Vladislav Shabanov <vshabanov88@gmail.com> Co-committed-by: Vladislav Shabanov <vshabanov88@gmail.com>

2 files changed, 129 insertions(+), 29 deletions(-)

src/link/MachO/eh_frame.zig+63-29
...@@ -3,6 +3,7 @@ pub const Cie = struct {...@@ -3,6 +3,7 @@ pub const Cie = struct {
3 offset: u32,3 offset: u32,
4 out_offset: u32 = 0,4 out_offset: u32 = 0,
5 size: u32,5 size: u32,
6 address_ptr_size: enum { p32, p64 } = .p64,
6 lsda_size: ?enum { p32, p64 } = null,7 lsda_size: ?enum { p32, p64 } = null,
7 personality: ?Personality = null,8 personality: ?Personality = null,
8 file: File.Index = 0,9 file: File.Index = 0,
...@@ -27,9 +28,15 @@ pub const Cie = struct {...@@ -27,9 +28,15 @@ pub const Cie = struct {
27 for (aug[1..]) |ch| switch (ch) {28 for (aug[1..]) |ch| switch (ch) {
28 'R' => {29 'R' => {
29 const enc: DW.EH.PE = @bitCast(try reader.takeByte());30 const enc: DW.EH.PE = @bitCast(try reader.takeByte());
30 if (enc != @as(DW.EH.PE, .{ .type = .absptr, .rel = .pcrel })) {31 if (enc.rel != .pcrel) {
31 @panic("unexpected pointer encoding"); // TODO error32 @panic("unexpected pointer encoding"); // TODO error
32 }33 }
34
35 switch (enc.type) {
36 .sdata4 => cie.address_ptr_size = .p32,
37 .absptr => cie.address_ptr_size = .p64,
38 else => @panic("unexpected pointer encoding"), // TODO error
39 }
33 },40 },
34 'P' => {41 'P' => {
35 const enc: DW.EH.PE = @bitCast(try reader.takeByte());42 const enc: DW.EH.PE = @bitCast(try reader.takeByte());
...@@ -131,21 +138,6 @@ pub const Fde = struct {...@@ -131,21 +138,6 @@ pub const Fde = struct {
131 const object = fde.getObject(macho_file);138 const object = fde.getObject(macho_file);
132 const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];139 const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];
133140
134 // Parse target atom index
135 const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
136 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
137 fde.atom = object.findAtom(taddr) orelse {
138 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
139 sect.segName(), sect.sectName(), fde.offset + 8,
140 });
141 return error.MalformedObject;
142 };
143 const atom = fde.getAtom(macho_file);
144 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
145
146 // Parse pc_range (function size)
147 fde.pc_range = std.mem.readInt(u64, data[16..][0..8], .little);
148
149 // Associate with a CIE141 // Associate with a CIE
150 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);142 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
151 const cie_offset = fde.offset + 4 - cie_ptr;143 const cie_offset = fde.offset + 4 - cie_ptr;
...@@ -163,10 +155,34 @@ pub const Fde = struct {...@@ -163,10 +155,34 @@ pub const Fde = struct {
163155
164 const cie = fde.getCie(macho_file);156 const cie = fde.getCie(macho_file);
165157
158 // Parse target atom index
159 const pc_begin = switch (cie.address_ptr_size) {
160 .p32 => std.mem.readInt(i32, data[8..][0..4], .little),
161 .p64 => std.mem.readInt(i64, data[8..][0..8], .little),
162 };
163 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
164 fde.atom = object.findAtom(taddr) orelse {
165 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
166 sect.segName(), sect.sectName(), fde.offset + 8,
167 });
168 return error.MalformedObject;
169 };
170 const atom = fde.getAtom(macho_file);
171 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
172
173 // Parse pc_range (function size)
174 fde.pc_range = switch (cie.address_ptr_size) {
175 .p32 => std.mem.readInt(u32, data[12..][0..4], .little),
176 .p64 => std.mem.readInt(u64, data[16..][0..8], .little),
177 };
178
166 // Parse LSDA atom index if any179 // Parse LSDA atom index if any
167 if (cie.lsda_size) |lsda_size| {180 if (cie.lsda_size) |lsda_size| {
168 var reader: std.Io.Reader = .fixed(data);181 var reader: std.Io.Reader = .fixed(data);
169 reader.seek = 24;182 reader.seek = switch (cie.address_ptr_size) {
183 .p32 => 16,
184 .p64 => 24,
185 };
170 _ = try reader.takeLeb128(u64); // augmentation length186 _ = try reader.takeLeb128(u64); // augmentation length
171 fde.lsda_ptr_offset = @intCast(reader.seek);187 fde.lsda_ptr_offset = @intCast(reader.seek);
172 const lsda_ptr = switch (lsda_size) {188 const lsda_ptr = switch (lsda_size) {
...@@ -378,12 +394,21 @@ pub fn write(macho_file: *MachO, buffer: []u8) void {...@@ -378,12 +394,21 @@ pub fn write(macho_file: *MachO, buffer: []u8) void {
378 const offset = fde.out_offset + 8;394 const offset = fde.out_offset + 8;
379 const saddr = sect.addr + offset;395 const saddr = sect.addr + offset;
380 const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;396 const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;
381 std.mem.writeInt(397
382 i64,398 switch (fde.getCie(macho_file).address_ptr_size) {
383 buffer[offset..][0..8],399 .p32 => std.mem.writeInt(
384 @as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),400 i32,
385 .little,401 buffer[offset..][0..4],
386 );402 @intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr))),
403 .little,
404 ),
405 .p64 => std.mem.writeInt(
406 i64,
407 buffer[offset..][0..8],
408 @as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),
409 .little,
410 ),
411 }
387 }412 }
388413
389 if (fde.getLsdaAtom(macho_file)) |atom| {414 if (fde.getLsdaAtom(macho_file)) |atom| {
...@@ -465,12 +490,21 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_in...@@ -465,12 +490,21 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_in
465 const offset = fde.out_offset + 8;490 const offset = fde.out_offset + 8;
466 const saddr = sect.addr + offset;491 const saddr = sect.addr + offset;
467 const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;492 const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;
468 std.mem.writeInt(493
469 i64,494 switch (fde.getCie(macho_file).address_ptr_size) {
470 code[offset..][0..8],495 .p32 => std.mem.writeInt(
471 @as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),496 i32,
472 .little,497 code[offset..][0..4],
473 );498 @intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr))),
499 .little,
500 ),
501 .p64 => std.mem.writeInt(
502 i64,
503 code[offset..][0..8],
504 @as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),
505 .little,
506 ),
507 }
474 }508 }
475509
476 if (fde.getLsdaAtom(macho_file)) |atom| {510 if (fde.getLsdaAtom(macho_file)) |atom| {
test/link/macho.zig+66
...@@ -74,6 +74,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -74,6 +74,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
74 macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target }));74 macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target }));
75 macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target }));75 macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target }));
76 macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target }));76 macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target }));
77 macho_step.dependOn(testEhFramePointerEncodingSdata4(b, .{ .target = aarch64_target }));
77 macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target }));78 macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target }));
78 macho_step.dependOn(testWeakRef(b, .{ .target = b.resolveTargetQuery(.{79 macho_step.dependOn(testWeakRef(b, .{ .target = b.resolveTargetQuery(.{
79 .cpu_arch = .x86_64,80 .cpu_arch = .x86_64,
...@@ -2852,6 +2853,71 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2852,6 +2853,71 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2852 return test_step;2853 return test_step;
2853}2854}
28542855
2856fn testEhFramePointerEncodingSdata4(b: *Build, opts: Options) *Step {
2857 const test_step = addTestStep(b, "eh_frame-pointer-encoding-sdata4", opts);
2858
2859 const a_o = addObject(b, opts, .{ .name = "foo", .asm_source_bytes =
2860 \\.global _foo
2861 \\.align 2
2862 \\_foo:
2863 \\ mov w0, #100
2864 \\ ret
2865 \\LEND_foo:
2866 \\
2867 \\.section __TEXT,__gcc_except_tab
2868 \\LLSDA_foo:
2869 \\ .byte 0xff
2870 \\ .byte 0xff
2871 \\ .byte 0x01
2872 \\ .uleb128 0
2873 \\
2874 \\.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
2875 \\LCIE:
2876 \\ .long LCIE_end - LCIE_start
2877 \\LCIE_start:
2878 \\ .long 0 ; CIE ID
2879 \\ .byte 1 ; Version
2880 \\ .asciz "zLR" ; Augmentation string
2881 \\ .uleb128 1 ; Code alignment factor
2882 \\ .sleb128 -8 ; Data alignment factor
2883 \\ .byte 30 ; Return address register
2884 \\ .uleb128 2 ; Augmentation data length
2885 \\ .byte 0x1b ; LSDA pointer encoding (DW_EH_PE_pcrel | DW_EH_PE_sdata4)
2886 \\ .byte 0x1b ; FDE pointer encoding (DW_EH_PE_pcrel | DW_EH_PE_sdata4)
2887 \\ .byte 0x0c ; DW_CFA_def_cfa
2888 \\ .uleb128 31 ; Reg 31
2889 \\ .uleb128 0 ; Offset 0
2890 \\ .align 3
2891 \\LCIE_end:
2892 \\LFDE:
2893 \\ .long LFDE_end - LFDE_start
2894 \\LFDE_start:
2895 \\ .long LFDE_start - LCIE ; CIE pointer
2896 \\ .long _foo - . ; PC begin
2897 \\ .long LEND_foo - _foo ; PC range
2898 \\ .uleb128 4 ; Augmentation data length
2899 \\ .long LLSDA_foo - . ; LSDA pointer
2900 \\ .align 3
2901 \\LFDE_end:
2902 });
2903
2904 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
2905 \\#include <stdio.h>
2906 \\int foo();
2907 \\int main() {
2908 \\ printf("%d\n", foo());
2909 \\ return 0;
2910 \\}
2911 });
2912 exe.root_module.addObject(a_o);
2913
2914 const run = addRunArtifact(exe);
2915 run.expectStdOutEqual("100\n");
2916 test_step.dependOn(&run.step);
2917
2918 return test_step;
2919}
2920
2855fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {2921fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
2856 const test_step = addTestStep(b, "unwind-info-no-subsections-arm64", opts);2922 const test_step = addTestStep(b, "unwind-info-no-subsections-arm64", opts);
28572923