From a1ea208652f6046f01284ea7e7abab065d6513b1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 1 Sep 2016 02:04:35 +0400 Subject: [PATCH] arch/x86_64: hack to work around ld64 shortcomings on OS X. fix #35, close #36 --- .travis.yml | 3 +++ src/arch/x86_64.rs | 27 ++++++++++++++++++++++++++- src/lib.rs | 2 +- src/os/sys.rs | 4 ++-- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9e0985c..a6c0749 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ language: rust rust: nightly +os: + - linux + - osx sudo: false install: - .travis/docs/install diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 7290951..b4b4b1b 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -49,6 +49,7 @@ use stack::Stack; pub struct StackPointer(*mut usize); pub unsafe fn init(stack: &Stack, f: unsafe extern "C" fn(usize) -> !) -> StackPointer { + #[cfg(not(target_vendor = "apple"))] #[naked] unsafe extern "C" fn trampoline_1() { asm!( @@ -77,6 +78,21 @@ pub unsafe fn init(stack: &Stack, f: unsafe extern "C" fn(usize) -> !) -> StackP : : "s" (trampoline_2 as usize) : "memory" : "volatile") } + #[cfg(target_vendor = "apple")] + #[naked] + unsafe extern "C" fn trampoline_1() { + asm!( + r#" + # Same as above; however, .local and .size are not supported in Mach-O. + __morestack: + .private_extern __morestack + .cfi_def_cfa %rbx, 0 + .cfi_offset %rbp, -16 + call ${0:c} + "# + : : "s" (trampoline_2 as usize) : "memory" : "volatile") + } + #[naked] unsafe extern "C" fn trampoline_2() { asm!( @@ -84,7 +100,16 @@ pub unsafe fn init(stack: &Stack, f: unsafe extern "C" fn(usize) -> !) -> StackP # Set up the second part of our DWARF CFI. # When unwinding the frame corresponding to this function, a DWARF unwinder # will restore %rbx (and thus CFA of the first trampoline) from the stack slot. - .cfi_offset %rbx, 16 + # + # The following is functionally equivalent to: + # .cfi_offset %rbx, 16 + # however positive offsets in .cfi_offset translate to DW_CFA_offset_extended_sf, + # and ld64's CFI parser only supports regular DW_CFA_offset (which only supports + # negative offsets, with the sign being implicit), so to avoid crashing the linker + # on OS X, fold offset into DW_CFA_def_offset. + .cfi_def_cfa_offset 24 + .cfi_offset %rip, -24 + .cfi_offset %rbx, 0 # Call the provided function. call *8(%rsp) "# diff --git a/src/lib.rs b/src/lib.rs index 8fd6052..02b12e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -#![feature(asm, naked_functions)] +#![feature(asm, naked_functions, cfg_target_vendor)] #![cfg_attr(feature = "alloc", feature(alloc))] #![cfg_attr(test, feature(test, thread_local, const_fn))] #![no_std] diff --git a/src/os/sys.rs b/src/os/sys.rs index 748da41..2dae903 100644 --- a/src/os/sys.rs +++ b/src/os/sys.rs @@ -17,13 +17,13 @@ use self::libc::MAP_FAILED; const GUARD_PROT: c_int = libc::PROT_NONE; const STACK_PROT: c_int = libc::PROT_READ | libc::PROT_WRITE; -#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly")))] +#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple")))] const STACK_FLAGS: c_int = libc::MAP_STACK | libc::MAP_PRIVATE | libc::MAP_ANON; // workaround for http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html // according to libgreen, DragonFlyBSD suffers from this too -#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] +#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple"))] const STACK_FLAGS: c_int = libc::MAP_PRIVATE | libc::MAP_ANON;