summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/arm
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/linux/arm')
-rw-r--r--libc/sysdeps/linux/arm/bits/syscalls.h57
-rw-r--r--libc/sysdeps/linux/arm/clone.S75
-rw-r--r--libc/sysdeps/linux/arm/sysdep.h36
3 files changed, 111 insertions, 57 deletions
diff --git a/libc/sysdeps/linux/arm/bits/syscalls.h b/libc/sysdeps/linux/arm/bits/syscalls.h
index 5544ca652..e447a7b2d 100644
--- a/libc/sysdeps/linux/arm/bits/syscalls.h
+++ b/libc/sysdeps/linux/arm/bits/syscalls.h
@@ -43,41 +43,7 @@
}) \
)
-#if !defined(__thumb__)
-#if defined(__ARM_EABI__)
-#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
-(__extension__ \
- ({unsigned int __internal_sys_result; \
- { \
- register int __a1 __asm__ ("r0"), _nr __asm__ ("r7"); \
- LOAD_ARGS_##nr (args) \
- _nr = (name); \
- __asm__ __volatile__ ("swi 0x0 @ syscall " #name \
- : "=r" (__a1) \
- : "r" (_nr) ASM_ARGS_##nr \
- : "memory"); \
- __internal_sys_result = __a1; \
- } \
- (int) __internal_sys_result; }) \
-)
-#else /* defined(__ARM_EABI__) */
-
-#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
-(__extension__ \
- ({ unsigned int __internal_sys_result; \
- { \
- register int __a1 __asm__ ("a1"); \
- LOAD_ARGS_##nr (args) \
- __asm__ __volatile__ ("swi %1 @ syscall " #name \
- : "=r" (__a1) \
- : "i" (name) ASM_ARGS_##nr \
- : "memory"); \
- __internal_sys_result = __a1; \
- } \
- (int) __internal_sys_result; }) \
-)
-#endif
-#else /* !defined(__thumb__) */
+#if defined(__thumb__)
/* We can't use push/pop inside the asm because that breaks
unwinding (ie. thread cancellation).
*/
@@ -101,7 +67,23 @@
} \
(int) __internal_sys_result; }) \
)
-#endif /*!defined(__thumb__)*/
+#else /* ARM */
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
+(__extension__ \
+ ({unsigned int __internal_sys_result; \
+ { \
+ register int __a1 __asm__ ("r0"), _nr __asm__ ("r7"); \
+ LOAD_ARGS_##nr (args) \
+ _nr = (name); \
+ __asm__ __volatile__ ("swi 0x0 @ syscall " #name \
+ : "=r" (__a1) \
+ : "r" (_nr) ASM_ARGS_##nr \
+ : "memory"); \
+ __internal_sys_result = __a1; \
+ } \
+ (int) __internal_sys_result; }) \
+)
+#endif
#define INTERNAL_SYSCALL_ERROR_P(val, err) \
((unsigned int) (val) >= 0xfffff001u)
@@ -138,12 +120,13 @@
LOAD_ARGS_5 (a1, a2, a3, a4, a5) \
register int __v2 __asm__ ("v2") = __v2tmp;
#define ASM_ARGS_6 ASM_ARGS_5, "r" (__v2)
+#ifndef __thumb__
#define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \
int __v3tmp = (int) (a7); \
LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) \
register int __v3 __asm__ ("v3") = __v3tmp;
#define ASM_ARGS_7 ASM_ARGS_6, "r" (__v3)
-
+#endif
#endif /* __ASSEMBLER__ */
#endif /* _BITS_SYSCALLS_H */
diff --git a/libc/sysdeps/linux/arm/clone.S b/libc/sysdeps/linux/arm/clone.S
index 03cd10e62..d1c9239da 100644
--- a/libc/sysdeps/linux/arm/clone.S
+++ b/libc/sysdeps/linux/arm/clone.S
@@ -19,6 +19,7 @@
/* clone() is even more special than fork() as it mucks with stacks
and invokes a function in the right context after its all over. */
+#include <sysdep.h>
#define _ERRNO_H
#include <features.h>
#include <bits/errno.h>
@@ -26,6 +27,13 @@
#include <bits/arm_asm.h>
#include <bits/arm_bx.h>
+#if defined __UCLIBC_HAS_THREADS__ && !defined __LINUXTHREADS_OLD__
+#include <sysdep-cancel.h>
+#endif
+
+#define CLONE_VM 0x00000100
+#define CLONE_THREAD 0x00010000
+
#if defined(__NR_clone)
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
@@ -52,23 +60,22 @@ __clone:
@ get flags
mov r0, r2
@ new sp is already in r1
- @ load remaining arguments off the stack
- stmfd sp!, {r4}
- ldr r2, [sp, #4]
- ldr r3, [sp, #8]
- ldr r4, [sp, #12]
DO_CALL (clone)
movs a1, a1
blt __error
- ldmnefd sp!, {r4}
beq 1f
bx lr
1:
@ pick the function arg and call address off the stack and execute
ldr r0, [sp, #4]
+#if defined(__USE_BX__)
ldr r1, [sp]
bl 2f @ blx r1
+#else
+ mov lr, pc
+ ldr pc, [sp]
+#endif
@ and we are done, passing the return value through r0
bl HIDDEN_JUMPTARGET(_exit)
@@ -87,6 +94,8 @@ __error:
.pool
#else
__clone:
+.fnstart
+.cantunwind
@ sanity check args
cmp r0, #0
IT(te, ne)
@@ -95,32 +104,58 @@ __clone:
beq __error
@ insert the args onto the new stack
- sub r1, r1, #8
- str r3, [r1, #4]
- @ save the function pointer as the 0th element
- str r0, [r1]
+ str r3, [r1, #-4]!
+ str r0, [r1, #-4]!
@ do the system call
@ get flags
mov r0, r2
+#ifdef RESET_PID
+ mov ip, r2
+#endif
@ new sp is already in r1
- @ load remaining arguments off the stack
- stmfd sp!, {r4}
- ldr r2, [sp, #4]
- ldr r3, [sp, #8]
- ldr r4, [sp, #12]
- DO_CALL (clone)
- movs a1, a1
- IT(t, ne)
- ldmnefd sp!, {r4}
+ push {r4, r7}
+ cfi_adjust_cfa_offset (8)
+ cfi_rel_offset (r4, 0)
+ cfi_rel_offset (r7, 4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ ldr r4, [sp, #16]
+ ldr r7, =SYS_ify(clone)
+ swi 0x0
+ cfi_endproc
+ cmp r0, #0
+ beq 1f
+ pop {r4, r7}
blt __error
- IT(t, ne)
#if defined(__USE_BX__)
bxne lr
#else
movne pc, lr
#endif
+ cfi_startproc
+.fnend
+PSEUDO_END (__clone)
+
+1:
+ .fnstart
+ .cantunwind
+#ifdef RESET_PID
+ tst ip, #CLONE_THREAD
+ bne 3f
+ GET_TLS (lr)
+ mov r1, r0
+ tst ip, #CLONE_VM
+ ldr r7, =SYS_ify(getpid)
+ ite ne
+ movne r0, #-1
+ swieq 0x0
+ NEGOFF_ADJ_BASE (r1, TID_OFFSET)
+ str r0, NEGOFF_OFF1 (r1, TID_OFFSET)
+ str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET)
+3:
+#endif
@ pick the function arg and call address off the stack and execute
ldr r0, [sp, #4]
mov lr, pc
diff --git a/libc/sysdeps/linux/arm/sysdep.h b/libc/sysdeps/linux/arm/sysdep.h
index 64f40407e..2d0a9cc41 100644
--- a/libc/sysdeps/linux/arm/sysdep.h
+++ b/libc/sysdeps/linux/arm/sysdep.h
@@ -213,6 +213,42 @@ __local_syscall_error: \
sees the right arguments.
*/
+#if __ARM_ARCH > 6 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6ZK__)
+# define ARCH_HAS_HARD_TP
+#endif
+
+# ifdef __thumb2__
+# define NEGOFF_ADJ_BASE(R, OFF) add R, R, $OFF
+# define NEGOFF_ADJ_BASE2(D, S, OFF) add D, S, $OFF
+# define NEGOFF_OFF1(R, OFF) [R]
+# define NEGOFF_OFF2(R, OFFA, OFFB) [R, $((OFFA) - (OFFB))]
+# else
+# define NEGOFF_ADJ_BASE(R, OFF)
+# define NEGOFF_ADJ_BASE2(D, S, OFF) mov D, S
+# define NEGOFF_OFF1(R, OFF) [R, $OFF]
+# define NEGOFF_OFF2(R, OFFA, OFFB) [R, $OFFA]
+# endif
+
+# ifdef ARCH_HAS_HARD_TP
+/* If the cpu has cp15 available, use it. */
+# define GET_TLS(TMP) mrc p15, 0, r0, c13, c0, 3
+# else
+/* At this generic level we have no tricks to pull. Call the ABI routine. */
+# define GET_TLS(TMP) \
+ push { r1, r2, r3, lr }; \
+ cfi_remember_state; \
+ cfi_adjust_cfa_offset (16); \
+ cfi_rel_offset (r1, 0); \
+ cfi_rel_offset (r2, 4); \
+ cfi_rel_offset (r3, 8); \
+ cfi_rel_offset (lr, 12); \
+ bl __aeabi_read_tp; \
+ pop { r1, r2, r3, lr }; \
+ cfi_restore_state
+# endif /* ARCH_HAS_HARD_TP */
+
+
+
#undef DO_CALL
#if defined(__ARM_EABI__)