From 6920dbdf2b6bfdc87ca077d332a5e43fba8f07ca Mon Sep 17 00:00:00 2001 From: tamnd <1218621+tamnd@users.noreply.github.com> Date: Tue, 27 Oct 2026 17:43:47 +0700 Subject: [PATCH] R64: tell rucc its target and explain the 7.2.8 config differences --- README.md | 2 +- config-divergences.toml | 40 +++++++++++++++++++++++++++++++++++ crates/rk-shim/src/bringup.rs | 10 +++++---- crates/rk/src/build.rs | 7 +++++- crates/rk/src/flags.rs | 3 ++- crates/rk/src/probes.rs | 9 ++++---- docs/plan/10-architectures.md | 2 +- rows.toml | 2 +- 8 files changed, 62 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 433b62c..578e560 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The goal is simple to state and slow to reach: every Linux release, from the mus ## Rows -A row is an architecture with a QEMU machine and a reference toolchain. X64 is x86-64 and comes first. A64 is arm64. X32 is i686, which the x86-64 kernel needs anyway for its real mode setup code and its 32-bit vDSO. R64 is riscv64 and waits for rucc to have a RISC-V back end. +A row is an architecture with a QEMU machine and a reference toolchain. X64 is x86-64 and comes first. A64 is arm64. X32 is i686, which the x86-64 kernel needs anyway for its real mode setup code and its 32-bit vDSO. R64 is riscv64, where 7.2.8 built by rucc boots and passes the same smoke and KUnit tests as gcc. ## Milestones diff --git a/config-divergences.toml b/config-divergences.toml index c797ce7..48c8847 100644 --- a/config-divergences.toml +++ b/config-divergences.toml @@ -96,6 +96,46 @@ reason = "The same as CC_CAN_LINK, one level stricter. On X32 in 6.1 Kconfig ask symbol = "GCC_ASM_GOTO_OUTPUT_WORKAROUND" reason = "This follows GCC_VERSION. In 6.1 it is y for gcc 12.0 to 12.3, which have bug 113921 in asm goto with outputs, and it adds an empty asm volatile after each asm goto. rucc claims 12.2.0 for 6.1 and gets it. The CI reference gcc-12 got it at 12.3.0 and does not at 12.4.0, and a reference gcc-13 at 13.3, as on server2, has the fix and does not either. The extra empty asm emits no code" +[[divergence]] +symbol = "CC_HAS_MIN_FUNCTION_ALIGNMENT" +reason = "-fmin-function-alignment came in gcc 14. The persona is gcc 14.2 and rucc takes the flag and honors it, while the riscv64 reference is Ubuntu 24.04's gcc 13.3, which does not know it. The kernel only uses it to align functions, and on riscv64 it decides whether dynamic ftrace can be offered, see GCC_SUPPORTS_DYNAMIC_FTRACE" + +[[divergence]] +symbol = "CC_HAS_SANE_FUNCTION_ALIGNMENT" +reason = "follows CC_HAS_MIN_FUNCTION_ALIGNMENT, see there" + +[[divergence]] +symbol = "GCC_SUPPORTS_DYNAMIC_FTRACE" +reason = "on riscv64 with compressed instructions this needs -fmin-function-alignment, which gcc 13.3 lacks, see CC_HAS_MIN_FUNCTION_ALIGNMENT. rucc also takes -fpatchable-function-entry" + +[[divergence]] +symbol = "HAVE_DYNAMIC_FTRACE*" +reason = "selected by RISCV when GCC_SUPPORTS_DYNAMIC_FTRACE is set, see there" + +[[divergence]] +symbol = "HAVE_FUNCTION_TRACER" +reason = "selected by RISCV with dynamic ftrace, see GCC_SUPPORTS_DYNAMIC_FTRACE" + +[[divergence]] +symbol = "HAVE_FUNCTION_GRAPH_TRACER" +reason = "selected by RISCV with dynamic ftrace, see GCC_SUPPORTS_DYNAMIC_FTRACE" + +[[divergence]] +symbol = "FUNCTION_TRACER" +reason = "only visible with HAVE_FUNCTION_TRACER, see GCC_SUPPORTS_DYNAMIC_FTRACE. It is off in the rucc build, so no unit is built differently" + +[[divergence]] +symbol = "STACK_TRACER" +reason = "only visible with HAVE_FUNCTION_TRACER, see GCC_SUPPORTS_DYNAMIC_FTRACE. It is off in the rucc build" + +[[divergence]] +symbol = "TOOLCHAIN_HAS_ZA*" +reason = "The riscv64 reference is Ubuntu 24.04's gcc 13.3, which refuses Zacas and Zabha in -march. rucc takes them and assembles amocas and the byte and halfword AMOs, checked against llvm-mc" + +[[divergence]] +symbol = "RISCV_ISA_ZABHA" +reason = "follows TOOLCHAIN_HAS_ZABHA, see TOOLCHAIN_HAS_ZA*. The kernel picks the Zabha code at boot through alternatives, so a machine without it runs the same code as the gcc build" + [[flags]] flag = "/home/runner/.cache/rucc/include/*" reason = "the -isystem the kernel takes from $(CC) -print-file-name=include for the units that use the NEON intrinsics, which is where each compiler keeps its own arm_neon.h" diff --git a/crates/rk-shim/src/bringup.rs b/crates/rk-shim/src/bringup.rs index f858db0..7f392c6 100644 --- a/crates/rk-shim/src/bringup.rs +++ b/crates/rk-shim/src/bringup.rs @@ -68,15 +68,16 @@ const NEWER_THAN_BRINGUP: &[&str] = &["-fzero-init-padding-bits="]; /// The arguments a call hands to its compiler. /// -/// rk puts the era's persona in `CC` as `-fgnuc-version=` and `-fgnu-as-version=`, which only rucc -/// knows. GCC refuses -/// it, so a delegated call leaves it out, along with the flags in [`NEWER_THAN_BRINGUP`]. Every -/// other argument goes through as kbuild wrote it. +/// rk puts the era's persona in `CC` as `-fgnuc-version=` and `-fgnu-as-version=`, and on a cross +/// row `--target=`, which only rucc knows. GCC refuses it, so a delegated call leaves it out, +/// along with the flags in [`NEWER_THAN_BRINGUP`]. Every other argument goes through as kbuild +/// wrote it. #[must_use] pub fn passed_on(args: &[String], delegated: bool) -> Vec { let refused = |a: &str| { a.starts_with("-fgnuc-version=") || a.starts_with("-fgnu-as-version=") + || a.starts_with("--target=") || NEWER_THAN_BRINGUP.iter().any(|f| a.starts_with(f)) }; args.iter() @@ -183,6 +184,7 @@ mod tests { let args: Vec = [ "-fgnuc-version=14.2.0", "-fgnu-as-version=2.44", + "--target=riscv64-linux-gnu", "-m16", "-c", "-o", diff --git a/crates/rk/src/build.rs b/crates/rk/src/build.rs index f59e9fd..b5b934d 100644 --- a/crates/rk/src/build.rs +++ b/crates/rk/src/build.rs @@ -544,7 +544,7 @@ pub fn run(plan: &Plan) -> Result { std::fs::write(bin.join(rk_shim::config::FILE_NAME), config.to_toml()) .map_err(|e| format!("writing the shim's settings: {e}"))?; - let persona = if plan.compiler.rucc { + let mut persona = if plan.compiler.rucc { vec![ format!("-fgnuc-version={}", plan.era.gnuc), format!("-fgnu-as-version={}", plan.era.gnu_as), @@ -552,6 +552,11 @@ pub fn run(plan: &Plan) -> Result { } else { Vec::new() }; + // rucc takes its target from the name it is run as, and the shim runs it by its real path, + // so on a cross row it is told the target the way clang is. + if plan.compiler.rucc && !plan.row.cross.is_empty() && !host_is(&plan.row.arch) { + persona.push(format!("--target={}", plan.row.cross.trim_end_matches('-'))); + } let cc = std::iter::once(shim.display().to_string()) .chain(persona.iter().cloned()) .collect::>() diff --git a/crates/rk/src/flags.rs b/crates/rk/src/flags.rs index ae78cb6..68ed9b9 100644 --- a/crates/rk/src/flags.rs +++ b/crates/rk/src/flags.rs @@ -108,6 +108,7 @@ pub fn normalize(words: &[String], dirs: &[(&str, &str)]) -> Vec { } if word.starts_with("-fgnuc-version=") || word.starts_with("-fgnu-as-version=") + || word.starts_with("--target=") || word.starts_with("-Wp,-MD,") || word.starts_with("-Wp,-MMD,") || matches!(word.as_str(), "-MD" | "-MMD") @@ -286,7 +287,7 @@ mod tests { const GCC: &str = "savedcmd_kernel/fork.o := /g/rk-bin/rk-cc -Wp,-MMD,kernel/.fork.o.d -nostdinc -I/src/linux/include -mno-red-zone -fno-PIE -DKBUILD_MODFILE='\"kernel/fork\"' -DKBUILD_BASENAME='\"fork\"' -c -o kernel/fork.o /src/linux/kernel/fork.c ; ./tools/objtool/objtool --hacks=jump_label kernel/fork.o\n\nsource_kernel/fork.o := /src/linux/kernel/fork.c\n"; - const RUCC: &str = "savedcmd_kernel/fork.o := /r/rk-bin/rk-cc -fgnuc-version=14.2.0 -Wp,-MMD,kernel/.fork.o.d -nostdinc -I/src/linux/include -fno-PIE -DKBUILD_MODFILE='\"kernel/fork\"' -DKBUILD_BASENAME='\"fork\"' -c -o kernel/fork.o /src/linux/kernel/fork.c\n"; + const RUCC: &str = "savedcmd_kernel/fork.o := /r/rk-bin/rk-cc -fgnuc-version=14.2.0 --target=x86_64-linux-gnu -Wp,-MMD,kernel/.fork.o.d -nostdinc -I/src/linux/include -fno-PIE -DKBUILD_MODFILE='\"kernel/fork\"' -DKBUILD_BASENAME='\"fork\"' -c -o kernel/fork.o /src/linux/kernel/fork.c\n"; fn commands(text: &str, out: &str) -> Commands { let (object, words) = parse_cmd(text).unwrap(); diff --git a/crates/rk/src/probes.rs b/crates/rk/src/probes.rs index 1f100c5..84424b1 100644 --- a/crates/rk/src/probes.rs +++ b/crates/rk/src/probes.rs @@ -14,9 +14,9 @@ use rk_shim::record::CompileRecord; use std::collections::BTreeMap; use std::fmt::Write as _; -/// What a probe asks, as its arguments without the compiler, the persona, the output and the -/// names of temporary files, which change from run to run, followed by what it read on standard -/// input after `<<<`. Every `as-instr` probe has the same arguments and differs only there. +/// What a probe asks, as its arguments without the compiler, the persona (with the `--target=` a +/// cross row gives rucc), the output and the names of temporary files, which change from run to +/// run, followed by what it read on standard input after `<<<`. Every `as-instr` probe has the same arguments and differs only there. #[must_use] pub fn question(record: &CompileRecord) -> String { let mut words = Vec::new(); @@ -28,6 +28,7 @@ pub fn question(record: &CompileRecord) -> String { } if arg.starts_with("-fgnuc-version=") || arg.starts_with("-fgnu-as-version=") + || arg.starts_with("--target=") || (arg.starts_with("-o") && arg.len() > 2) { continue; @@ -190,7 +191,7 @@ mod tests { {"started":1,"argv":["/o/rk-bin/rk-cc","-c","-o","a.o","a.c"],"compiler":"/g","cwd":"/o","wall-seconds":0.1,"exit":0} "#; - const RUCC: &str = r#"{"started":1,"argv":["/p/rk-bin/rk-cc","-fgnuc-version=14.2.0","-Werror","-mno-red-zone","-c","-x","c","/dev/null","-o",".tmp_40/tmp"],"compiler":"/r","cwd":"/p","wall-seconds":0.1,"exit":0,"probe":true} + const RUCC: &str = r#"{"started":1,"argv":["/p/rk-bin/rk-cc","-fgnuc-version=14.2.0","--target=x86_64-linux-gnu","-Werror","-mno-red-zone","-c","-x","c","/dev/null","-o",".tmp_40/tmp"],"compiler":"/r","cwd":"/p","wall-seconds":0.1,"exit":0,"probe":true} {"started":1,"argv":["/p/rk-bin/rk-cc","-fgnuc-version=14.2.0","-Werror","-fcf-protection=branch","-c","-x","c","/dev/null","-o",".tmp_41/tmp"],"compiler":"/r","cwd":"/p","wall-seconds":0.1,"exit":1,"stderr":"rucc: error: unsupported option '-fcf-protection=branch'\n","probe":true} "#; diff --git a/docs/plan/10-architectures.md b/docs/plan/10-architectures.md index b40ebd5..7e932e0 100644 --- a/docs/plan/10-architectures.md +++ b/docs/plan/10-architectures.md @@ -75,7 +75,7 @@ Rows: X32 boots `i386` defconfig (`ARCH=i386 defconfig` → `i386_defconfig`) un ## 10.4 R64: riscv64 -Blocked on rucc's M9 (the RISC-V back end, parent issue #10). When it exists, kernel specifics: +rucc's RISC-V back end landed with M9, and 7.2.8 built by rucc boots on `virt` and passes the same boot, smoke and KUnit tests as gcc. Kernel specifics: | Item | Detail | |---|---| diff --git a/rows.toml b/rows.toml index cb8f99a..790601c 100644 --- a/rows.toml +++ b/rows.toml @@ -54,7 +54,7 @@ machine = "pc" cpu = "max" console = "ttyS0" -# Waits for rucc's RISC-V back end (K7). Listed so the name is taken. +# rucc runs as itself and takes its target from --target=, which rk adds to the persona on this row. [[row]] name = "R64" arch = "riscv"