This ensures that each intrinsic ends up in a separate module, which in turn (because rustc treats compiler_builtins specially) will result in each intrinsic ending up in its own object file. This allows the linker to only pick up object files for intrinsics that are missing and avoids duplicate symbol definition errors.
86 lines
2.5 KiB
Rust
86 lines
2.5 KiB
Rust
#![allow(unused_imports)]
|
|
|
|
use core::intrinsics;
|
|
|
|
// NOTE These functions are implemented using assembly because they using 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
|
|
// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca
|
|
|
|
intrinsics! {
|
|
#[naked]
|
|
#[cfg(all(
|
|
windows,
|
|
target_env = "gnu",
|
|
not(feature = "no-asm")
|
|
))]
|
|
pub unsafe extern "C" fn ___chkstk_ms() {
|
|
core::arch::asm!(
|
|
"push %ecx",
|
|
"push %eax",
|
|
"cmp $0x1000,%eax",
|
|
"lea 12(%esp),%ecx",
|
|
"jb 1f",
|
|
"2:",
|
|
"sub $0x1000,%ecx",
|
|
"test %ecx,(%ecx)",
|
|
"sub $0x1000,%eax",
|
|
"cmp $0x1000,%eax",
|
|
"ja 2b",
|
|
"1:",
|
|
"sub %eax,%ecx",
|
|
"test %ecx,(%ecx)",
|
|
"pop %eax",
|
|
"pop %ecx",
|
|
"ret",
|
|
options(noreturn, att_syntax)
|
|
);
|
|
}
|
|
|
|
// FIXME: __alloca should be an alias to __chkstk
|
|
#[naked]
|
|
#[cfg(all(
|
|
windows,
|
|
target_env = "gnu",
|
|
not(feature = "no-asm")
|
|
))]
|
|
pub unsafe extern "C" fn __alloca() {
|
|
core::arch::asm!(
|
|
"jmp ___chkstk", // Jump to ___chkstk since fallthrough may be unreliable"
|
|
options(noreturn, att_syntax)
|
|
);
|
|
}
|
|
|
|
#[naked]
|
|
#[cfg(all(
|
|
windows,
|
|
target_env = "gnu",
|
|
not(feature = "no-asm")
|
|
))]
|
|
pub unsafe extern "C" fn ___chkstk() {
|
|
core::arch::asm!(
|
|
"push %ecx",
|
|
"cmp $0x1000,%eax",
|
|
"lea 8(%esp),%ecx", // esp before calling this routine -> ecx
|
|
"jb 1f",
|
|
"2:",
|
|
"sub $0x1000,%ecx",
|
|
"test %ecx,(%ecx)",
|
|
"sub $0x1000,%eax",
|
|
"cmp $0x1000,%eax",
|
|
"ja 2b",
|
|
"1:",
|
|
"sub %eax,%ecx",
|
|
"test %ecx,(%ecx)",
|
|
"lea 4(%esp),%eax", // load pointer to the return address into eax
|
|
"mov %ecx,%esp", // install the new top of stack pointer into esp
|
|
"mov -4(%eax),%ecx", // restore ecx
|
|
"push (%eax)", // push return address onto the stack
|
|
"sub %esp,%eax", // restore the original value in eax
|
|
"ret",
|
|
options(noreturn, att_syntax)
|
|
);
|
|
}
|
|
}
|