惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tenable Blog
MyScale Blog
MyScale Blog
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
博客园 - 司徒正美
D
Darknet – Hacking Tools, Hacker News & Cyber Security
量子位
N
News | PayPal Newsroom
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LINUX DO - 热门话题
有赞技术团队
有赞技术团队
V
Visual Studio Blog
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Project Zero
Project Zero
B
Blog RSS Feed
J
Java Code Geeks
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
小众软件
小众软件
博客园 - 【当耐特】
Latest news
Latest news
T
Threat Research - Cisco Blogs
aimingoo的专栏
aimingoo的专栏
博客园_首页
博客园 - 三生石上(FineUI控件)
Engineering at Meta
Engineering at Meta
D
Docker
Forbes - Security
Forbes - Security
Help Net Security
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V2EX - 技术
V2EX - 技术
N
Netflix TechBlog - Medium
The Last Watchdog
The Last Watchdog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Threatpost
Cloudbric
Cloudbric
T
The Exploit Database - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
Webroot Blog
Webroot Blog

Rust Blog

Security Advisory for Cargo (CVE-2026-5223) | Rust Blog Security Advisory for Cargo (CVE-2026-5222) | Rust Blog Project goals update — April 2026 (end of 2025H2) | Rust Blog Rust is participating in Outreachy | Rust Blog Raising the baseline for the `nvptx64-nvidia-cuda` target | Rust Blog Announcing Google Summer of Code 2026 selected projects | Rust Blog Announcing Rust 1.95.0 | Rust Blog docs.rs: building fewer targets by default | Rust Blog Changes to WebAssembly targets and handling undefined symbols | Rust Blog Announcing Rust 1.94.1 | Rust Blog Security advisory for Cargo | Rust Blog What we heard about Rust's challenges | Rust Blog Call for Testing: Build Dir Layout v2 | Rust Blog Announcing rustup 1.29.0 | Rust Blog Announcing Rust 1.94.0 | Rust Blog 2025 State of Rust Survey Results | Rust Blog Rust debugging survey 2026 | Rust Blog Update on the October 15, 2018 incident on crates.io Announcing Rust 1.29.2 Announcing Rust 1.29 Announcing Rust 1.28 What is Rust 2018? Announcing Rust 1.27.2 Announcing Rust 1.27.1 Security Advisory for rustdoc Announcing Rust 1.27 Announcing Rust 1.26.2 Announcing Rust 1.26.1 Rust turns three Announcing Rust 1.26 The Rust Team All Hands in Berlin: a Recap Increasing Rust’s Reach 2018 Announcing Rust 1.25 Rust's 2018 roadmap Announcing Rust 1.24.1 Announcing Rust 1.24 The 2018 Rust Event Lineup Announcing Rust 1.23 New Year's Rust: A Call for Community Blogposts Rust in 2017: what we achieved Announcing Rust 1.22 (and 1.22.1) Fearless Concurrency in Firefox Quantum Announcing Rust 1.21 impl Future for Rust Rust 2017 Survey Results Announcing Rust 1.20 Announcing Rust 1.19 The 2017 Rust Conference Lineup Rust's 2017 roadmap, six months in Increasing Rust’s Reach Announcing Rust 1.18 Two years of Rust The Rust Libz Blitz Launching the 2017 State of Rust Survey Announcing Rust 1.17 Announcing Rust 1.16 Rust's language ergonomics initiative Announcing Rust 1.15.1 Rust's 2017 roadmap Announcing Rust 1.15 Announcing Rust 1.14 Announcing the First Underhanded Rust Contest Announcing Rust 1.13 Announcing Rust 1.12.1 Announcing Rust 1.12 Incremental Compilation Announcing Rust 1.11 Shape of errors to come The 2016 Rust Conference Lineup Announcing Rust 1.10 State of Rust Survey 2016 Announcing Rust 1.9 One year of Rust Taking Rust everywhere with rustup Launching the 2016 State of Rust Survey Cargo: predictable dependency management Introducing MIR Announcing Rust 1.8 Announcing Rust 1.7 Announcing Rust 1.6 Announcing Rust 1.5 Announcing Rust 1.4 Announcing Rust 1.3 Rust in 2016 Announcing Rust 1.2 Rust 1.1 stable, the Community Subteam, and RustCamp Announcing Rust 1.0 Abstraction without overhead: traits in Rust Rust Once, Run Everywhere Mixing matching, mutation, and moves in Rust Fearless Concurrency with Rust Announcing Rust 1.0 Beta Announcing Rust 1.0.0.alpha.2 Rust 1.0: status report and final timeline Announcing Rust 1.0 Alpha Rust 1.0: Scheduling the trains Yehuda Katz and Steve Klabnik are joining the Rust Core Team Cargo: Rust's community crate host Stability as a Deliverable Road to Rust 1.0
Stabilizing naked functions
Folkert de Vries · 2025-07-03 · via Rust Blog

Rust 1.88.0 stabilizes the #[unsafe(naked)] attribute and the naked_asm! macro which are used to define naked functions.

A naked function is marked with the #[unsafe(naked)] attribute, and its body consists of a single naked_asm! call. For example:

/// SAFETY: Respects the 64-bit System-V ABI.
#[unsafe(naked)]
pub extern "sysv64" fn wrapping_add(a: u64, b: u64) -> u64 {
    // Equivalent to `a.wrapping_add(b)`.
    core::arch::naked_asm!(
        "lea rax, [rdi + rsi]",
        "ret"
    );
}

What makes naked functions special — and gives them their name — is that the handwritten assembly block defines the entire function body. Unlike non-naked functions, the compiler does not add any special handling for arguments or return values.

