From 566cc4f99d03075f396b3ca13ee140fdcd80d37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 18 Jan 2025 14:55:58 +0100 Subject: [PATCH 1/4] compiler: Fix @import("builtin").unwind_tables logic. --- src/Package/Module.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Package/Module.zig b/src/Package/Module.zig index af91b01c9a8e..433a9b6adef9 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -387,7 +387,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .zig_backend = zig_backend, .output_mode = options.global.output_mode, .link_mode = options.global.link_mode, - .unwind_tables = options.global.any_unwind_tables, + .unwind_tables = unwind_tables, .is_test = options.global.is_test, .single_threaded = single_threaded, .link_libc = options.global.link_libc, From 4de661ef18d4cdc7f859c8bc1990e8a0519163db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 18 Jan 2025 13:54:05 +0100 Subject: [PATCH 2/4] start: Don't emit CFI directives if unwind tables are disabled. --- lib/std/start.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 9da0cb2ec61b..8b0d6183cfea 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -231,8 +231,8 @@ fn _start() callconv(.naked) noreturn { } // This is the first userspace frame. Prevent DWARF-based unwinders from unwinding further. We - // prevent FP-based unwinders from unwinding further by zeroing the register further below. - asm volatile (switch (native_arch) { + // prevent FP-based unwinders from unwinding further by zeroing the register below. + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (switch (native_arch) { .arc => ".cfi_undefined blink", .arm, .armeb, .thumb, .thumbeb => "", // https://github.com/llvm/llvm-project/issues/115891 .aarch64, .aarch64_be => ".cfi_undefined lr", From 8a78d875cc1cdab2648e7413fc0d2eea5afc6991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 18 Jan 2025 14:09:47 +0100 Subject: [PATCH 3/4] std.os.linux: Don't emit CFI directives if unwind tables are disabled. --- lib/std/os/linux/aarch64.zig | 8 +++++++- lib/std/os/linux/hexagon.zig | 6 +++++- lib/std/os/linux/loongarch64.zig | 5 +++++ lib/std/os/linux/mips.zig | 5 +++++ lib/std/os/linux/mips64.zig | 5 +++++ lib/std/os/linux/powerpc.zig | 5 +++++ lib/std/os/linux/powerpc64.zig | 5 +++++ lib/std/os/linux/riscv32.zig | 8 +++++++- lib/std/os/linux/riscv64.zig | 8 +++++++- lib/std/os/linux/s390x.zig | 5 +++++ lib/std/os/linux/sparc64.zig | 5 +++++ lib/std/os/linux/x86.zig | 5 +++++ lib/std/os/linux/x86_64.zig | 8 +++++++- 13 files changed, 73 insertions(+), 5 deletions(-) diff --git a/lib/std/os/linux/aarch64.zig b/lib/std/os/linux/aarch64.zig index db304a3a33b4..302c58ac2bcf 100644 --- a/lib/std/os/linux/aarch64.zig +++ b/lib/std/os/linux/aarch64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -122,7 +123,12 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ // child - \\1: .cfi_undefined lr + \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined lr + ); + asm volatile ( \\ mov fp, 0 \\ mov lr, 0 \\ diff --git a/lib/std/os/linux/hexagon.zig b/lib/std/os/linux/hexagon.zig index 0839ea8297a0..0b5cbb208ee8 100644 --- a/lib/std/os/linux/hexagon.zig +++ b/lib/std/os/linux/hexagon.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const iovec = std.posix.iovec; const iovec_const = std.posix.iovec_const; @@ -117,8 +118,11 @@ pub fn clone() callconv(.Naked) usize { \\ \\ p0 = cmp.eq(r0, #0) \\ if (!p0) dealloc_return - \\ + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined r31 + ); + asm volatile ( \\ r30 = #0 \\ r31 = #0 \\ diff --git a/lib/std/os/linux/loongarch64.zig b/lib/std/os/linux/loongarch64.zig index b52f1d10b137..ce57a6713a9b 100644 --- a/lib/std/os/linux/loongarch64.zig +++ b/lib/std/os/linux/loongarch64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const linux = std.os.linux; const SYS = linux.SYS; @@ -121,7 +122,11 @@ pub fn clone() callconv(.Naked) usize { \\ beqz $a0, 1f # whether child process \\ jirl $zero, $ra, 0 # parent process return \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined 1 + ); + asm volatile ( \\ move $fp, $zero \\ move $ra, $zero \\ diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig index 5d786ccde7f6..5ebe6bd68658 100644 --- a/lib/std/os/linux/mips.zig +++ b/lib/std/os/linux/mips.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -231,7 +232,11 @@ pub fn clone() callconv(.Naked) usize { \\ jr $ra \\ nop \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined $ra + ); + asm volatile ( \\ move $fp, $zero \\ move $ra, $zero \\ diff --git a/lib/std/os/linux/mips64.zig b/lib/std/os/linux/mips64.zig index 256c911bbe58..0d0a1104c12c 100644 --- a/lib/std/os/linux/mips64.zig +++ b/lib/std/os/linux/mips64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -210,7 +211,11 @@ pub fn clone() callconv(.Naked) usize { \\ jr $ra \\ nop \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined $ra + ); + asm volatile ( \\ move $fp, $zero \\ move $ra, $zero \\ diff --git a/lib/std/os/linux/powerpc.zig b/lib/std/os/linux/powerpc.zig index 9dde326e1b04..591575cb02a7 100644 --- a/lib/std/os/linux/powerpc.zig +++ b/lib/std/os/linux/powerpc.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -176,7 +177,11 @@ pub fn clone() callconv(.Naked) usize { \\ \\ #else: we're the child \\ 2: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined lr + ); + asm volatile ( \\ li 31, 0 \\ mtlr 0 \\ diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig index 6a1f98a65fba..419c9f062985 100644 --- a/lib/std/os/linux/powerpc64.zig +++ b/lib/std/os/linux/powerpc64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -161,7 +162,11 @@ pub fn clone() callconv(.Naked) usize { \\ bnelr cr7 \\ \\ # we're the child + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined lr + ); + asm volatile ( \\ li 31, 0 \\ mtlr 0 \\ diff --git a/lib/std/os/linux/riscv32.zig b/lib/std/os/linux/riscv32.zig index dc444a19560b..4df6e1671f93 100644 --- a/lib/std/os/linux/riscv32.zig +++ b/lib/std/os/linux/riscv32.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const iovec = std.posix.iovec; const iovec_const = std.posix.iovec_const; @@ -120,7 +121,12 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ # Child - \\1: .cfi_undefined ra + \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined ra + ); + asm volatile ( \\ mv fp, zero \\ mv ra, zero \\ diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index 45ba568c1bf9..c402e9e894ae 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/lib/std/os/linux/riscv64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const iovec = std.posix.iovec; const iovec_const = std.posix.iovec_const; @@ -120,7 +121,12 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ # Child - \\1: .cfi_undefined ra + \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined ra + ); + asm volatile ( \\ mv fp, zero \\ mv ra, zero \\ diff --git a/lib/std/os/linux/s390x.zig b/lib/std/os/linux/s390x.zig index 8fbe1c930b3b..337e36a574ab 100644 --- a/lib/std/os/linux/s390x.zig +++ b/lib/std/os/linux/s390x.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const iovec = std.posix.iovec; const iovec_const = std.posix.iovec_const; @@ -134,7 +135,11 @@ pub fn clone() callconv(.Naked) usize { \\bnzr %%r14 \\ \\# we're the child + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\.cfi_undefined %%r14 + ); + asm volatile ( \\lghi %%r11, 0 \\lghi %%r14, 0 \\ diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index 17df65feb72d..90cb799e02be 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const pid_t = linux.pid_t; @@ -215,7 +216,11 @@ pub fn clone() callconv(.Naked) usize { \\ restore \\2: \\ # Child process + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined %%i7 + ); + asm volatile ( \\ mov %%g0, %%fp \\ mov %%g0, %%i7 \\ diff --git a/lib/std/os/linux/x86.zig b/lib/std/os/linux/x86.zig index cb746e52a8dc..0cde6d805e78 100644 --- a/lib/std/os/linux/x86.zig +++ b/lib/std/os/linux/x86.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -156,7 +157,11 @@ pub fn clone() callconv(.Naked) usize { \\ retl \\ \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( \\ .cfi_undefined %%eip + ); + asm volatile ( \\ xorl %%ebp,%%ebp \\ \\ popl %%eax diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index 44a37345f0f4..1c5105d6247d 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/lib/std/os/linux/x86_64.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; @@ -117,7 +118,12 @@ pub fn clone() callconv(.Naked) usize { \\ jz 1f \\ retq \\ - \\1: .cfi_undefined %%rip + \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined %%rip + ); + asm volatile ( \\ xorl %%ebp,%%ebp \\ \\ popq %%rdi From 45bb4f955c8c8be40ed8b2247eaaa70661cf1b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 18 Jan 2025 14:32:55 +0100 Subject: [PATCH 4/4] test: Add a standalone test for omitting CFI directives. --- test/standalone/build.zig.zon | 3 ++ test/standalone/omit_cfi/build.zig | 67 ++++++++++++++++++++++++++++++ test/standalone/omit_cfi/main.zig | 1 + 3 files changed, 71 insertions(+) create mode 100644 test/standalone/omit_cfi/build.zig create mode 100644 test/standalone/omit_cfi/main.zig diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 06ebe980d1b0..9863e7cc6d46 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -183,6 +183,9 @@ .empty_global_error_set = .{ .path = "empty_global_error_set", }, + .omit_cfi = .{ + .path = "omit_cfi", + }, }, .paths = .{ "build.zig", diff --git a/test/standalone/omit_cfi/build.zig b/test/standalone/omit_cfi/build.zig new file mode 100644 index 000000000000..62f9fed471b2 --- /dev/null +++ b/test/standalone/omit_cfi/build.zig @@ -0,0 +1,67 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + inline for (.{ + .aarch64, + .aarch64_be, + .hexagon, + .loongarch64, + .mips, + .mipsel, + .mips64, + .mips64el, + .powerpc, + .powerpcle, + .powerpc64, + .powerpc64le, + .riscv32, + .riscv64, + .s390x, + .sparc64, + .x86, + .x86_64, + }) |arch| { + const target = b.resolveTargetQuery(.{ + .cpu_arch = arch, + .os_tag = .linux, + }); + + const omit_dbg = b.addExecutable(.{ + .name = b.fmt("{s}-linux-omit-dbg", .{@tagName(arch)}), + .root_module = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .target = target, + .optimize = .Debug, + // We are mainly concerned with CFI directives in our non-libc startup code and syscall + // code, so make it explicit that we don't want libc. + .link_libc = false, + .strip = true, + }), + }); + + const omit_uwt = b.addExecutable(.{ + .name = b.fmt("{s}-linux-omit-uwt", .{@tagName(arch)}), + .root_module = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .target = target, + .optimize = .Debug, + .link_libc = false, + .unwind_tables = .none, + }), + }); + + const omit_both = b.addExecutable(.{ + .name = b.fmt("{s}-linux-omit-both", .{@tagName(arch)}), + .root_module = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .target = target, + .optimize = .Debug, + .link_libc = false, + .strip = true, + .unwind_tables = .none, + }), + }); + + inline for (.{ omit_dbg, omit_uwt, omit_both }) |step| b.installArtifact(step); + } +} diff --git a/test/standalone/omit_cfi/main.zig b/test/standalone/omit_cfi/main.zig new file mode 100644 index 000000000000..902b554db075 --- /dev/null +++ b/test/standalone/omit_cfi/main.zig @@ -0,0 +1 @@ +pub fn main() void {}