Skip to content

Commit

Permalink
Runtime support for arm on iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
vhbit committed Jun 12, 2014
1 parent 9e90a5e commit d730ae2
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 36 deletions.
39 changes: 37 additions & 2 deletions src/librustrt/stack.rs
Expand Up @@ -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
Expand Down Expand Up @@ -193,14 +215,19 @@ 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);
extern {
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
Expand Down Expand Up @@ -267,12 +294,20 @@ 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;
extern {
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
}
}
24 changes: 16 additions & 8 deletions src/rt/arch/arm/_context.S
Expand Up @@ -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]
Expand Down Expand Up @@ -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
62 changes: 46 additions & 16 deletions src/rt/arch/arm/morestack.S
Expand Up @@ -8,33 +8,63 @@
.text
.code 32
.arm
#if defined(__APPLE__)
.align 2
#else
.align
#endif

#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

.global rust_stack_exhausted
.global __morestack
.hidden __morestack
#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
22 changes: 12 additions & 10 deletions 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
Expand All @@ -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

.globl RECORD_SP_LIMIT
.globl GET_SP_LIMIT

record_sp_limit:
RECORD_SP_LIMIT:
// First, try to read TLS address from coprocessor
mrc p15, #0, r3, c13, c0, #3
cmp r3, #0
Expand All @@ -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
Expand All @@ -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

0 comments on commit d730ae2

Please sign in to comment.