This feature is a more ergonomic alternative to defining functions using global_asm!. Naked functions are used in low-level settings like Rust's compiler-builtins, operating systems, and embedded applications.

Why use naked functions?

But wait, if naked functions are just syntactic sugar for global_asm!, why add them in the first place?

To see the benefits, let's rewrite the wrapping_add example from the introduction using global_asm!:

// SAFETY: `wrapping_add` is defined in this module,
// and expects the 64-bit System-V ABI.
unsafe extern "sysv64" {
    safe fn wrapping_add(a: u64, b: u64) -> u64
}

core::arch::global_asm!(
    r#"
        // Platform-specific directives that set up a function.
        .section .text.wrapping_add,"ax",@progbits
        .p2align 2
        .globl wrapping_add
        .type wrapping_add,@function

wrapping_add:
        lea rax, [rdi + rsi]
        ret

.Ltmp0:
        .size wrapping_add, .Ltmp0-wrapping_add
    "#
);

The assembly block starts and ends with the directives (.section, .p2align, etc.) that are required to define a function. These directives are mechanical, but they are different between object file formats. A naked function will automatically emit the right directives.

Next, the wrapping_add name is hardcoded, and will not participate in Rust's name mangling. That makes it harder to write cross-platform code, because different targets have different name mangling schemes (e.g. x86_64 macOS prefixes symbols with _, but Linux does not). The unmangled symbol is also globally visible — so that the extern block can find it — which can cause symbol resolution conflicts. A naked function's name does participate in name mangling and won't run into these issues.

A further limitation that this example does not show is that functions defined using global assembly cannot use generics. Especially const generics are useful in combination with assembly.

Finally, having just one definition provides a consistent place for (safety) documentation and attributes, with less risk of them getting out of date. Proper safety comments are essential for naked functions. The naked attribute is unsafe because the ABI (sysv64 in our example), the signature, and the implementation have to be consistent.

How did we get here?

Naked functions have been in the works for a long time.

The original RFC for naked functions is from 2015. That RFC was superseded by RFC 2972 in 2020. Inline assembly in Rust had changed substantially at that point, and the new RFC limited the body of naked functions to a single asm! call with some additional constraints. And now, 10 years after the initial proposal, naked functions are stable.

Two additional notable changes helped prepare naked functions for stabilization:

Introduction of the naked_asm! macro

The body of a naked function must be a single naked_asm! call. This macro is a blend between asm! (it is in a function body) and global_asm! (only some operand types are accepted).

The initial implementation of RFC 2972 added lints onto a standard asm! call in a naked function. This approach made it hard to write clear error messages and documentation. With the dedicated naked_asm! macro the behavior is much easier to specify.

Lowering to global_asm!

The initial implementation relied on LLVM to lower functions with the naked attribute for code generation. This approach had two issues:

  • LLVM would sometimes add unexpected additional instructions to what the user wrote.
  • Rust has non-LLVM code generation backends now, and they would have had to implement LLVM's (unspecified!) behavior.

The implementation that is stabilized now instead converts the naked function into a piece of global assembly. The code generation backends can already emit global assembly, and this strategy guarantees that the whole body of the function is just the instructions that the user wrote.

What's next for assembly?

We're working on further assembly ergonomics improvements. If naked functions are something you are excited about and (may) use, we'd appreciate you testing these new features and providing feedback on their designs.

extern "custom" functions

Naked functions usually get the extern "C" calling convention. But often that calling convention is a lie. In many cases, naked functions don't implement an ABI that Rust knows about. Instead they use some custom calling convention that is specific to that function.

The abi_custom feature adds extern "custom" functions and blocks, which allows us to correctly write code like this example from compiler-builtins:

#![feature(abi_custom)]

/// Division and modulo of two numbers using Arm's nonstandard ABI.
///
/// ```c
/// typedef struct { int quot; int rem; } idiv_return;
///  __value_in_regs idiv_return __aeabi_idivmod(int num, int denom);
/// ```
// SAFETY: The assembly implements the expected ABI, and "custom"
// ensures this function cannot be called directly.
#[unsafe(naked)]
pub unsafe extern "custom" fn __aeabi_idivmod() {
    core::arch::naked_asm!(
        "push {{r0, r1, r4, lr}}", // Back up clobbers.
        "bl {trampoline}",         // Call an `extern "C"` function for a / b.
        "pop {{r1, r2}}",
        "muls r2, r2, r0",         // Perform the modulo.
        "subs r1, r1, r2",
        "pop {{r4, pc}}",          // Restore clobbers, implicit return by setting `pc`.
        trampoline = sym crate::arm::__aeabi_idiv,
    );
}

A consequence of using a custom calling convention is that such functions cannot be called using a Rust call expression; the compiler simply does not know how to generate correct code for such a call. Instead the compiler will error when the program does try to call an extern "custom" function, and the only way to execute the function is using inline assembly.

cfg on lines of inline assembly

The cfg_asm feature adds the ability to annotate individual lines of an assembly block with #[cfg(...)] or #[cfg_attr(..., ...)]. Configuring specific sections of assembly is useful to make assembly depend on, for instance, the target, target features, or feature flags. For example:

#![feature(cfg_asm)]

global_asm!(
    // ...

    // If enabled, initialise the SP. This is normally
    // initialised by the CPU itself or by a bootloader, but
    // some debuggers fail to set it when resetting the
    // target, leading to stack corruptions.
    #[cfg(feature = "set-sp")]
    "ldr r0, =_stack_start
     msr msp, r0",

     // ...
)

This example is from the cortex-m crate that currently has to use a custom macro that duplicates the whole assembly block for every use of #[cfg(...)]. With cfg_asm, that will no longer be necessary.