From d730ae2fb0c455775fb1962454537c79e54f817e Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Mon, 5 May 2014 10:08:34 +0300 Subject: [PATCH] Runtime support for arm on iOS --- src/librustrt/stack.rs | 39 +++++++++++++++++++++-- src/rt/arch/arm/_context.S | 24 +++++++++----- src/rt/arch/arm/morestack.S | 62 +++++++++++++++++++++++++++---------- src/rt/arch/arm/record_sp.S | 22 +++++++------ 4 files changed, 111 insertions(+), 36 deletions(-) diff --git a/src/librustrt/stack.rs b/src/librustrt/stack.rs index 148d93adc848..aac773f6f859 100644 --- a/src/librustrt/stack.rs +++ b/src/librustrt/stack.rs @@ -24,6 +24,28 @@ //! detection is not guaranteed to continue in the future. Usage of this module //! is discouraged unless absolutely necessary. +// iOS related notes +// +// It is possible to implement it using idea from +// http://www.opensource.apple.com/source/Libc/Libc-825.40.1/pthreads/pthread_machdep.h +// +// In short: _pthread_{get,set}_specific_direct allows extremely fast +// access, exactly what is required for segmented stack +// There is a pool of reserved slots for Apple internal use (0..119) +// First dynamic allocated pthread key starts with 257 (on iOS7) +// So using slot 149 should be pretty safe ASSUMING space is reserved +// for every key < first dynamic key +// +// There is also an opportunity to steal keys reserved for Garbage Collection +// ranges 80..89 and 110..119, especially considering the fact Garbage Collection +// never supposed to work on iOS. But as everybody knows it - there is a chance +// that those slots will be re-used, like it happened with key 95 (moved from +// JavaScriptCore to CoreText) +// +// Unfortunately Apple rejected patch to LLVM which generated +// corresponding prolog, decision was taken to disable segmented +// stack support on iOS. + pub static RED_ZONE: uint = 20 * 1024; /// This function is invoked from rust's current __morestack function. Segmented @@ -193,7 +215,7 @@ pub unsafe fn record_sp_limit(limit: uint) { // mips, arm - Some brave soul can port these to inline asm, but it's over // my head personally #[cfg(target_arch = "mips")] - #[cfg(target_arch = "arm")] #[inline(always)] + #[cfg(target_arch = "arm", not(target_os = "ios"))] #[inline(always)] unsafe fn target_record_sp_limit(limit: uint) { use libc::c_void; return record_sp_limit(limit as *c_void); @@ -201,6 +223,11 @@ pub unsafe fn record_sp_limit(limit: uint) { fn record_sp_limit(limit: *c_void); } } + + // iOS segmented stack is disabled for now, see related notes + #[cfg(target_arch = "arm", target_os = "ios")] #[inline(always)] + unsafe fn target_record_sp_limit(_: uint) { + } } /// The counterpart of the function above, this function will fetch the current @@ -267,7 +294,7 @@ pub unsafe fn get_sp_limit() -> uint { // mips, arm - Some brave soul can port these to inline asm, but it's over // my head personally #[cfg(target_arch = "mips")] - #[cfg(target_arch = "arm")] #[inline(always)] + #[cfg(target_arch = "arm", not(target_os = "ios"))] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { use libc::c_void; return get_sp_limit() as uint; @@ -275,4 +302,12 @@ pub unsafe fn get_sp_limit() -> uint { fn get_sp_limit() -> *c_void; } } + + // iOS doesn't support segmented stacks yet. This function might + // be called by runtime though so it is unsafe to mark it as + // unreachable, let's return a fixed constant. + #[cfg(target_arch = "arm", target_os = "ios")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + 1024 + } } diff --git a/src/rt/arch/arm/_context.S b/src/rt/arch/arm/_context.S index fb6db57414a5..38fc4827f586 100644 --- a/src/rt/arch/arm/_context.S +++ b/src/rt/arch/arm/_context.S @@ -12,8 +12,16 @@ .align #endif -.globl rust_swap_registers -rust_swap_registers: +#if defined(__APPLE__) + #define SWAP_REGISTERS _rust_swap_registers + #define BOOTSTRAP_TASK _rust_bootstrap_green_task +#else + #define SWAP_REGISTERS rust_swap_registers + #define BOOTSTRAP_TASK rust_bootstrap_green_task +#endif + +.globl SWAP_REGISTERS +SWAP_REGISTERS: str r0, [r0, #0] str r3, [r0, #12] str r4, [r0, #16] @@ -53,9 +61,9 @@ rust_swap_registers: mov pc, lr // For reasons of this existence, see the comments in x86_64/_context.S -.globl rust_bootstrap_green_task -rust_bootstrap_green_task: - mov r0, r0 - mov r1, r3 - mov r2, r4 - mov pc, r5 +.globl BOOTSTRAP_TASK +BOOTSTRAP_TASK: + mov r0, r0 + mov r1, r3 + mov r2, r4 + mov pc, r5 diff --git a/src/rt/arch/arm/morestack.S b/src/rt/arch/arm/morestack.S index 219f0962d771..0b9012cc2a80 100644 --- a/src/rt/arch/arm/morestack.S +++ b/src/rt/arch/arm/morestack.S @@ -8,33 +8,63 @@ .text .code 32 .arm +#if defined(__APPLE__) +.align 2 +#else .align +#endif -.global rust_stack_exhausted -.global __morestack -.hidden __morestack +#if defined(__APPLE__) +#define MORESTACK ___morestack +#define STACK_EXHAUSTED _rust_stack_exhausted +#else +#define MORESTACK __morestack +#define STACK_EXHAUSTED rust_stack_exhausted +#endif + +.global STACK_EXHAUSTED +.global MORESTACK + +// Unfortunately LLVM yet doesn't support emitting correct debug +// DWARF information for non-ELF targets so to make it compile +// on iOS all that directives are simply commented out +#if defined(__APPLE__) +#define UNWIND @ +#else +#define UNWIND +#endif + +#if defined(__APPLE__) +.private_extern MORESTACK +#else +.hidden MORESTACK +#endif + +#if !defined(__APPLE__) + .type MORESTACK,%function +#endif // r4 and r5 are scratch registers for __morestack due to llvm // ARMFrameLowering::adjustForSegmentedStacks() implementation. - .type __morestack,%function -__morestack: - .fnstart - // Save frame pointer and return address - .save {r4, r5} - .save {lr} - .save {r6, fp, lr} +MORESTACK: + UNWIND .fnstart + + // Save frame pointer and return address + UNWIND .save {r4, r5} + UNWIND .save {lr} + UNWIND .save {r6, fp, lr} push {r6, fp, lr} - .movsp r6 - mov r6, sp - .setfp fp, sp, #4 - add fp, sp, #4 + UNWIND .movsp r6 + mov r6, sp + UNWIND .setfp fp, sp, #4 + add fp, sp, #4 // Save argument registers of the original function push {r0, r1, r2, r3, lr} // Create new stack - bl rust_stack_exhausted@plt + bl STACK_EXHAUSTED@plt // the above function ensures that it never returns - .fnend + UNWIND .fnend diff --git a/src/rt/arch/arm/record_sp.S b/src/rt/arch/arm/record_sp.S index cce14ed5a3ec..94cfcff039e4 100644 --- a/src/rt/arch/arm/record_sp.S +++ b/src/rt/arch/arm/record_sp.S @@ -1,3 +1,5 @@ +// Do not compile anything here for iOS +#if !defined(__APPLE__) // Mark stack as non-executable #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack, "", %progbits @@ -6,16 +8,15 @@ .text .code 32 .arm -#if defined(__APPLE__) -.align 2 -#else .align -#endif -.globl record_sp_limit -.globl get_sp_limit +#define RECORD_SP_LIMIT record_sp_limit +#define GET_SP_LIMIT get_sp_limit -record_sp_limit: +.globl RECORD_SP_LIMIT +.globl GET_SP_LIMIT + +RECORD_SP_LIMIT: // First, try to read TLS address from coprocessor mrc p15, #0, r3, c13, c0, #3 cmp r3, #0 @@ -27,12 +28,12 @@ record_sp_limit: add r3, r3, #252 #elif __linux__ add r3, r3, #4 -#endif +#endif // ANDROID str r0, [r3] mov pc, lr -get_sp_limit: +GET_SP_LIMIT: // First, try to read TLS address from coprocessor mrc p15, #0, r3, c13, c0, #3 cmp r3, #0 @@ -44,7 +45,8 @@ get_sp_limit: add r3, r3, #252 #elif __linux__ add r3, r3, #4 -#endif +#endif // __ANDROID__ ldr r0, [r3] mov pc, lr +#endif