| #![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 |
| |
| #[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] |
| #[naked] |
| #[no_mangle] |
| pub unsafe fn ___chkstk_ms() { |
| 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" ::: "memory" : "volatile"); |
| intrinsics::unreachable(); |
| } |
| |
| // FIXME: __alloca should be an alias to __chkstk |
| #[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] |
| #[naked] |
| #[no_mangle] |
| pub unsafe fn __alloca() { |
| asm!("jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable" |
| ::: "memory" : "volatile"); |
| intrinsics::unreachable(); |
| } |
| |
| #[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))] |
| #[naked] |
| #[no_mangle] |
| pub unsafe fn ___chkstk() { |
| 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" ::: "memory" : "volatile"); |
| intrinsics::unreachable(); |
| } |