1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#![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(windows)]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk_ms() {
    asm!("push   %rcx
          push   %rax
          cmp    $$0x1000,%rax
          lea    24(%rsp),%rcx
          jb     1f
          2:
          sub    $$0x1000,%rcx
          test   %rcx,(%rcx)
          sub    $$0x1000,%rax
          cmp    $$0x1000,%rax
          ja     2b
          1:
          sub    %rax,%rcx
          test   %rcx,(%rcx)
          pop    %rax
          pop    %rcx
          ret");
    intrinsics::unreachable();
}

#[cfg(windows)]
#[naked]
#[no_mangle]
pub unsafe fn __alloca() {
    asm!("mov    %rcx,%rax  // x64 _alloca is a normal function with parameter in rcx
          jmp    ___chkstk  // Jump to ___chkstk since fallthrough may be unreliable");
    intrinsics::unreachable();
}

#[cfg(windows)]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk() {
    asm!("push   %rcx
          cmp    $$0x1000,%rax
          lea    16(%rsp),%rcx  // rsp before calling this routine -> rcx
          jb     1f
          2:
          sub    $$0x1000,%rcx
          test   %rcx,(%rcx)
          sub    $$0x1000,%rax
          cmp    $$0x1000,%rax
          ja     2b
          1:
          sub    %rax,%rcx
          test   %rcx,(%rcx)

          lea    8(%rsp),%rax   // load pointer to the return address into rax
          mov    %rcx,%rsp      // install the new top of stack pointer into rsp
          mov    -8(%rax),%rcx  // restore rcx
          push   (%rax)         // push return address onto the stack
          sub    %rsp,%rax      // restore the original value in rax
          ret");
    intrinsics::unreachable();
}