ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Rust 编译器错误 E0781 详解:为什么 `cmse-nonsecure-call` ABI 只能用于函数指针

2026/9/10 3:21:46 拓冰建站 浏览量
Rust 编译器错误 E0781 详解:为什么 `cmse-nonsecure-call` ABI 只能用于函数指针 Rust 编译器错误 E0781 详解为什么cmse-nonsecure-callABI 只能用于函数指针【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rustE0781 是 rustc 针对 ARM TrustZone CMSEControl-Memory Security Extension调用约定的一条硬错误cmse-nonsecure-callABI 不允许挂在普通函数项上只能出现在函数指针类型中。本文基于 rustc 的错误码文档 E0781.md 完整还原该错误的触发场景并深入 rustc_hir_analysis 的校验源码说明这条限制背后的调用约定约束以及如何在非安全态Non-secure state代码中正确使用这个 ABI。错误概述与触发示例rustc 错误码文档 E0781.md 对这条错误给出的原文是Thecmse-nonsecure-callABI can only be used with function pointers. cmse-nonsecure-callABI 只能用于函数指针。文档中给出的错误代码示例compile_fail,E0781测试片段如下#![feature(abi_cmse_nonsecure_call)] pub extern cmse-nonsecure-call fn test() {}这段代码的问题在于它把cmse-nonsecure-call直接写在一个函数项fn item上。rustc 会在此处报错提示该 ABI 仅允许出现在函数指针类型如extern cmse-nonsecure-call fn(...)类型的声明中。文档随后给出了正确的使用方向Thecmse-nonsecure-callABI should be used by casting function pointers to specific addresses. cmse-nonsecure-callABI 应当通过将函数指针转换cast到特定地址来使用。也就是说非安全态一侧不定义真正的函数实体而是持有指向安全侧Secure state入口点地址的函数指针经由该指针发起跨安全域的调用。背景CMSE 与两个 TrustZone ABIcmse-nonsecure-call属于 ARM Cortex-M TrustZone-CMSE 体系下的受控调用约定非安全态程序通过特殊指令跳转到安全侧的 Non-Secure Callable 入口该约定对寄存器、参数传递方式有极严格限制。在 extern_abi.rs 中可以看到 rustc 对这两个 ABI 的定位/* arm */ /// extremely constrained barely-C ABI for TrustZone CmseNonSecureCall, /// extremely constrained barely-C ABI for TrustZone CmseNonSecureEntry,源码注释将其描述为面向 TrustZone 的、约束极严的、勉强算 C 的 ABI。其中cmse-nonsecure-call非安全态Non-secure调用安全侧入口时使用的 ABI只能出现在函数指针类型上cmse-nonsecure-entry安全侧入口函数本身声明时使用的 ABI。两者在字符串化时的映射见 extern_abi.rsCmseNonSecureCall cmse-nonsecure-call。该能力由 unstable feature 门控unstable.rs 中声明为(unstable, abi_cmse_nonsecure_call, 1.90.0, Some(81391))即自 1.90.0 起以#![feature(abi_cmse_nonsecure_call)]启用removed.rs 同时记录了旧名abi_c_cmse_nonsecure_call已在 1.90.0 被移除并更名为现名。因此该错误只会在 nightly 通道、显式开启该 feature 的场景下出现。源码剖析E0781 是如何被诊断的诊断逻辑集中在 cmse.rs 的validate_cmse_abi函数中入口。对于CmseNonSecureCall分支关键判断如下匹配逻辑ExternAbi::CmseNonSecureCall match tcx.hir_node(hir_id) { // 合法当前节点是 FnPtr 类型的类型节点 hir::Node::Ty(hir::Ty { kind: hir::TyKind::FnPtr(fn_ptr_ty), .. }) fn_ptr_ty.decl, _ { // 不合法报 E0781 let span match tcx.parent_hir_node(hir_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::ForeignMod { .. }, span, .. }) *span, _ tcx.hir_span(hir_id), }; struct_span_code_err!( dcx, span, E0781, the \cmse-nonsecure-call\ ABI is only allowed on function pointers ) .emit(); return; } },从源码结构看可以归纳出以下要点触发时机validate_cmse_abi由类型降低阶段调用调用点每当 rustc 遇到携带 CMSE ABI 的函数签名时都会走一次校验判定标准编译器检查携带该 ABI 的 HIR 节点是否为TyKind::FnPtr函数指针类型节点。如果是普通fn项、extern块中的函数声明等即触发 E0781错误定位的精细处理若 ABI 写在外联模块extern cmse-nonsecure-call { ... }内的声明上报错 span 会被提升到整个ForeignModextern 块使诊断指向更合理的代码位置早退设计一旦发出 E0781函数立即return不再继续做后续的寄存器布局检查——因为对象类型都不对布局校验已无意义。为什么必须是函数指针寄存器约束是根本原因同一文件中紧随其后的两个校验函数解释了这条 ABI 的极其受限具体体现在哪参数约束is_valid_cmse_inputs所有参数必须经寄存器传递不得溢出到栈。实现上按每个参数大小向上对齐到 max(4, 对齐值)累加总量超过 16 字节即 4 个 32 位寄存器就报CmseInputsStackSpill错误返回值约束is_valid_cmse_output返回值必须放进寄存器允许 ≤4 字节或恰好 8 字节的 64 位标量i64/u64/f64含透明包装。文件头部注释L11-L13说明了设计意图参数和结果必须通过寄存器返回LLVM 也会校验这些条件但 rustc 在这里提前检查可以给出更好的错误信息。可以推断cmse-nonsecure-call的调用路径由汇编层的特殊跳转指令实现安全侧入口地址在链接期确定非安全态一侧没有常规的函数实体可供调用约定展开因此 rustc 从类型层面强制只许声明函数指针再转换到具体入口地址这一使用形态。正确写法按错误码文档的指引正确形态是声明函数指针类型 将指针转换到特定地址。结合上述寄存器约束一个典型用法示意如下#![feature(abi_cmse_nonsecure_call)] // 1. 用 cmse-nonsecure-call ABI 声明函数指针类型 // 注意参数总量 ≤ 16 字节、返回值 ≤ 4 字节或 8 字节 64 位标量 type SecureEntry unsafe extern cmse-nonsecure-call fn(u32, u32) - u32; // 2. 将安全侧入口地址如 0x0800_8000转换为该函数指针类型 let entry: SecureEntry unsafe { core::mem::transmute(0x0800_8000usize) }; // 3. 通过函数指针发起调用 let result entry(1, 2);要点回顾不要写extern cmse-nonsecure-call fn foo() {}这样的函数项——这是 E0781 的直接触发条件参数与返回值必须满足寄存器约束否则即使通过了 E0781 检查也会在后续布局校验中报CmseInputsStackSpill/CmseOutputStackSpill类错误该 feature 目前为 unstable1.90.0 起名为abi_cmse_nonsecure_call只能在 nightly 上使用此外该 ABI 也不支持#[tail_call]显式尾调用参见测试 cmse-nonsecure-call.rs。相关资源错误码定义文档E0781.mdCMSE ABI 校验实现rustc_hir_analysis/src/hir_ty_lowering/cmse.rsABI 枚举定义rustc_abi/src/extern_abi.rsfeature 门控unstable/removedrustc_feature/src/unstable.rs、rustc_feature/src/removed.rs尾调用不兼容测试tests/ui/explicit-tail-calls/unsupported-abi/cmse-nonsecure-call.rs【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考