1 | #![allow (unused_imports)] |
2 | |
3 | use core::intrinsics; |
4 | |
5 | // NOTE These functions are implemented using assembly because they using a custom |
6 | // calling convention which can't be implemented using a normal Rust function |
7 | |
8 | // NOTE These functions are never mangled as they are not tested against compiler-rt |
9 | // and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca |
10 | |
11 | intrinsics! { |
12 | #[naked] |
13 | #[cfg (all( |
14 | any(all(windows, target_env = "gnu" ), target_os = "uefi" ), |
15 | not(feature = "no-asm" ) |
16 | ))] |
17 | pub unsafe extern "C" fn ___chkstk_ms() { |
18 | core::arch::asm!( |
19 | "push %rcx" , |
20 | "push %rax" , |
21 | "cmp $0x1000,%rax" , |
22 | "lea 24(%rsp),%rcx" , |
23 | "jb 1f" , |
24 | "2:" , |
25 | "sub $0x1000,%rcx" , |
26 | "test %rcx,(%rcx)" , |
27 | "sub $0x1000,%rax" , |
28 | "cmp $0x1000,%rax" , |
29 | "ja 2b" , |
30 | "1:" , |
31 | "sub %rax,%rcx" , |
32 | "test %rcx,(%rcx)" , |
33 | "pop %rax" , |
34 | "pop %rcx" , |
35 | "ret" , |
36 | options(noreturn, att_syntax) |
37 | ); |
38 | } |
39 | |
40 | #[naked] |
41 | #[cfg (all( |
42 | any(all(windows, target_env = "gnu" ), target_os = "uefi" ), |
43 | not(feature = "no-asm" ) |
44 | ))] |
45 | pub unsafe extern "C" fn __alloca() { |
46 | core::arch::asm!( |
47 | "mov %rcx,%rax" , // x64 _alloca is a normal function with parameter in rcx |
48 | "jmp ___chkstk" , // Jump to ___chkstk since fallthrough may be unreliable" |
49 | options(noreturn, att_syntax) |
50 | ); |
51 | } |
52 | |
53 | #[naked] |
54 | #[cfg (all( |
55 | any(all(windows, target_env = "gnu" ), target_os = "uefi" ), |
56 | not(feature = "no-asm" ) |
57 | ))] |
58 | pub unsafe extern "C" fn ___chkstk() { |
59 | core::arch::asm!( |
60 | "push %rcx" , |
61 | "cmp $0x1000,%rax" , |
62 | "lea 16(%rsp),%rcx" , // rsp before calling this routine -> rcx |
63 | "jb 1f" , |
64 | "2:" , |
65 | "sub $0x1000,%rcx" , |
66 | "test %rcx,(%rcx)" , |
67 | "sub $0x1000,%rax" , |
68 | "cmp $0x1000,%rax" , |
69 | "ja 2b" , |
70 | "1:" , |
71 | "sub %rax,%rcx" , |
72 | "test %rcx,(%rcx)" , |
73 | "lea 8(%rsp),%rax" , // load pointer to the return address into rax |
74 | "mov %rcx,%rsp" , // install the new top of stack pointer into rsp |
75 | "mov -8(%rax),%rcx" , // restore rcx |
76 | "push (%rax)" , // push return address onto the stack |
77 | "sub %rsp,%rax" , // restore the original value in rax |
78 | "ret" , |
79 | options(noreturn, att_syntax) |
80 | ); |
81 | } |
82 | } |
83 | |
84 | // HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM |
85 | // support unless we emit the _fltused |
86 | mod _fltused { |
87 | #[no_mangle ] |
88 | #[used ] |
89 | #[cfg (target_os = "uefi" )] |
90 | static _fltused: i32 = 0; |
91 | } |
92 | |