From 02efcc88c15ecd53ba9b6ddd05bf7e5b353c38fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 5 Jul 2026 10:36:05 +0200 Subject: [PATCH 1/3] musl: mark ctr and xer clobbered in syscalls on powerpc Backport of musl commit f6944eb3c4ce1c97dc39dc36d32390dc9f70b67b. --- lib/libc/musl/arch/powerpc/syscall_arch.h | 14 +++++++------- lib/libc/musl/arch/powerpc64/syscall_arch.h | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/libc/musl/arch/powerpc/syscall_arch.h b/lib/libc/musl/arch/powerpc/syscall_arch.h index ede97c1c085fa54b0439d3742a946574bae42bb2..6ce5dc3dea262c1d7eedea3ca7085ee801215f71 100644 --- a/lib/libc/musl/arch/powerpc/syscall_arch.h +++ b/lib/libc/musl/arch/powerpc/syscall_arch.h @@ -9,7 +9,7 @@ static inline long __syscall0(long n) register long r3 __asm__("r3"); __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "=r"(r3) - :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -19,7 +19,7 @@ static inline long __syscall1(long n, long a) register long r3 __asm__("r3") = a; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3) - :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -30,7 +30,7 @@ static inline long __syscall2(long n, long a, long b) register long r4 __asm__("r4") = b; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4) - :: "memory", "cr0", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -42,7 +42,7 @@ static inline long __syscall3(long n, long a, long b, long c) register long r5 __asm__("r5") = c; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5) - :: "memory", "cr0", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -55,7 +55,7 @@ static inline long __syscall4(long n, long a, long b, long c, long d) register long r6 __asm__("r6") = d; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5), "+r"(r6) - :: "memory", "cr0", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -69,7 +69,7 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) register long r7 __asm__("r7") = e; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5), "+r"(r6), "+r"(r7) - :: "memory", "cr0", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -84,7 +84,7 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo register long r8 __asm__("r8") = f; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5), "+r"(r6), "+r"(r7), "+r"(r8) - :: "memory", "cr0", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } diff --git a/lib/libc/musl/arch/powerpc64/syscall_arch.h b/lib/libc/musl/arch/powerpc64/syscall_arch.h index 76b4e335cff958d189a737ae75cbe07ef0891503..a4a4e414f84446b14e7baff9438c1e3680209730 100644 --- a/lib/libc/musl/arch/powerpc64/syscall_arch.h +++ b/lib/libc/musl/arch/powerpc64/syscall_arch.h @@ -7,7 +7,7 @@ static inline long __syscall0(long n) register long r3 __asm__("r3"); __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "=r"(r3) - :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -17,7 +17,7 @@ static inline long __syscall1(long n, long a) register long r3 __asm__("r3") = a; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3) - :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -28,7 +28,7 @@ static inline long __syscall2(long n, long a, long b) register long r4 __asm__("r4") = b; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4) - :: "memory", "cr0", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -40,7 +40,7 @@ static inline long __syscall3(long n, long a, long b, long c) register long r5 __asm__("r5") = c; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5) - :: "memory", "cr0", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -53,7 +53,7 @@ static inline long __syscall4(long n, long a, long b, long c, long d) register long r6 __asm__("r6") = d; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5), "+r"(r6) - :: "memory", "cr0", "r7", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r7", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -67,7 +67,7 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) register long r7 __asm__("r7") = e; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5), "+r"(r6), "+r"(r7) - :: "memory", "cr0", "r8", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r8", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } @@ -82,7 +82,7 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo register long r8 __asm__("r8") = f; __asm__ __volatile__("sc ; bns+ 1f ; neg %1, %1 ; 1:" : "+r"(r0), "+r"(r3), "+r"(r4), "+r"(r5), "+r"(r6), "+r"(r7), "+r"(r8) - :: "memory", "cr0", "r9", "r10", "r11", "r12"); + :: "memory", "cr0", "r9", "r10", "r11", "r12", "ctr", "xer"); return r3; } -- 2.54.0 From 7e8d4c3065f7f80464ea5ebd916e734d8448c0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 5 Jul 2026 02:05:39 +0200 Subject: [PATCH 2/3] compiler: inherit uwtables/fp settings for vendored libs from root module We previously tried to just match whatever upstream did. But since we control compilation of these libraries, we may as well provide a better debugging experience where we can. * Frame pointer omission is now always inherited from the root module in all vendored libraries. * The unwind tables level is now inherited from the root module in vendored libc and crt0 components. Some libraries (libunwind, libcxxabi, libtsan) still enable unwind tables independently of the root module because they need the tables for correctness. This happens to fix std.debug's ability to DWARF unwind through musl startup code on 32-bit ARM; previously, it would get stuck trying to unwind through libc_start_main_stage2() because it had incomplete CFI. --- src/Compilation.zig | 10 +++------- src/libs/freebsd.zig | 1 - src/libs/libcxx.zig | 2 +- src/libs/libtsan.zig | 2 +- src/libs/mingw.zig | 9 +-------- src/libs/musl.zig | 4 ---- src/libs/openbsd.zig | 2 -- 7 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 35eee9c648f7f3bd5c6b8409f38d23c0ad33f94c..b12ca8debea3793c0c019c95f4b4e4f902576782 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -7327,8 +7327,6 @@ fn buildOutputFromZig( pub const CrtFileOptions = struct { function_sections: bool = true, data_sections: bool = true, - omit_frame_pointer: ?bool = null, - unwind_tables: ?std.lang.UnwindTables = null, pic: ?bool = null, no_builtin: ?bool = null, @@ -7375,7 +7373,7 @@ pub fn build_crt_file( .root_optimize_mode = comp.compilerRtOptMode(), .root_strip = comp.compilerRtStrip(), .link_libc = false, - .any_unwind_tables = options.unwind_tables != .none, + .any_unwind_tables = comp.root_mod.unwind_tables != .none, .lto = switch (output_mode) { .Lib => if (options.allow_lto) comp.config.lto else .none, .Obj, .Exe => .none, @@ -7398,11 +7396,9 @@ pub fn build_crt_file( .sanitize_c = .off, .sanitize_thread = false, .red_zone = comp.root_mod.red_zone, - // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer. - .omit_frame_pointer = options.omit_frame_pointer orelse comp.root_mod.omit_frame_pointer, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, - // Some libcs (e.g. MinGW) are opinionated about -funwind-tables. - .unwind_tables = options.unwind_tables orelse .none, + .unwind_tables = comp.root_mod.unwind_tables, // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC. .pic = options.pic orelse comp.root_mod.pic, .optimize_mode = comp.compilerRtOptMode(), diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index 8fcfb043b3fd7d6d2fcd060909cc270f27c8b520..fd8e80a78f6931227bd5e1ed7a21366c0cbc775b 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -242,7 +242,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre prog_node, files, .{ - .omit_frame_pointer = false, .pic = true, }, ); diff --git a/src/libs/libcxx.zig b/src/libs/libcxx.zig index cc91db8333dde6f83f32e7f964742d36e692cc92..502199a58fbee46259a18257192e97d79cab3678 100644 --- a/src/libs/libcxx.zig +++ b/src/libs/libcxx.zig @@ -325,7 +325,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr // See the `-fno-exceptions` logic for WASI. // The old 32-bit x86 variant of SEH doesn't use tables. const unwind_tables: std.lang.UnwindTables = - if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows)) .none else .async; + if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .async; const config = Compilation.Config.resolve(.{ .output_mode = output_mode, diff --git a/src/libs/libtsan.zig b/src/libs/libtsan.zig index af8830699ca5d240ea379d98cb9382d67fe0d984..cb15557c5b57c441217568e67caae602ddfa37a9 100644 --- a/src/libs/libtsan.zig +++ b/src/libs/libtsan.zig @@ -96,7 +96,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .sanitize_c = .off, .sanitize_thread = false, .red_zone = comp.root_mod.red_zone, - .omit_frame_pointer = optimize_mode != .Debug and !target.os.tag.isDarwin(), + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .unwind_tables = unwind_tables, .optimize_mode = optimize_mode, diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index df40f4ff7f138eef2617f80100545e732095bbfb..99257442052cea392327370ca91879be1371cb3c 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -39,9 +39,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre const arena = arena_allocator.allocator(); const target = comp.getTarget(); - // The old 32-bit x86 variant of SEH doesn't use tables. - const unwind_tables: std.lang.UnwindTables = if (target.cpu.arch != .x86) .async else .none; - switch (crt_file) { .crt2_o => { var args = std.array_list.Managed([]const u8).init(arena); @@ -60,7 +57,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre }; return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{ .function_sections = false, // https://codeberg.org/ziglang/zig/issues/30702 - .unwind_tables = unwind_tables, }); }, @@ -76,9 +72,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; - return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{ - .unwind_tables = unwind_tables, - }); + return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{}); }, .libmingw32_lib => { @@ -157,7 +151,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre } return comp.build_crt_file("libmingw32", .Lib, .@"mingw-w64 libmingw32.lib", prog_node, c_source_files.items, .{ - .unwind_tables = unwind_tables, // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611 .allow_lto = false, }); diff --git a/src/libs/musl.zig b/src/libs/musl.zig index e3613d020b203a9dc9858bb8c48d1316a2338509..3d32cc98b722252c029489076ea1ef7c9132cc6c 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -43,7 +43,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro }, }; return comp.build_crt_file("crt1", .Obj, .@"musl crt1.o", prog_node, &files, .{ - .omit_frame_pointer = true, .no_builtin = true, }); }, @@ -61,7 +60,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro }, }; return comp.build_crt_file("rcrt1", .Obj, .@"musl rcrt1.o", prog_node, &files, .{ - .omit_frame_pointer = true, .pic = true, .no_builtin = true, }); @@ -80,7 +78,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro }, }; return comp.build_crt_file("Scrt1", .Obj, .@"musl Scrt1.o", prog_node, &files, .{ - .omit_frame_pointer = true, .pic = true, .no_builtin = true, }); @@ -166,7 +163,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro }; } return comp.build_crt_file("c", .Lib, .@"musl libc.a", prog_node, c_source_files.items, .{ - .omit_frame_pointer = true, .no_builtin = true, }); }, diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index 9cbd679a3efae3bd3aadf574edadaf5479eee836..7f6dc2db817ff630366f463a9405821714a12c95 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -125,8 +125,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre const files = files_buf[0..files_index]; return comp.build_crt_file("crt0", .Obj, .@"openbsd libc Scrt0.o", prog_node, files, .{ - // Unclear why OpenBSD does this, but we'll do the same. - .omit_frame_pointer = if (target.cpu.arch.isX86()) false else null, .pic = true, }); }, -- 2.54.0 From f0fdc9098919ff65daea48b5b54154406b88d107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 4 Jul 2026 00:10:23 +0200 Subject: [PATCH 3/3] std.debug.SelfInfo.Elf: enable DWARF unwinding for ARM It seems like whatever bug was causing this to be unreliable is no longer present; all module tests work for me with DWARF unwinding enabled. So let's enable this for now, and if any breakage does pop up later, we can deal with it then. --- lib/std/debug/SelfInfo/Elf.zig | 19 ++++++++++++------- test/src/StackTrace.zig | 5 +++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 9e8153555f4a68dfde3996328263aee2dd39d582..4e7fba60796adbb2f78a53b795aed5724eecd096 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -92,12 +92,10 @@ pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { } pub const can_unwind: bool = s: { - // Notably, we are yet to support unwinding on ARM. There, unwinding is not done through - // `.eh_frame`, but instead with the `.ARM.exidx` section, which has a different format. const archs: []const std.Target.Cpu.Arch = switch (builtin.target.os.tag) { - // Not supported yet: arm .haiku => &.{ .aarch64, + .arm, .riscv64, .x86, .x86_64, @@ -106,12 +104,14 @@ pub const can_unwind: bool = s: { .x86, .x86_64, }, - // Not supported yet: arm/armeb/thumb/thumbeb, hppa, hppa64, microblaze/microblazeel + // Not supported yet: hppa, hppa64, microblaze/microblazeel, sh/sheb .linux => &.{ .aarch64, .aarch64_be, .alpha, .arc, + .arm, + .armeb, .csky, .loongarch32, .loongarch64, @@ -124,6 +124,8 @@ pub const can_unwind: bool = s: { .riscv32, .riscv64, .s390x, + .thumb, + .thumbeb, .x86, .x86_64, }, @@ -136,18 +138,20 @@ pub const can_unwind: bool = s: { .dragonfly => &.{ .x86_64, }, - // Not supported yet: arm .freebsd => &.{ .aarch64, + .arm, .riscv64, .x86, .x86_64, }, - // Not supported yet: arm/armeb, hppa, mips64/mips64el, sh/sheb + // Not supported yet: hppa, mips64/mips64el, sh/sheb .netbsd => &.{ .aarch64, .aarch64_be, .alpha, + .arm, + .armeb, .m68k, .mips, .mipsel, @@ -156,9 +160,10 @@ pub const can_unwind: bool = s: { .x86, .x86_64, }, - // Not supported yet: arm, hppa, sh + // Not supported yet: hppa, sh .openbsd => &.{ .aarch64, + .arm, .m88k, .mips64, .mips64el, diff --git a/test/src/StackTrace.zig b/test/src/StackTrace.zig index 9beb8904607bbf550c3080fe4e34a9cd617b28c0..0022e5b9b616671a0a0d4809a8d648dc14cc3988 100644 --- a/test/src/StackTrace.zig +++ b/test/src/StackTrace.zig @@ -72,6 +72,8 @@ fn addCaseTarget( .mips64el, .sh, .sheb, + .xtensa, + .xtensaeb, => .useless, .hexagon, .powerpc, @@ -87,8 +89,7 @@ fn addCaseTarget( const supports_unwind_tables = switch (target.result.os.tag) { // x86-windows just has no way to do stack unwinding other then using frame pointers. .windows => target.result.cpu.arch != .x86, - // We do not yet implement support for the AArch32 exception table section `.ARM.exidx`. - else => !target.result.cpu.arch.isArm(), + else => true, }; const use_llvm_vals: []const bool = if (both_backends) &.{ true, false } else &.{true}; -- 2.54.0