From 9a7cb556eef7cb75b31d0bc05f73c6338dfd8e49 Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@redhat.com>
Date: Fri, 30 May 2014 13:57:04 -0400
Subject: [PATCH] aarch64: Backport syscall rewrite
From commits:
a60339aaff82beadea6f580e587d64052cb5e3b8 Fix handling of nocancel syscall...
3612eb8f25d978e7e4ac536a34098091f737161c Merge rtld_errno offset w/ mem ref
a6b3657be6bc5067aeec98d990f60765361c6557 Merge __local_multiple_threads ofs...
c69abcee726a6f63d9e5e8f0d9dcc79374ee3ef8 Fix DO_CALL block comment
6e6c2d01ebb1ef839675c7151d2a114f53663386 Remove DOARGS/UNDOARGS macros
ca3cfa40c16ef34c74951a07a57cfcbcd58898b1 Tidy syscall error check
af4e8ef9443e258ebeb0ddf3c5c9579f24dfacd5 Tabify sysdep-cancel.h
a8b4f04ad7dff4f39797a7ab7f8babda54266026 Share code in sysdep-cancel.h
645d44abe3ca6253a9d4762f092e4a1b9d294b11 Pass regno parameter to SINGLE_THREAD_P
b5be4597716eff94149f5529c8eb2cd3b4296188 Improve syscall-cancel stack frame
74f31c18593111725478a991b395ae45661985a3 Fix error return from __ioctl
f0712b543eaddeca8fc6d7a8eb6b5b8d24105ce2 Remove PSEUDO_RET
And a not-yet-committed cleanup to clone.S.
---
ports/sysdeps/unix/sysv/linux/aarch64/clone.S | 51 +++---
ports/sysdeps/unix/sysv/linux/aarch64/ioctl.S | 13 +-
.../unix/sysv/linux/aarch64/nptl/localplt.data | 1 -
.../unix/sysv/linux/aarch64/nptl/sysdep-cancel.h | 189 +++++++--------------
ports/sysdeps/unix/sysv/linux/aarch64/syscall.S | 4 +-
ports/sysdeps/unix/sysv/linux/aarch64/sysdep.h | 84 ++-------
ports/sysdeps/unix/sysv/linux/aarch64/vfork.S | 4 +-
7 files changed, 108 insertions(+), 238 deletions(-)
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/clone.S glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/clone.S
index 8be1464..d5c31f3 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/clone.S
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/clone.S
@@ -39,46 +39,43 @@
*/
.text
ENTRY(__clone)
+ /* Save args for the child. */
+ mov x10, x0
+ mov x11, x2
+ mov x12, x3
+
/* Sanity check args. */
- cbz x0, 1f
- cbz x1, 1f
- /* Insert the args onto the new stack. */
- stp x0, x3, [x1, #-16]! /* Fn, arg. */
+ mov x0, #-EINVAL
+ cbz x10, .Lsyscall_error
+ cbz x1, .Lsyscall_error
/* Do the system call. */
+ /* X0:flags, x1:newsp, x2:parenttidptr, x3:newtls, x4:childtid. */
mov x0, x2 /* flags */
-
/* New sp is already in x1. */
mov x2, x4 /* ptid */
mov x3, x5 /* tls */
mov x4, x6 /* ctid */
-#ifdef RESET_PID
- /* We rely on the kernel preserving the argument regsiters across a
- each system call so that we can inspect the flags against after
- the clone call. */
- mov x5, x0
-#endif
-
mov x8, #SYS_ify(clone)
- /* X0:flags, x1:newsp, x2:parenttidptr, x3:newtls, x4:childtid. */
svc 0x0
- cfi_endproc
cmp x0, #0
- beq 2f
- blt C_SYMBOL_NAME(__syscall_error)
+ beq thread_start
+ blt .Lsyscall_error
RET
-1: mov x0, #-EINVAL
- b syscall_error
+PSEUDO_END (__clone)
-2:
+ .align 4
+ .type thread_start, %function
+thread_start:
cfi_startproc
cfi_undefined (x30)
mov x29, 0
+
#ifdef RESET_PID
- tbnz x5, #CLONE_THREAD_BIT, 3f
+ tbnz x11, #CLONE_THREAD_BIT, 3f
mov x0, #-1
- tbnz x5, #CLONE_VM_BIT, 2f
+ tbnz x11, #CLONE_VM_BIT, 2f
mov x8, #SYS_ify(getpid)
svc 0x0
2:
@@ -86,18 +83,16 @@ ENTRY(__clone)
sub x1, x1, #PTHREAD_SIZEOF
str w0, [x1, #PTHREAD_PID_OFFSET]
str w0, [x1, #PTHREAD_TID_OFFSET]
-
3:
#endif
- /* Pick the function arg and call address from the stack and
- execute. */
- ldp x1, x0, [sp], #16
- blr x1
+
+ /* Pick the function arg execute. */
+ mov x0, x12
+ blr x10
/* We are done, pass the return value through x0. */
b HIDDEN_JUMPTARGET(_exit)
cfi_endproc
- cfi_startproc
-PSEUDO_END (__clone)
+ .size thread_start, .-thread_start
weak_alias (__clone, clone)
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/ioctl.S glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/ioctl.S
index f01fb84..be6c026 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/ioctl.S
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/ioctl.S
@@ -20,13 +20,12 @@
.text
ENTRY(__ioctl)
- movz x8, #__NR_ioctl
- sxtw x0, w0
- svc #0x0
- cmn x0, #0x1, lsl #12
- b.hi C_SYMBOL_NAME(__syscall_error)
+ mov x8, #__NR_ioctl
+ sxtw x0, w0
+ svc #0x0
+ cmn x0, #4095
+ b.cs .Lsyscall_error
ret
-
- PSEUDO_END (__ioctl)
+PSEUDO_END (__ioctl)
weak_alias (__ioctl, ioctl)
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/localplt.data glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/localplt.data
index 84af95d..dfca9a7 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/localplt.data
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/localplt.data
@@ -12,4 +12,3 @@ libm.so: matherr
libm.so: __signbit
libm.so: __signbitf
libm.so: __signbitl
-libpthread.so: __errno_location
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h
index e0e5cc0..a3b9284 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h
@@ -26,119 +26,60 @@
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
- .section ".text"; \
- .type __##syscall_name##_nocancel,%function; \
- .globl __##syscall_name##_nocancel; \
- __##syscall_name##_nocancel: \
- cfi_startproc; \
- DO_CALL (syscall_name, args); \
- PSEUDO_RET; \
- cfi_endproc; \
- .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
- ENTRY (name); \
- SINGLE_THREAD_P; \
- DOARGS_##args; \
- bne .Lpseudo_cancel; \
- DO_CALL (syscall_name, 0); \
- UNDOARGS_##args; \
- cmn x0, 4095; \
- PSEUDO_RET; \
- .Lpseudo_cancel: \
- DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \
- CENABLE; \
- mov x16, x0; /* put mask in safe place. */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
- mov x8, SYS_ify (syscall_name); /* do the call. */ \
- svc 0; \
- str x0, [sp, -16]!; /* save syscall return value. */ \
- cfi_adjust_cfa_offset (16); \
- mov x0, x16; /* get mask back. */ \
- CDISABLE; \
- ldr x0, [sp], 16; \
- cfi_adjust_cfa_offset (-16); \
- ldr x30, [sp], 16; \
- cfi_adjust_cfa_offset (-16); \
- cfi_restore (x30); \
- UNDOARGS_##args; \
- cmn x0, 4095;
-
-# define DOCARGS_0 \
- str x30, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x30, 0)
+ .section ".text"; \
+ENTRY (__##syscall_name##_nocancel); \
+.Lpseudo_nocancel: \
+ DO_CALL (syscall_name, args); \
+.Lpseudo_finish: \
+ cmn x0, 4095; \
+ b.cs .Lsyscall_error; \
+ .subsection 2; \
+ .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
+ENTRY (name); \
+ SINGLE_THREAD_P(16); \
+ cbz w16, .Lpseudo_nocancel; \
+ /* Setup common stack frame no matter the number of args. \
+ Also save the first arg, since it's basically free. */ \
+ stp x30, x0, [sp, -64]!; \
+ cfi_adjust_cfa_offset (64); \
+ cfi_rel_offset (x30, 0); \
+ DOCARGS_##args; /* save syscall args around CENABLE. */ \
+ CENABLE; \
+ mov x16, x0; /* save mask around syscall. */ \
+ UNDOCARGS_##args; /* restore syscall args. */ \
+ DO_CALL (syscall_name, args); \
+ str x0, [sp, 8]; /* save result around CDISABLE. */ \
+ mov x0, x16; /* restore mask for CDISABLE. */ \
+ CDISABLE; \
+ /* Break down the stack frame, restoring result at once. */ \
+ ldp x30, x0, [sp], 64; \
+ cfi_adjust_cfa_offset (-64); \
+ cfi_restore (x30); \
+ b .Lpseudo_finish; \
+ cfi_endproc; \
+ .size name, .-name; \
+ .previous
+
+# undef PSEUDO_END
+# define PSEUDO_END(name) \
+ SYSCALL_ERROR_HANDLER; \
+ cfi_endproc
+
+# define DOCARGS_0
+# define DOCARGS_1
+# define DOCARGS_2 str x1, [sp, 16]
+# define DOCARGS_3 stp x1, x2, [sp, 16]
+# define DOCARGS_4 DOCARGS_3; str x3, [sp, 32]
+# define DOCARGS_5 DOCARGS_3; stp x3, x4, [sp, 32]
+# define DOCARGS_6 DOCARGS_5; str x5, [sp, 48]
# define UNDOCARGS_0
-
-# define DOCARGS_1 \
- DOCARGS_0; \
- str x0, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x0, 0)
-
-# define UNDOCARGS_1 \
- ldr x0, [sp], 16; \
- cfi_restore (x0); \
- cfi_adjust_cfa_offset (-16); \
-
-# define DOCARGS_2 \
- DOCARGS_1; \
- str x1, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x1, 0)
-
-# define UNDOCARGS_2 \
- ldr x1, [sp], 16; \
- cfi_restore (x1); \
- cfi_adjust_cfa_offset (-16); \
- UNDOCARGS_1
-
-# define DOCARGS_3 \
- DOCARGS_2; \
- str x2, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x2, 0)
-
-# define UNDOCARGS_3 \
- ldr x2, [sp], 16; \
- cfi_restore (x2); \
- cfi_adjust_cfa_offset (-16); \
- UNDOCARGS_2
-
-# define DOCARGS_4 \
- DOCARGS_3; \
- str x3, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x3, 0)
-
-# define UNDOCARGS_4 \
- ldr x3, [sp], 16; \
- cfi_restore (x3); \
- cfi_adjust_cfa_offset (-16); \
- UNDOCARGS_3
-
-# define DOCARGS_5 \
- DOCARGS_4; \
- str x4, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x4, 0)
-
-# define UNDOCARGS_5 \
- ldr x4, [sp], 16; \
- cfi_restore (x4); \
- cfi_adjust_cfa_offset (-16); \
- UNDOCARGS_4
-
-# define DOCARGS_6 \
- DOCARGS_5; \
- str x5, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x5, 0)
-
-# define UNDOCARGS_6 \
- ldr x5, [sp], 16; \
- cfi_restore (x5); \
- cfi_adjust_cfa_offset (-16); \
- UNDOCARGS_5
+# define UNDOCARGS_1 ldr x0, [sp, 8]
+# define UNDOCARGS_2 ldp x0, x1, [sp, 8]
+# define UNDOCARGS_3 UNDOCARGS_1; ldp x1, x2, [sp, 16]
+# define UNDOCARGS_4 UNDOCARGS_2; ldp x2, x3, [sp, 24]
+# define UNDOCARGS_5 UNDOCARGS_3; ldp x3, x4, [sp, 32]
+# define UNDOCARGS_6 UNDOCARGS_4; ldp x4, x5, [sp, 40]
# ifdef IS_IN_libpthread
# define CENABLE bl __pthread_enable_asynccancel
@@ -160,11 +101,9 @@
extern int __local_multiple_threads attribute_hidden;
# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
# else
-# define SINGLE_THREAD_P \
- adrp x16, __local_multiple_threads; \
- add x16, x16, #:lo12:__local_multiple_threads; \
- ldr x16, [x16]; \
- cmp x16, 0;
+# define SINGLE_THREAD_P(R) \
+ adrp x##R, __local_multiple_threads; \
+ ldr w##R, [x##R, :lo12:__local_multiple_threads]
# endif
# else
/* There is no __local_multiple_threads for librt, so use the TCB. */
@@ -173,20 +112,10 @@ extern int __local_multiple_threads attribute_hidden;
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
# else
-# define SINGLE_THREAD_P \
- stp x0, x30, [sp, -16]!; \
- cfi_adjust_cfa_offset (16); \
- cfi_rel_offset (x0, 0); \
- cfi_rel_offset (x30, 8); \
- bl __read_tp; \
- sub x0, x0, PTHREAD_SIZEOF; \
- ldr x16, [x0, PTHREAD_MULTIPLE_THREADS_OFFSET]; \
- ldp x0, x30, [sp], 16; \
- cfi_restore (x0); \
- cfi_restore (x30); \
- cfi_adjust_cfa_offset (-16); \
- cmp x16, 0
-# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
+# define SINGLE_THREAD_P(R) \
+ mrs x##R, tpidr_el0; \
+ sub x##R, x##R, PTHREAD_SIZEOF; \
+ ldr w##R, [x##R, PTHREAD_MULTIPLE_THREADS_OFFSET]
# endif
# endif
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/syscall.S glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/syscall.S
index 574fdf1..fac6416 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/syscall.S
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/syscall.S
@@ -37,8 +37,6 @@ ENTRY (syscall)
mov x6, x7
svc 0x0
cmn x0, #4095
- b.cs 1f
+ b.cs .Lsyscall_error
RET
-1:
- b SYSCALL_ERROR
PSEUDO_END (syscall)
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/sysdep.h glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/sysdep.h
index 713bf7d..9961c03 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/sysdep.h
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/sysdep.h
@@ -58,19 +58,8 @@
.text; \
ENTRY (name); \
DO_CALL (syscall_name, args); \
- cmn x0, #4095;
-
-/* Notice the use of 'RET' instead of 'ret' the assembler is case
- insensitive and eglibc already uses the preprocessor symbol 'ret'
- so we use the upper case 'RET' to force through a ret instruction
- to the assembler */
-# define PSEUDO_RET \
- b.cs 1f; \
- RET; \
- 1: \
- b SYSCALL_ERROR
-# undef ret
-# define ret PSEUDO_RET
+ cmn x0, #4095; \
+ b.cs .Lsyscall_error
# undef PSEUDO_END
# define PSEUDO_END(name) \
@@ -83,15 +72,7 @@
ENTRY (name); \
DO_CALL (syscall_name, args);
-/* Notice the use of 'RET' instead of 'ret' the assembler is case
- insensitive and eglibc already uses the preprocessor symbol 'ret'
- so we use the upper case 'RET' to force through a ret instruction
- to the assembler */
-# define PSEUDO_RET_NOERRNO \
- RET;
-
-# undef ret_NOERRNO
-# define ret_NOERRNO PSEUDO_RET_NOERRNO
+# define ret_NOERRNO ret
# undef PSEUDO_END_NOERRNO
# define PSEUDO_END_NOERRNO(name) \
@@ -109,47 +90,38 @@
# define PSEUDO_END_ERRVAL(name) \
END (name)
-# define ret_ERRVAL PSEUDO_RET_NOERRNO
+# define ret_ERRVAL ret
+# define SYSCALL_ERROR .Lsyscall_error
# if NOT_IN_libc
-# define SYSCALL_ERROR __local_syscall_error
# if RTLD_PRIVATE_ERRNO
# define SYSCALL_ERROR_HANDLER \
-__local_syscall_error: \
+.Lsyscall_error: \
adrp x1, C_SYMBOL_NAME(rtld_errno); \
- add x1, x1, #:lo12:C_SYMBOL_NAME(rtld_errno); \
neg w0, w0; \
- str w0, [x1]; \
+ str w0, [x1, :lo12:C_SYMBOL_NAME(rtld_errno)]; \
mov x0, -1; \
RET;
# else
# define SYSCALL_ERROR_HANDLER \
-__local_syscall_error: \
- stp x29, x30, [sp, -32]!; \
- cfi_adjust_cfa_offset (32); \
- cfi_rel_offset (x29, 0); \
- cfi_rel_offset (x30, 8); \
- add x29, sp, 0; \
- str x19, [sp,16]; \
- neg x19, x0; \
- bl C_SYMBOL_NAME(__errno_location); \
- str x19, [x0]; \
+.Lsyscall_error: \
+ adrp x1, :gottprel:errno; \
+ neg w2, w0; \
+ ldr x1, [x1, :gottprel_lo12:errno]; \
+ mrs x3, tpidr_el0; \
mov x0, -1; \
- ldr x19, [sp,16]; \
- ldp x29, x30, [sp], 32; \
- cfi_adjust_cfa_offset (-32); \
- cfi_restore (x29); \
- cfi_restore (x30); \
+ str w2, [x1, x3]; \
RET;
# endif
# else
-# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
-# define SYSCALL_ERROR __syscall_error
+# define SYSCALL_ERROR_HANDLER \
+.Lsyscall_error: \
+ b __syscall_error;
# endif
/* Linux takes system call args in registers:
- syscall number in the SVC instruction
+ syscall number x8
arg 1 x0
arg 2 x1
arg 3 x2
@@ -177,28 +149,8 @@ __local_syscall_error: \
# undef DO_CALL
# define DO_CALL(syscall_name, args) \
- DOARGS_##args \
mov x8, SYS_ify (syscall_name); \
- svc 0; \
- UNDOARGS_##args
-
-# define DOARGS_0 /* nothing */
-# define DOARGS_1 /* nothing */
-# define DOARGS_2 /* nothing */
-# define DOARGS_3 /* nothing */
-# define DOARGS_4 /* nothing */
-# define DOARGS_5 /* nothing */
-# define DOARGS_6 /* nothing */
-# define DOARGS_7 /* nothing */
-
-# define UNDOARGS_0 /* nothing */
-# define UNDOARGS_1 /* nothing */
-# define UNDOARGS_2 /* nothing */
-# define UNDOARGS_3 /* nothing */
-# define UNDOARGS_4 /* nothing */
-# define UNDOARGS_5 /* nothing */
-# define UNDOARGS_6 /* nothing */
-# define UNDOARGS_7 /* nothing */
+ svc 0
#else /* not __ASSEMBLER__ */
diff --git glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/vfork.S glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/vfork.S
index f2dc49b..3fb68b9 100644
--- glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/vfork.S
+++ glibc-2.17-c758a686/ports/sysdeps/unix/sysv/linux/aarch64/vfork.S
@@ -38,10 +38,8 @@ ENTRY (__vfork)
RESTORE_PID
#endif
cmn x0, #4095
- b.cs 1f
+ b.cs .Lsyscall_error
RET
-1:
- b SYSCALL_ERROR
PSEUDO_END (__vfork)
libc_hidden_def (__vfork)
--
1.8.3.1