From b6091ababa6934a13963e56c61501a434d27351b Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Tue, 16 Aug 2016 17:46:46 -0500 Subject: [PATCH 1/4] Add x86_64 builtins --- src/lib.rs | 3 +++ src/x86_64.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/x86_64.rs diff --git a/src/lib.rs b/src/lib.rs index 2263fda..7941b20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,9 @@ extern crate rlibc; #[cfg(target_arch = "arm")] pub mod arm; +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + pub mod udiv; pub mod mul; pub mod shift; diff --git a/src/x86_64.rs b/src/x86_64.rs new file mode 100644 index 0000000..5df365c --- /dev/null +++ b/src/x86_64.rs @@ -0,0 +1,67 @@ +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 +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), 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] +#[cfg_attr(not(test), no_mangle)] +pub unsafe fn __alloca() { + asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx"); + // The original behavior had __alloca fall through to ___chkstk here, but + // I don't believe that this behavior is guaranteed, and a program that uses + // only __alloca could have ___chkstk removed by --gc-sections. Call + // ___chkstk here to guarantee that neither of those happen. + ___chkstk(); +} + +#[cfg(windows)] +#[naked] +#[cfg_attr(not(test), 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(); +} + From c9bff743cdeeda92613eb8a19e91a0dc8916e71f Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 12:11:38 -0500 Subject: [PATCH 2/4] Use `jmp` to implement __alloca fallthrough --- src/x86_64.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/x86_64.rs b/src/x86_64.rs index 5df365c..8368593 100644 --- a/src/x86_64.rs +++ b/src/x86_64.rs @@ -30,12 +30,9 @@ pub unsafe fn ___chkstk_ms() { #[naked] #[cfg_attr(not(test), no_mangle)] pub unsafe fn __alloca() { - asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx"); - // The original behavior had __alloca fall through to ___chkstk here, but - // I don't believe that this behavior is guaranteed, and a program that uses - // only __alloca could have ___chkstk removed by --gc-sections. Call - // ___chkstk here to guarantee that neither of those happen. - ___chkstk(); + 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)] From aab3a10a9dd722d81bf24c16df8411ea41cebfd7 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 12:53:56 -0500 Subject: [PATCH 3/4] Disable mangling for msvc stack builtins This prevents linker errors in test builds due to the `jmp` instruction in __alloca --- src/x86_64.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/x86_64.rs b/src/x86_64.rs index 8368593..8bc3309 100644 --- a/src/x86_64.rs +++ b/src/x86_64.rs @@ -2,9 +2,13 @@ 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] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk_ms() { asm!("push %rcx push %rax @@ -28,7 +32,7 @@ pub unsafe fn ___chkstk_ms() { #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[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"); @@ -37,7 +41,7 @@ pub unsafe fn __alloca() { #[cfg(windows)] #[naked] -#[cfg_attr(not(test), no_mangle)] +#[no_mangle] pub unsafe fn ___chkstk() { asm!("push %rcx cmp $$0x1000,%rax From 6b7a00325ca17e234e8b00c20a7e58cf1b7a7867 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Wed, 17 Aug 2016 14:35:48 -0500 Subject: [PATCH 4/4] Check off x86_64 builtins in README [ci ignore] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73a25e9..4ff8b45 100644 --- a/README.md +++ b/README.md @@ -133,8 +133,8 @@ See [rust-lang/rust#35437][0]. - [x] udivsi3.c - [x] umoddi3.c - [x] umodsi3.c -- [ ] x86_64/chkstk.S -- [ ] x86_64/chkstk2.S +- [x] x86_64/chkstk.S +- [x] x86_64/chkstk2.S These builtins are needed to support 128-bit integers, which are in the process of being added to Rust.