From a996a75e06193d377c3071042ece1c3af5cfdc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 12 Dec 2025 20:25:34 +0100 Subject: [PATCH 1/6] compiler: make all Zig-provided libraries use -ffunction-sections -fdata-sections We already did this for some of them; this just makes us consistent. Doing this gives the linker more flexibility to rearrange code/data, but more importantly, allows --gc-sections to get rid of all the unused code, which is a real concern for these libraries in particular. --- src/Compilation.zig | 8 ++++---- src/libs/libcxx.zig | 4 ++++ src/libs/libtsan.zig | 2 ++ src/libs/libunwind.zig | 3 ++- src/libs/mingw.zig | 1 + src/libs/musl.zig | 8 -------- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 1b17f81c7dbe0e47bec03686701b5d3145f3d883..f308a60bd3e62e309d7dcb9ec38ecfaca18fff2a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -8084,8 +8084,8 @@ fn buildOutputFromZig( } pub const CrtFileOptions = struct { - function_sections: ?bool = null, - data_sections: ?bool = null, + function_sections: bool = true, + data_sections: bool = true, omit_frame_pointer: ?bool = null, unwind_tables: ?std.builtin.UnwindTables = null, pic: ?bool = null, @@ -8188,8 +8188,8 @@ pub fn build_crt_file( .root_name = root_name, .libc_installation = comp.libc_installation, .emit_bin = .yes_cache, - .function_sections = options.function_sections orelse false, - .data_sections = options.data_sections orelse false, + .function_sections = options.function_sections, + .data_sections = options.data_sections, .c_source_files = c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, diff --git a/src/libs/libcxx.zig b/src/libs/libcxx.zig index bd8863991d63db6ed10d14cc426f0961fec0d676..316ac6d815b3d6023f0d63164194e412cfdd7e5c 100644 --- a/src/libs/libcxx.zig +++ b/src/libs/libcxx.zig @@ -265,6 +265,8 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! .root_name = root_name, .libc_installation = comp.libc_installation, .emit_bin = .yes_cache, + .function_sections = true, + .data_sections = true, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, @@ -459,6 +461,8 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .root_name = root_name, .libc_installation = comp.libc_installation, .emit_bin = .yes_cache, + .function_sections = true, + .data_sections = true, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, diff --git a/src/libs/libtsan.zig b/src/libs/libtsan.zig index 2f9574c47343aad0bf7b90013cbdd8c49f46c6cc..c9dcf609537b3cce617d77a5b456be4044cb09f5 100644 --- a/src/libs/libtsan.zig +++ b/src/libs/libtsan.zig @@ -288,6 +288,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .root_name = root_name, .libc_installation = comp.libc_installation, .emit_bin = .yes_cache, + .function_sections = true, + .data_sections = true, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, diff --git a/src/libs/libunwind.zig b/src/libs/libunwind.zig index 787a87f951094245fe042a22da043b41b833373f..c1437d39bd0c800039b4231f2ae7c172749676ff 100644 --- a/src/libs/libunwind.zig +++ b/src/libs/libunwind.zig @@ -155,7 +155,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .main_mod = null, .libc_installation = comp.libc_installation, .emit_bin = .yes_cache, - .function_sections = comp.function_sections, + .function_sections = true, + .data_sections = true, .c_source_files = &c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 5c57f6d53e8b495fe08932fa3746711c192427f5..da67f476616815c849bc52ab2184ac5f2bf9e49c 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -56,6 +56,7 @@ 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, }); }, diff --git a/src/libs/musl.zig b/src/libs/musl.zig index f1983381952d060c646a0a8bc16fe8e73964eaac..744f1f28d24b7c5cb1e9b49e47cdd244fb31aaa6 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -43,8 +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, .{ - .function_sections = true, - .data_sections = true, .omit_frame_pointer = true, .no_builtin = true, }); @@ -63,8 +61,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, .{ - .function_sections = true, - .data_sections = true, .omit_frame_pointer = true, .pic = true, .no_builtin = true, @@ -84,8 +80,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, .{ - .function_sections = true, - .data_sections = true, .omit_frame_pointer = true, .pic = true, .no_builtin = true, @@ -172,8 +166,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, .{ - .function_sections = true, - .data_sections = true, .omit_frame_pointer = true, .no_builtin = true, }); -- 2.54.0 From 7daf0b6f4660245ac518c663f8971aad7e540da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 12 Dec 2025 20:30:50 +0100 Subject: [PATCH 2/6] build: use -ffunction-sections -fdata-sections for the Zig compiler on PowerPC It has been observed in practice on powerpc64(le)-linux that zig.o (in various stages and build modes) is large enough that the +/- 32MB branch range of PowerPC is insufficient to reach from one end of the code section to the other. With LLVM 21, this leads to silent miscompiles that then crash at runtime. With LLVM 22, it will at least lead to branch range errors that fail the compilation, but that gets us no closer to a working compiler. By using these options, we give the linker much greater flexibility to move code and data around to satisfy these range constraints; without them, the linker is not allowed to split up the huge code and data sections of zig.o to do so. Similar issues have also been observed on powerpc-linux (32-bit), hexagon-linux, and some variations of mips(64)(el)-linux. But let's be conservative for now; those other targets can be added to the condition later. As a data point to support this change, it's worth noting that LLD started enabling these options for LTO precisely because the resulting large compilation units ran into these range issues. In some abstract sense, Zig can be seen as doing a limited form of "LTO" in the frontend, so it's not surprising that we would hit the same issues. --- CMakeLists.txt | 5 +++++ build.zig | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4de1a9b99198c178c6f8fbfc57b7802dbc311847..fbd8673ce48b00f22cd95d79200de3f27403614f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -787,6 +787,11 @@ else() set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-sanitize=undefined -fno-stack-protector") + # Must match the condition in build.zig. + if(ZIG_HOST_TARGET_ARCH MATCHES "^powerpc(64)?(le)?$") + set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -ffunction-sections -fdata-sections") + set(ZIG2_COMPILE_FLAGS "${ZIG2_COMPILE_FLAGS} -ffunction-sections -fdata-sections") + endif() if(APPLE) set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") elseif(MINGW) diff --git a/build.zig b/build.zig index 342c2cfada354e9cccda63484ed9252b7bcafe67..2311f879a42153e79056f180fa0d50b381ac9ba0 100644 --- a/build.zig +++ b/build.zig @@ -838,6 +838,12 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerModOptions) *std.Build.Ste }); exe.stack_size = stack_size; + // Must match the condition in CMakeLists.txt. + const function_data_sections = options.target.result.cpu.arch.isPowerPC(); + + exe.link_function_sections = function_data_sections; + exe.link_data_sections = function_data_sections; + return exe; } -- 2.54.0 From 6a1fecea675061ce4f62148319941ce7b9e91877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 5 Jan 2026 19:43:50 +0100 Subject: [PATCH 3/6] build: bump max_rss for test-behavior on powerpc64le-linux to 627_431_833 --- build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 2311f879a42153e79056f180fa0d50b381ac9ba0..58a5c5def37e2987dee92ede7cf8b0282364a64a 100644 --- a/build.zig +++ b/build.zig @@ -477,7 +477,7 @@ pub fn build(b: *std.Build) !void { .linux => switch (b.graph.host.result.cpu.arch) { .aarch64 => 659_809_075, .loongarch64 => 598_902_374, - .powerpc64le => 550_656_409, + .powerpc64le => 627_431_833, .riscv64 => 827_043_430, .s390x => 580_596_121, .x86_64 => 3_290_894_745, -- 2.54.0 From 64f5ef88808110943b6bc31e550fa7eeeec7ba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 10 Dec 2025 02:49:54 +0100 Subject: [PATCH 4/6] ci: add powerpc64le-linux scripts --- ci/powerpc64le-linux-debug.sh | 65 ++++++++++++++++++++++++++++++ ci/powerpc64le-linux-release.sh | 71 +++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100755 ci/powerpc64le-linux-debug.sh create mode 100755 ci/powerpc64le-linux-release.sh diff --git a/ci/powerpc64le-linux-debug.sh b/ci/powerpc64le-linux-debug.sh new file mode 100755 index 0000000000000000000000000000000000000000..e521c4cca261e7e0c6b75541a615eccc38a59f0f --- /dev/null +++ b/ci/powerpc64le-linux-debug.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +# Requires cmake ninja-build + +set -x +set -e + +TARGET="powerpc64le-linux-musl" +MCPU="baseline" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.1594+9fa433d71" +PREFIX="$HOME/deps/$CACHE_BASENAME" +ZIG="$PREFIX/bin/zig" + +# Override the cache directories because they won't actually help other CI runs +# which will be testing alternate versions of zig, and ultimately would just +# fill up space on the hard drive for no reason. +export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache" +export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache" + +mkdir build-debug +cd build-debug + +export CC="$ZIG cc -target $TARGET -mcpu=$MCPU" +export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU" + +cmake .. \ + -DCMAKE_INSTALL_PREFIX="stage3-debug" \ + -DCMAKE_PREFIX_PATH="$PREFIX" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DZIG_TARGET_TRIPLE="$TARGET" \ + -DZIG_TARGET_MCPU="$MCPU" \ + -DZIG_STATIC=ON \ + -DZIG_NO_LIB=ON \ + -GNinja \ + -DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \ + -DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE +# https://github.com/ziglang/zig/issues/22213 + +# Now cmake will use zig as the C/C++ compiler. We reset the environment variables +# so that installation and testing do not get affected by them. +unset CC +unset CXX + +ninja install + +# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts. +stage3-debug/bin/zig build test docs \ + --maxrss ${ZSF_MAX_RSS:-0} \ + -Dstatic-llvm \ + -Dskip-non-native \ + -Dtarget=native-native-musl \ + --search-prefix "$PREFIX" \ + --zig-lib-dir "$PWD/../lib" \ + --test-timeout 4m + +stage3-debug/bin/zig build \ + --prefix stage4-debug \ + -Denable-llvm \ + -Dno-lib \ + -Dtarget=$TARGET \ + -Dcpu=$MCPU \ + -Duse-zig-libcxx \ + -Dversion-string="$(stage3-debug/bin/zig version)" + +stage4-debug/bin/zig test ../test/behavior.zig diff --git a/ci/powerpc64le-linux-release.sh b/ci/powerpc64le-linux-release.sh new file mode 100755 index 0000000000000000000000000000000000000000..96915af5276f79898bc5d3d95eb448812cb4ec05 --- /dev/null +++ b/ci/powerpc64le-linux-release.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +# Requires cmake ninja-build + +set -x +set -e + +TARGET="powerpc64le-linux-musl" +MCPU="baseline" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.16.0-dev.1594+9fa433d71" +PREFIX="$HOME/deps/$CACHE_BASENAME" +ZIG="$PREFIX/bin/zig" + +# Override the cache directories because they won't actually help other CI runs +# which will be testing alternate versions of zig, and ultimately would just +# fill up space on the hard drive for no reason. +export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache" +export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache" + +mkdir build-release +cd build-release + +export CC="$ZIG cc -target $TARGET -mcpu=$MCPU" +export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU" + +cmake .. \ + -DCMAKE_INSTALL_PREFIX="stage3-release" \ + -DCMAKE_PREFIX_PATH="$PREFIX" \ + -DCMAKE_BUILD_TYPE=Release \ + -DZIG_TARGET_TRIPLE="$TARGET" \ + -DZIG_TARGET_MCPU="$MCPU" \ + -DZIG_STATIC=ON \ + -DZIG_NO_LIB=ON \ + -GNinja \ + -DCMAKE_C_LINKER_DEPFILE_SUPPORTED=FALSE \ + -DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=FALSE +# https://github.com/ziglang/zig/issues/22213 + +# Now cmake will use zig as the C/C++ compiler. We reset the environment variables +# so that installation and testing do not get affected by them. +unset CC +unset CXX + +ninja install + +# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts. +stage3-release/bin/zig build test docs \ + --maxrss ${ZSF_MAX_RSS:-0} \ + -Dstatic-llvm \ + -Dskip-non-native \ + -Dtarget=native-native-musl \ + --search-prefix "$PREFIX" \ + --zig-lib-dir "$PWD/../lib" \ + --test-timeout 4m + +# Ensure that stage3 and stage4 are byte-for-byte identical. +stage3-release/bin/zig build \ + --prefix stage4-release \ + -Denable-llvm \ + -Dno-lib \ + -Doptimize=ReleaseFast \ + -Dstrip \ + -Dtarget=$TARGET \ + -Dcpu=$MCPU \ + -Duse-zig-libcxx \ + -Dversion-string="$(stage3-release/bin/zig version)" + +# diff returns an error code if the files differ. +echo "If the following command fails, it means nondeterminism has been" +echo "introduced, making stage3 and stage4 no longer byte-for-byte identical." +diff stage3-release/bin/zig stage4-release/bin/zig -- 2.54.0 From 63eb3957299e187938d6634ba450eabe86deb52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 5 Jan 2026 19:49:15 +0100 Subject: [PATCH 5/6] ci: build test stage3 on powerpc64le-linux with long calls Necessary to work around this: error: ld.lld: /home/ci/.cache/act/f23fdcb74e58cd75/hostexecutor/zig-global-cache/o/c67e3042d116da0f73d3129d377044bf/libc++abi.a(/home/ci/.cache/act/f23fdcb74e58cd75/hostexecutor/zig-global-cache/o/61dd7765ab891b4db54a5e49b8ab8c86/cxa_thread_atexit.o):(function __cxa_thread_atexit: .text.__cxa_thread_atexit+0x40): relocation R_PPC64_REL24_NOTOC out of range: -251925824 is not in [-33554432, 33554431]; references '__cxa_thread_atexit_impl' note: referenced by cxa_thread_atexit.cpp:116 (/home/ci/.cache/act/f23fdcb74e58cd75/hostexecutor/lib/libcxxabi/src/cxa_thread_atexit.cpp:116) note: defined in /home/ci/.cache/act/f23fdcb74e58cd75/hostexecutor/zig-global-cache/o/c67e3042d116da0f73d3129d377044bf/libc++abi.a(/home/ci/.cache/act/f23fdcb74e58cd75/hostexecutor/zig-global-cache/o/61dd7765ab891b4db54a5e49b8ab8c86/cxa_thread_atexit.o) This is only a problem for now because we link libLLVM; once we start invoking llc instead, we won't need this workaround anymore. --- ci/powerpc64le-linux-debug.sh | 1 + ci/powerpc64le-linux-release.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/ci/powerpc64le-linux-debug.sh b/ci/powerpc64le-linux-debug.sh index e521c4cca261e7e0c6b75541a615eccc38a59f0f..1b9a51e44debff61729207ec1529e1d494b8c84b 100755 --- a/ci/powerpc64le-linux-debug.sh +++ b/ci/powerpc64le-linux-debug.sh @@ -49,6 +49,7 @@ stage3-debug/bin/zig build test docs \ -Dstatic-llvm \ -Dskip-non-native \ -Dtarget=native-native-musl \ + -Dcpu=native+longcall \ --search-prefix "$PREFIX" \ --zig-lib-dir "$PWD/../lib" \ --test-timeout 4m diff --git a/ci/powerpc64le-linux-release.sh b/ci/powerpc64le-linux-release.sh index 96915af5276f79898bc5d3d95eb448812cb4ec05..77e1ca803ae27db49ed7a2b8fed48392f485c4d4 100755 --- a/ci/powerpc64le-linux-release.sh +++ b/ci/powerpc64le-linux-release.sh @@ -49,6 +49,7 @@ stage3-release/bin/zig build test docs \ -Dstatic-llvm \ -Dskip-non-native \ -Dtarget=native-native-musl \ + -Dcpu=native+longcall \ --search-prefix "$PREFIX" \ --zig-lib-dir "$PWD/../lib" \ --test-timeout 4m -- 2.54.0 From 43a8e9ee80504a7dd93dc41869fb9a81c67ec625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Thu, 11 Dec 2025 21:24:01 +0100 Subject: [PATCH 6/6] ci: enable powerpc64le-linux --- .forgejo/workflows/ci.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml index ffcfede0cef7fff897371adcf68651524d37a98d..e47b3ebbd3ed7a4e13f33eee3428d9c6238d656f 100644 --- a/.forgejo/workflows/ci.yaml +++ b/.forgejo/workflows/ci.yaml @@ -78,6 +78,27 @@ jobs: run: sh ci/loongarch64-linux-release.sh timeout-minutes: 180 + powerpc64le-linux-debug: + runs-on: [self-hosted, powerpc64le-linux] + steps: + - name: Checkout + uses: https://codeberg.org/ziglang/checkout@19af6bac491e2534a4687a50ee84fa7f13258d28 + with: + fetch-depth: 0 + - name: Build and Test + run: sh ci/powerpc64le-linux-debug.sh + timeout-minutes: 360 + powerpc64le-linux-release: + runs-on: [self-hosted, powerpc64le-linux] + steps: + - name: Checkout + uses: https://codeberg.org/ziglang/checkout@19af6bac491e2534a4687a50ee84fa7f13258d28 + with: + fetch-depth: 0 + - name: Build and Test + run: sh ci/powerpc64le-linux-release.sh + timeout-minutes: 240 + riscv64-linux-debug: if: github.event_name != 'pull_request' runs-on: [self-hosted, riscv64-linux] -- 2.54.0