Skip to content

use extern "custom" on naked functions with a custom calling convention #957

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

Merged
merged 2 commits into from
Jun 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler-builtins/src/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::intrinsics;
intrinsics! {
#[unsafe(naked)]
#[cfg(all(target_os = "uefi", not(feature = "no-asm")))]
pub unsafe extern "C" fn __chkstk() {
pub unsafe extern "custom" fn __chkstk() {
core::arch::naked_asm!(
".p2align 2",
"lsl x16, x15, #4",
Expand Down
13 changes: 6 additions & 7 deletions compiler-builtins/src/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,18 @@ unsafe extern "C" {
}

// SAFETY: these are defined in compiler-builtins
// FIXME(extern_custom), this isn't always the correct ABI
unsafe extern "aapcs" {
unsafe extern "custom" {
// AAPCS is not always the correct ABI for these intrinsics, but we only use this to
// forward another `__aeabi_` call so it doesn't matter.
fn __aeabi_idiv(a: i32, b: i32) -> i32;
fn __aeabi_idiv();
}

intrinsics! {
// NOTE This function and the ones below are implemented using assembly because they are using a
// custom calling convention which can't be implemented using a normal Rust function.
#[unsafe(naked)]
#[cfg(not(target_env = "msvc"))]
pub unsafe extern "C" fn __aeabi_uidivmod() {
pub unsafe extern "custom" fn __aeabi_uidivmod() {
core::arch::naked_asm!(
"push {{lr}}",
"sub sp, sp, #4",
Expand All @@ -35,7 +34,7 @@ intrinsics! {
}

#[unsafe(naked)]
pub unsafe extern "C" fn __aeabi_uldivmod() {
pub unsafe extern "custom" fn __aeabi_uldivmod() {
core::arch::naked_asm!(
"push {{r4, lr}}",
"sub sp, sp, #16",
Expand All @@ -51,7 +50,7 @@ intrinsics! {
}

#[unsafe(naked)]
pub unsafe extern "C" fn __aeabi_idivmod() {
pub unsafe extern "custom" fn __aeabi_idivmod() {
core::arch::naked_asm!(
"push {{r0, r1, r4, lr}}",
"bl {trampoline}",
Expand All @@ -64,7 +63,7 @@ intrinsics! {
}

#[unsafe(naked)]
pub unsafe extern "C" fn __aeabi_ldivmod() {
pub unsafe extern "custom" fn __aeabi_ldivmod() {
core::arch::naked_asm!(
"push {{r4, lr}}",
"sub sp, sp, #16",
Expand Down
2 changes: 1 addition & 1 deletion compiler-builtins/src/int/udiv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ intrinsics! {
}

#[unsafe(naked)]
pub unsafe extern "C" fn __udivmodqi4() {
pub unsafe extern "custom" fn __udivmodqi4() {
// compute unsigned 8-bit `n / d` and `n % d`.
//
// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
Expand Down
1 change: 1 addition & 0 deletions compiler-builtins/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![cfg_attr(feature = "compiler-builtins", compiler_builtins)]
#![cfg_attr(all(target_family = "wasm"), feature(wasm_numeric_instr))]
#![feature(abi_custom)]
#![feature(abi_unadjusted)]
#![feature(asm_experimental_arch)]
#![feature(cfg_target_has_atomic)]
Expand Down
15 changes: 3 additions & 12 deletions compiler-builtins/src/probestack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,12 @@
// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
// ensuring that if any pages are unmapped we'll make a page fault.
//
// FIXME(abi_custom): This function is unsafe because it uses a custom ABI,
// it does not actually match `extern "C"`.
//
// The ABI here is that the stack frame size is located in `%rax`. Upon
// return we're not supposed to modify `%rsp` or `%rax`.
#[cfg(target_arch = "x86_64")]
#[unsafe(naked)]
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rust_probestack() {
pub unsafe extern "custom" fn __rust_probestack() {
#[cfg(not(all(target_env = "sgx", target_vendor = "fortanix")))]
macro_rules! ret {
() => {
Expand Down Expand Up @@ -144,13 +141,10 @@ pub unsafe extern "C" fn __rust_probestack() {
// that on Unix we're expected to restore everything as it was, this
// function basically can't tamper with anything.
//
// FIXME(abi_custom): This function is unsafe because it uses a custom ABI,
// it does not actually match `extern "C"`.
//
// The ABI here is the same as x86_64, except everything is 32-bits large.
#[unsafe(naked)]
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rust_probestack() {
pub unsafe extern "custom" fn __rust_probestack() {
core::arch::naked_asm!(
"
.cfi_startproc
Expand Down Expand Up @@ -192,9 +186,6 @@ pub unsafe extern "C" fn __rust_probestack() {
// probestack function will also do things like _chkstk in MSVC.
// So we need to sub %ax %sp in probestack when arch is x86.
//
// FIXME(abi_custom): This function is unsafe because it uses a custom ABI,
// it does not actually match `extern "C"`.
//
// REF: Rust commit(74e80468347)
// rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805
// Comments in LLVM:
Expand All @@ -203,7 +194,7 @@ pub unsafe extern "C" fn __rust_probestack() {
// themselves.
#[unsafe(naked)]
#[rustc_std_internal_symbol]
pub unsafe extern "C" fn __rust_probestack() {
pub unsafe extern "custom" fn __rust_probestack() {
core::arch::naked_asm!(
"
.cfi_startproc
Expand Down
10 changes: 5 additions & 5 deletions compiler-builtins/src/x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use core::intrinsics;

// NOTE These functions are implemented using assembly because they using a custom
// NOTE These functions are implemented using assembly because they use a custom
// calling convention which can't be implemented using a normal Rust function

// NOTE These functions are never mangled as they are not tested against compiler-rt
Expand All @@ -13,10 +13,10 @@ intrinsics! {
any(all(windows, target_env = "gnu"), target_os = "uefi"),
not(feature = "no-asm")
))]
pub unsafe extern "C" fn __chkstk() {
pub unsafe extern "custom" fn __chkstk() {
core::arch::naked_asm!(
"jmp __alloca", // Jump to __alloca since fallthrough may be unreliable"
options(att_syntax)
"jmp {}", // Jump to __alloca since fallthrough may be unreliable"
sym crate::x86::_alloca::_alloca,
);
}

Expand All @@ -25,7 +25,7 @@ intrinsics! {
any(all(windows, target_env = "gnu"), target_os = "uefi"),
not(feature = "no-asm")
))]
pub unsafe extern "C" fn _alloca() {
pub unsafe extern "custom" fn _alloca() {
// __chkstk and _alloca are the same function
core::arch::naked_asm!(
"push %ecx",
Expand Down
4 changes: 2 additions & 2 deletions compiler-builtins/src/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use core::intrinsics;

// NOTE These functions are implemented using assembly because they using a custom
// NOTE These functions are implemented using assembly because they use a custom
// calling convention which can't be implemented using a normal Rust function

// NOTE These functions are never mangled as they are not tested against compiler-rt
Expand All @@ -17,7 +17,7 @@ intrinsics! {
),
not(feature = "no-asm")
))]
pub unsafe extern "C" fn ___chkstk_ms() {
pub unsafe extern "custom" fn ___chkstk_ms() {
core::arch::naked_asm!(
"push %rcx",
"push %rax",
Expand Down