-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C-cmse-nonsecure-call
: improved error messages
#127814
Merged
bors
merged 11 commits into
rust-lang:master
from
folkertdev:c-cmse-nonsecure-call-error-messages
Jul 19, 2024
Merged
Changes from 5 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
50ba821
add rust error message for CMSE stack spill
folkertdev 1e86064
add more tests for `cmse-nonsecure-call` stack spills
folkertdev 36d2371
make function pub in error_codes markdown file
folkertdev c7ff46c
move cmse ABI validation into its own module
folkertdev 1a79606
another attempt at fixing the examples in the error codes .md
folkertdev 09b620d
stop running code samples in the error code .md
folkertdev 5f0f690
add test for repr(transparent) enum
folkertdev 8a3dd7f
add test for unions and repr(transparent) with ZST fields
folkertdev 7b63734
move CMSE validation to hir_analysis
folkertdev 6b6b842
remove cmse validation from rustc_codegen_ssa
folkertdev c2894a4
improve error reporting
folkertdev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use rustc_middle::ty::FnSig; | ||
use rustc_span::Span; | ||
|
||
use crate::errors::{CmseCallInputsStackSpill, CmseCallOutputStackSpill}; | ||
use crate::traits::BuilderMethods; | ||
|
||
/// Check conditions on inputs and outputs that the cmse ABIs impose: arguments and results MUST be | ||
/// returned via registers (i.e. MUST NOT spill to the stack). LLVM will also validate these | ||
/// conditions, but by checking them here rustc can emit nicer error messages. | ||
pub fn validate_cmse_abi<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | ||
bx: &Bx, | ||
fn_sig: &FnSig<'tcx>, | ||
call_site_span: Span, | ||
function_definition_span: Span, | ||
) { | ||
if let rustc_target::spec::abi::Abi::CCmseNonSecureCall = fn_sig.abi { | ||
if !has_valid_inputs(bx, fn_sig) { | ||
let err = CmseCallInputsStackSpill { call_site_span, function_definition_span }; | ||
bx.tcx().dcx().emit_err(err); | ||
} | ||
|
||
if !has_valid_output(bx, fn_sig) { | ||
let err = CmseCallOutputStackSpill { call_site_span, function_definition_span }; | ||
bx.tcx().dcx().emit_err(err); | ||
} | ||
} | ||
} | ||
|
||
/// Returns whether the inputs will fit into the available registers | ||
fn has_valid_inputs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &Bx, fn_sig: &FnSig<'tcx>) -> bool { | ||
let mut accum = 0u64; | ||
|
||
for arg_def in fn_sig.inputs().iter() { | ||
let layout = bx.layout_of(*arg_def); | ||
|
||
let align = layout.layout.align().abi.bytes(); | ||
let size = layout.layout.size().bytes(); | ||
|
||
accum += size; | ||
accum = accum.next_multiple_of(Ord::max(4, align)); | ||
} | ||
|
||
// the available argument space is 16 bytes (4 32-bit registers) in total | ||
let available_space = 16; | ||
|
||
accum <= available_space | ||
} | ||
|
||
/// Returns whether the output will fit into the available registers | ||
fn has_valid_output<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &Bx, fn_sig: &FnSig<'tcx>) -> bool { | ||
let mut ret_layout = bx.layout_of(fn_sig.output()); | ||
|
||
// unwrap any `repr(transparent)` wrappers | ||
loop { | ||
if ret_layout.is_transparent::<Bx>() { | ||
match ret_layout.non_1zst_field(bx) { | ||
None => break, | ||
Some((_, layout)) => ret_layout = layout, | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
// Fundamental types of size 8 can be passed via registers according to the ABI | ||
let valid_2register_return_types = [bx.tcx().types.i64, bx.tcx().types.u64, bx.tcx().types.f64]; | ||
|
||
// A Composite Type larger than 4 bytes is stored in memory at an address | ||
// passed as an extra argument when the function was called. That is not allowed | ||
// for cmse_nonsecure_entry functions. | ||
ret_layout.layout.size().bytes() <= 4 || valid_2register_return_types.contains(&ret_layout.ty) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
Functions marked as `C-cmse-nonsecure-call` place restrictions on their | ||
inputs and outputs. | ||
|
||
- inputs must fit in the 4 available 32-bit argument registers. Alignment | ||
is relevant. | ||
- outputs must either fit in 4 bytes, or be a foundational type of | ||
size 8 (`i64`, `u64`, `f64`). | ||
|
||
For more information, | ||
see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). | ||
|
||
Erroneous code example: | ||
|
||
```compile_fail,E0798 | ||
#![feature(abi_c_cmse_nonsecure_call)] | ||
|
||
#[no_mangle] | ||
pub fn test( | ||
f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, | ||
) -> u32 { | ||
f(1, 2, 3, 4, 5) | ||
} | ||
``` | ||
folkertdev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Arguments' alignment is respected. In the example below, padding is inserted | ||
so that the `u64` argument is passed in registers r2 and r3. There is then no | ||
room left for the final `f32` argument | ||
|
||
```compile_fail,E0798 | ||
#![feature(abi_c_cmse_nonsecure_call)] | ||
|
||
#[no_mangle] | ||
pub fn test( | ||
f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, | ||
) -> u32 { | ||
f(1, 2, 3.0) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -536,6 +536,7 @@ E0794: 0794, | |
E0795: 0795, | ||
E0796: 0796, | ||
E0797: 0797, | ||
E0798: 0798, | ||
); | ||
) | ||
} | ||
|
24 changes: 0 additions & 24 deletions
24
tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs
This file was deleted.
Oops, something went wrong.
27 changes: 0 additions & 27 deletions
27
tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
This file was deleted.
Oops, something went wrong.
4 changes: 0 additions & 4 deletions
4
tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr
This file was deleted.
Oops, something went wrong.
29 changes: 29 additions & 0 deletions
29
tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//@ build-fail | ||
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib | ||
//@ needs-llvm-components: arm | ||
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] | ||
#![no_core] | ||
#[lang = "sized"] | ||
pub trait Sized {} | ||
#[lang = "copy"] | ||
pub trait Copy {} | ||
impl Copy for u32 {} | ||
|
||
#[repr(C, align(16))] | ||
#[allow(unused)] | ||
pub struct AlignRelevant(u32); | ||
|
||
#[no_mangle] | ||
pub fn test( | ||
f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, | ||
f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32, | ||
f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32, | ||
f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32, | ||
f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32, | ||
) { | ||
f1(1, 2, 3, 4, 5); //~ ERROR [E0798] | ||
f2(1, 2, 3, 4, 5); //~ ERROR [E0798] | ||
f3(1, 2, 3); //~ ERROR [E0798] | ||
f4(AlignRelevant(1), 2); //~ ERROR [E0798] | ||
f5([0xAA; 5]); //~ ERROR [E0798] | ||
} |
58 changes: 58 additions & 0 deletions
58
tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers | ||
--> $DIR/params-via-stack.rs:24:5 | ||
| | ||
LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, | ||
oli-obk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| -- this function uses the `C-cmse-nonsecure-call` ABI | ||
... | ||
LL | f1(1, 2, 3, 4, 5); | ||
| ^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers | ||
| | ||
= note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers | ||
|
||
error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers | ||
--> $DIR/params-via-stack.rs:25:5 | ||
| | ||
LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32, | ||
| -- this function uses the `C-cmse-nonsecure-call` ABI | ||
... | ||
LL | f2(1, 2, 3, 4, 5); | ||
| ^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers | ||
| | ||
= note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers | ||
|
||
error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers | ||
--> $DIR/params-via-stack.rs:26:5 | ||
| | ||
LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32, | ||
| -- this function uses the `C-cmse-nonsecure-call` ABI | ||
... | ||
LL | f3(1, 2, 3); | ||
| ^^^^^^^^^^^ but its arguments don't fit in the available registers | ||
| | ||
= note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers | ||
|
||
error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers | ||
--> $DIR/params-via-stack.rs:27:5 | ||
| | ||
LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32, | ||
| -- this function uses the `C-cmse-nonsecure-call` ABI | ||
... | ||
LL | f4(AlignRelevant(1), 2); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers | ||
| | ||
= note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers | ||
|
||
error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers | ||
--> $DIR/params-via-stack.rs:28:5 | ||
| | ||
LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32, | ||
| -- this function uses the `C-cmse-nonsecure-call` ABI | ||
... | ||
LL | f5([0xAA; 5]); | ||
| ^^^^^^^^^^^^^ but its arguments don't fit in the available registers | ||
| | ||
= note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers | ||
|
||
error: aborting due to 5 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0798`. |
41 changes: 41 additions & 0 deletions
41
tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//@ build-fail | ||
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib | ||
//@ needs-llvm-components: arm | ||
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] | ||
#![no_core] | ||
#[lang = "sized"] | ||
pub trait Sized {} | ||
#[lang = "copy"] | ||
pub trait Copy {} | ||
impl Copy for u32 {} | ||
|
||
#[repr(C)] | ||
pub struct ReprCU64(u64); | ||
|
||
#[repr(C)] | ||
pub struct ReprCBytes(u8, u8, u8, u8, u8); | ||
|
||
#[repr(C)] | ||
pub struct U64Compound(u32, u32); | ||
|
||
#[repr(C, align(16))] | ||
pub struct ReprCAlign16(u16); | ||
|
||
#[no_mangle] | ||
pub fn test( | ||
f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, | ||
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, | ||
f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, | ||
f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, | ||
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], | ||
f6: extern "C-cmse-nonsecure-call" fn() -> u128, //~ WARNING [improper_ctypes_definitions] | ||
f7: extern "C-cmse-nonsecure-call" fn() -> i128, //~ WARNING [improper_ctypes_definitions] | ||
) { | ||
f1(); //~ ERROR [E0798] | ||
f2(); //~ ERROR [E0798] | ||
f3(); //~ ERROR [E0798] | ||
f4(); //~ ERROR [E0798] | ||
f5(); //~ ERROR [E0798] | ||
f6(); //~ ERROR [E0798] | ||
f7(); //~ ERROR [E0798] | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the near future, this will also validate the
C-cmse-nonsecure-entry
abi which will be added by #127766.