From 14375593cd85034dceb81c038ef688d12d2a194c Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 May 2025 07:57:01 +0000 Subject: [PATCH 1/2] Add -Zindirect-branch-cs-prefix (from draft PR) --- compiler/rustc_codegen_llvm/src/context.rs | 9 +++++++++ compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ tests/codegen/indirect-branch-cs-prefix.rs | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 tests/codegen/indirect-branch-cs-prefix.rs diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f36f3b2b16b83..61d5533499d6a 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -451,6 +451,15 @@ pub(crate) unsafe fn create_module<'ll>( } } + if sess.opts.unstable_opts.indirect_branch_cs_prefix { + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "indirect_branch_cs_prefix", + 1, + ); + } + match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) { // Set up the small-data optimization limit for architectures that use diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 5419d688caaee..a769399fb9471 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -804,6 +804,7 @@ fn test_unstable_options_tracking_hash() { tracked!(function_sections, Some(false)); tracked!(human_readable_cgu_names, true); tracked!(incremental_ignore_spans, true); + tracked!(indirect_branch_cs_prefix, true); tracked!(inline_mir, Some(true)); tracked!(inline_mir_hint_threshold, Some(123)); tracked!(inline_mir_threshold, Some(123)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6218521d4f069..b32432a2bdc64 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2257,6 +2257,8 @@ options! { - hashes of green query instances - hash collisions of query keys - hash collisions when creating dep-nodes"), + indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "add cs prefix to call and jmp to indirect thunk (default: no)"), inline_llvm: bool = (true, parse_bool, [TRACKED], "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], diff --git a/tests/codegen/indirect-branch-cs-prefix.rs b/tests/codegen/indirect-branch-cs-prefix.rs new file mode 100644 index 0000000000000..a00b63a497081 --- /dev/null +++ b/tests/codegen/indirect-branch-cs-prefix.rs @@ -0,0 +1,18 @@ +// Test that the `indirect_branch_cs_prefix` module attribute is (not) emitted when the +// `-Zindirect-branch-cs-prefix` flag is (not) set. + +//@ add-core-stubs +//@ revisions: unset set +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [set] compile-flags: -Zindirect-branch-cs-prefix + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +// unset-NOT: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} +// set: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} From 331c2b6df9ec353209d878dc445ea8288fd69ac6 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 7 May 2025 15:38:14 +0200 Subject: [PATCH 2/2] Add `-Zindirect-branch-cs-prefix` option This is intended to be used for Linux kernel RETPOLINE builds. Signed-off-by: Miguel Ojeda --- compiler/rustc_session/messages.ftl | 2 ++ compiler/rustc_session/src/errors.rs | 4 +++ compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_session/src/session.rs | 6 ++++ .../indirect-branch-cs-prefix.md | 19 ++++++++++++ .../x86_64-indirect-branch-cs-prefix.rs | 29 +++++++++++++++++++ tests/codegen/indirect-branch-cs-prefix.rs | 8 ++--- .../requires-x86-or-x86_64.aarch64.stderr | 4 +++ .../requires-x86-or-x86_64.rs | 21 ++++++++++++++ 9 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md create mode 100644 tests/assembly/x86_64-indirect-branch-cs-prefix.rs create mode 100644 tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr create mode 100644 tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 61953614c77e1..ff5f03d121d9f 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -54,6 +54,8 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target .note = compatible flavors are: {$compatible_list} +session_indirect_branch_cs_prefix_requires_x86_or_x86_64 = `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64 + session_instrumentation_not_supported = {$us} instrumentation is not supported for this target session_int_literal_too_large = integer literal is too large diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 9c591dcf619a5..9fac0527e919f 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -471,6 +471,10 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664; #[diag(session_function_return_thunk_extern_requires_non_large_code_model)] pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; +#[derive(Diagnostic)] +#[diag(session_indirect_branch_cs_prefix_requires_x86_or_x86_64)] +pub(crate) struct IndirectBranchCsPrefixRequiresX86OrX8664; + #[derive(Diagnostic)] #[diag(session_unsupported_regparm)] pub(crate) struct UnsupportedRegparm { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b32432a2bdc64..18cce02734bbc 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2258,7 +2258,7 @@ options! { - hash collisions of query keys - hash collisions when creating dep-nodes"), indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "add cs prefix to call and jmp to indirect thunk (default: no)"), + "add `cs` prefix to `call` and `jmp` to indirect thunks (default: no)"), inline_llvm: bool = (true, parse_bool, [TRACKED], "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 6b85e0abc8683..7baa996278412 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1372,6 +1372,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + if sess.opts.unstable_opts.indirect_branch_cs_prefix { + if sess.target.arch != "x86" && sess.target.arch != "x86_64" { + sess.dcx().emit_err(errors::IndirectBranchCsPrefixRequiresX86OrX8664); + } + } + if let Some(regparm) = sess.opts.unstable_opts.regparm { if regparm > 3 { sess.dcx().emit_err(errors::UnsupportedRegparm { regparm }); diff --git a/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md b/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md new file mode 100644 index 0000000000000..040e2d4170131 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md @@ -0,0 +1,19 @@ +# `indirect-branch-cs-prefix` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116852. + +------------------------ + +Option `-Zindirect-branch-cs-prefix` controls whether a `cs` prefix is added to +`call` and `jmp` to indirect thunks. + +It is equivalent to [Clang]'s and [GCC]'s `-mindirect-branch-cs-prefix`. The +Linux kernel uses it for RETPOLINE builds. For details, see +[LLVM commit 6f867f910283] ("[X86] Support ``-mindirect-branch-cs-prefix`` for +call and jmp to indirect thunk") which introduces the feature. + +Only x86 and x86_64 are supported. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mindirect-branch-cs-prefix +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mindirect-branch-cs-prefix +[LLVM commit 6f867f910283]: https://github.com/llvm/llvm-project/commit/6f867f9102838ebe314c1f3661fdf95700386e5a diff --git a/tests/assembly/x86_64-indirect-branch-cs-prefix.rs b/tests/assembly/x86_64-indirect-branch-cs-prefix.rs new file mode 100644 index 0000000000000..2b83f002c4833 --- /dev/null +++ b/tests/assembly/x86_64-indirect-branch-cs-prefix.rs @@ -0,0 +1,29 @@ +// Test that the `cs` prefix is (not) added into a `call` and a `jmp` to the +// indirect thunk when the `-Zindirect-branch-cs-prefix` flag is (not) set. + +//@ revisions: unset set +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 -Cunsafe-allow-abi-mismatch=retpoline,retpoline-external-thunk,indirect-branch-cs-prefix -Zretpoline-external-thunk +//@ [set] compile-flags: -Zindirect-branch-cs-prefix +//@ only-x86_64 +// FIXME: Are these required? +//@ ignore-apple Symbol is called `___x86_indirect_thunk` (Darwin's extra underscore) +//@ ignore-sgx Tests incompatible with LVI mitigations + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +#[no_mangle] +pub fn foo(g: fn()) { + // unset-NOT: cs + // unset: callq {{__x86_indirect_thunk.*}} + // set: cs + // set-NEXT: callq {{__x86_indirect_thunk.*}} + g(); + + // unset-NOT: cs + // unset: jmp {{__x86_indirect_thunk.*}} + // set: cs + // set-NEXT: jmp {{__x86_indirect_thunk.*}} + g(); +} diff --git a/tests/codegen/indirect-branch-cs-prefix.rs b/tests/codegen/indirect-branch-cs-prefix.rs index a00b63a497081..df25008d5f09b 100644 --- a/tests/codegen/indirect-branch-cs-prefix.rs +++ b/tests/codegen/indirect-branch-cs-prefix.rs @@ -1,5 +1,5 @@ -// Test that the `indirect_branch_cs_prefix` module attribute is (not) emitted when the -// `-Zindirect-branch-cs-prefix` flag is (not) set. +// Test that the `indirect_branch_cs_prefix` module attribute is (not) +// emitted when the `-Zindirect-branch-cs-prefix` flag is (not) set. //@ add-core-stubs //@ revisions: unset set @@ -11,8 +11,8 @@ #![feature(no_core, lang_items)] #![no_core] -#[lang = "sized"] -trait Sized {} +extern crate minicore; +use minicore::*; // unset-NOT: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} // set: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr new file mode 100644 index 0000000000000..e3f7871da3524 --- /dev/null +++ b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs new file mode 100644 index 0000000000000..bc81c993d26ef --- /dev/null +++ b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs @@ -0,0 +1,21 @@ +//@ revisions: x86 x86_64 aarch64 + +//@ compile-flags: -Zindirect-branch-cs-prefix + +//@[x86] check-pass +//@[x86] needs-llvm-components: x86 +//@[x86] compile-flags: --target i686-unknown-linux-gnu + +//@[x86_64] check-pass +//@[x86_64] needs-llvm-components: x86 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu + +//@[aarch64] check-fail +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu + +#![feature(no_core)] +#![no_core] +#![no_main] + +//[aarch64]~? ERROR `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64