diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/i386/sysdep.h')
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/sysdep.h | 206 |
1 files changed, 138 insertions, 68 deletions
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h index d76aca50d6..5fcb175e18 100644 --- a/sysdeps/unix/sysv/linux/i386/sysdep.h +++ b/sysdeps/unix/sysv/linux/i386/sysdep.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1992-2015 Free Software Foundation, Inc. +/* Copyright (C) 1992-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995. @@ -20,6 +20,7 @@ #define _LINUX_I386_SYSDEP_H 1 /* There is some commonality. */ +#include <sysdeps/unix/sysv/linux/sysdep.h> #include <sysdeps/unix/i386/sysdep.h> /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */ #include <dl-sysdep.h> @@ -40,6 +41,15 @@ # undef I386_USE_SYSENTER #endif +/* Since GCC 5 and above can properly spill %ebx with PIC when needed, + we can inline syscalls with 6 arguments if GCC 5 or above is used + to compile glibc. Disable GCC 5 optimization when compiling for + profiling since asm ("ebp") can't be used to put the 6th argument + in %ebp for syscall. */ +#if __GNUC_PREREQ (5,0) && !defined PROF +# define OPTIMIZE_FOR_GCC_5 +#endif + #ifdef __ASSEMBLER__ /* Linux uses a negative return value to indicate syscall errors, @@ -55,11 +65,7 @@ /* We don't want the label for the error handle to be global when we define it here. */ -#ifdef PIC -# define SYSCALL_ERROR_LABEL 0f -#else -# define SYSCALL_ERROR_LABEL syscall_error -#endif +#define SYSCALL_ERROR_LABEL __syscall_error #undef PSEUDO #define PSEUDO(name, syscall_name, args) \ @@ -100,55 +106,7 @@ #define ret_ERRVAL ret -#ifndef PIC -# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ -#else - -# if RTLD_PRIVATE_ERRNO -# define SYSCALL_ERROR_HANDLER \ -0:SETUP_PIC_REG(cx); \ - addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ - negl %eax; \ - movl %eax, rtld_errno@GOTOFF(%ecx); \ - orl $-1, %eax; \ - ret; - -# elif defined _LIBC_REENTRANT - -# if IS_IN (libc) -# define SYSCALL_ERROR_ERRNO __libc_errno -# else -# define SYSCALL_ERROR_ERRNO errno -# endif -# define SYSCALL_ERROR_HANDLER \ -0:SETUP_PIC_REG (cx); \ - addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ - movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx; \ - negl %eax; \ - SYSCALL_ERROR_HANDLER_TLS_STORE (%eax, %ecx); \ - orl $-1, %eax; \ - ret; -# ifndef NO_TLS_DIRECT_SEG_REFS -# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \ - movl src, %gs:(destoff) -# else -# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \ - addl %gs:0, destoff; \ - movl src, (destoff) -# endif -# else -/* Store (- %eax) into errno through the GOT. */ -# define SYSCALL_ERROR_HANDLER \ -0:SETUP_PIC_REG(cx); \ - addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ - negl %eax; \ - movl errno@GOT(%ecx), %ecx; \ - movl %eax, (%ecx); \ - orl $-1, %eax; \ - ret; -# endif /* _LIBC_REENTRANT */ -#endif /* PIC */ - +#define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.c is used. */ /* The original calling convention for system calls on Linux/i386 is to use int $0x80. */ @@ -275,6 +233,10 @@ #else /* !__ASSEMBLER__ */ +extern int __syscall_error (int) + attribute_hidden __attribute__ ((__regparm__ (1))); + +#ifndef OPTIMIZE_FOR_GCC_5 /* We need some help from the assembler to generate optimal code. We define some macros here which later will be used. */ asm (".L__X'%ebx = 1\n\t" @@ -314,11 +276,20 @@ struct libc_do_syscall_args { int ebx, edi, ebp; }; +#endif /* Define a macro which expands inline into the wrapper code for a system call. */ #undef INLINE_SYSCALL -#define INLINE_SYSCALL(name, nr, args...) \ +#if IS_IN (libc) +# define INLINE_SYSCALL(name, nr, args...) \ + ({ \ + unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ + __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, )) \ + ? __syscall_error (-INTERNAL_SYSCALL_ERRNO (resultvar, )) \ + : (int) resultvar; }) +#else +# define INLINE_SYSCALL(name, nr, args...) \ ({ \ unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \ @@ -327,6 +298,14 @@ struct libc_do_syscall_args resultvar = 0xffffffff; \ } \ (int) resultvar; }) +#endif + +/* Set error number and return -1. Return the internal function, + __syscall_error, which sets errno from the negative error number + and returns -1, to avoid PIC. */ +#undef INLINE_SYSCALL_ERROR_RETURN_VALUE +#define INLINE_SYSCALL_ERROR_RETURN_VALUE(resultvar) \ + __syscall_error (-(resultvar)) /* List of system calls which are supported as vsyscalls. */ # define HAVE_CLOCK_GETTIME_VSYSCALL 1 @@ -354,8 +333,12 @@ struct libc_do_syscall_args INTERNAL_SYSCALL_MAIN_INLINE(name, err, 5, args) /* Each object using 6-argument inline syscalls must include a definition of __libc_do_syscall. */ -#define INTERNAL_SYSCALL_MAIN_6(name, err, arg1, arg2, arg3, \ - arg4, arg5, arg6) \ +#ifdef OPTIMIZE_FOR_GCC_5 +# define INTERNAL_SYSCALL_MAIN_6(name, err, args...) \ + INTERNAL_SYSCALL_MAIN_INLINE(name, err, 6, args) +#else /* GCC 5 */ +# define INTERNAL_SYSCALL_MAIN_6(name, err, arg1, arg2, arg3, \ + arg4, arg5, arg6) \ struct libc_do_syscall_args _xv = \ { \ (int) (arg1), \ @@ -368,14 +351,52 @@ struct libc_do_syscall_args : "=a" (resultvar) \ : "i" (__NR_##name), "c" (arg2), "d" (arg3), "S" (arg4), "D" (&_xv) \ : "memory", "cc") +#endif /* GCC 5 */ #define INTERNAL_SYSCALL(name, err, nr, args...) \ ({ \ register unsigned int resultvar; \ INTERNAL_SYSCALL_MAIN_##nr (name, err, args); \ (int) resultvar; }) #ifdef I386_USE_SYSENTER -# ifdef SHARED -# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ +# ifdef OPTIMIZE_FOR_GCC_5 +# ifdef SHARED +# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *%%gs:%P2" \ + : "=a" (resultvar) \ + : "a" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \ + ASMARGS_##nr(args) : "memory", "cc") +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ + ({ \ + register unsigned int resultvar; \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *%%gs:%P2" \ + : "=a" (resultvar) \ + : "a" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ + ASMARGS_##nr(args) : "memory", "cc"); \ + (int) resultvar; }) +# else +# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *_dl_sysinfo" \ + : "=a" (resultvar) \ + : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc") +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ + ({ \ + register unsigned int resultvar; \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *_dl_sysinfo" \ + : "=a" (resultvar) \ + : "a" (name) ASMARGS_##nr(args) : "memory", "cc"); \ + (int) resultvar; }) +# endif +# else /* GCC 5 */ +# ifdef SHARED +# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ EXTRAVAR_##nr \ asm volatile ( \ LOADARGS_##nr \ @@ -385,7 +406,7 @@ struct libc_do_syscall_args : "=a" (resultvar) \ : "i" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \ ASMFMT_##nr(args) : "memory", "cc") -# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ ({ \ register unsigned int resultvar; \ EXTRAVAR_##nr \ @@ -397,8 +418,8 @@ struct libc_do_syscall_args : "0" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ ASMFMT_##nr(args) : "memory", "cc"); \ (int) resultvar; }) -# else -# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ +# else +# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ EXTRAVAR_##nr \ asm volatile ( \ LOADARGS_##nr \ @@ -407,7 +428,7 @@ struct libc_do_syscall_args RESTOREARGS_##nr \ : "=a" (resultvar) \ : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc") -# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ ({ \ register unsigned int resultvar; \ EXTRAVAR_##nr \ @@ -418,9 +439,27 @@ struct libc_do_syscall_args : "=a" (resultvar) \ : "0" (name) ASMFMT_##nr(args) : "memory", "cc"); \ (int) resultvar; }) -# endif +# endif +# endif /* GCC 5 */ #else -# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ +# ifdef OPTIMIZE_FOR_GCC_5 +# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "int $0x80" \ + : "=a" (resultvar) \ + : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc") +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ + ({ \ + register unsigned int resultvar; \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "int $0x80" \ + : "=a" (resultvar) \ + : "a" (name) ASMARGS_##nr(args) : "memory", "cc"); \ + (int) resultvar; }) +# else /* GCC 5 */ +# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ EXTRAVAR_##nr \ asm volatile ( \ LOADARGS_##nr \ @@ -429,7 +468,7 @@ struct libc_do_syscall_args RESTOREARGS_##nr \ : "=a" (resultvar) \ : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc") -# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ ({ \ register unsigned int resultvar; \ EXTRAVAR_##nr \ @@ -440,6 +479,7 @@ struct libc_do_syscall_args : "=a" (resultvar) \ : "0" (name) ASMFMT_##nr(args) : "memory", "cc"); \ (int) resultvar; }) +# endif /* GCC 5 */ #endif #undef INTERNAL_SYSCALL_DECL @@ -504,6 +544,36 @@ struct libc_do_syscall_args # define RESTOREARGS_5 #endif +#ifdef OPTIMIZE_FOR_GCC_5 +# define LOADREGS_0() +# define ASMARGS_0() +# define LOADREGS_1(arg1) \ + LOADREGS_0 () +# define ASMARGS_1(arg1) \ + ASMARGS_0 (), "b" ((unsigned int) (arg1)) +# define LOADREGS_2(arg1, arg2) \ + LOADREGS_1 (arg1) +# define ASMARGS_2(arg1, arg2) \ + ASMARGS_1 (arg1), "c" ((unsigned int) (arg2)) +# define LOADREGS_3(arg1, arg2, arg3) \ + LOADREGS_2 (arg1, arg2) +# define ASMARGS_3(arg1, arg2, arg3) \ + ASMARGS_2 (arg1, arg2), "d" ((unsigned int) (arg3)) +# define LOADREGS_4(arg1, arg2, arg3, arg4) \ + LOADREGS_3 (arg1, arg2, arg3) +# define ASMARGS_4(arg1, arg2, arg3, arg4) \ + ASMARGS_3 (arg1, arg2, arg3), "S" ((unsigned int) (arg4)) +# define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \ + LOADREGS_4 (arg1, arg2, arg3, arg4) +# define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \ + ASMARGS_4 (arg1, arg2, arg3, arg4), "D" ((unsigned int) (arg5)) +# define LOADREGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ + register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \ + LOADREGS_5 (arg1, arg2, arg3, arg4, arg5) +# define ASMARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ + ASMARGS_5 (arg1, arg2, arg3, arg4, arg5), "r" (_a6) +#endif /* GCC 5 */ + #define ASMFMT_0() #ifdef __PIC__ # define ASMFMT_1(arg1) \ @@ -541,7 +611,7 @@ struct libc_do_syscall_args #endif /* Consistency check for position-independent code. */ -#if defined __PIC__ && !__GNUC_PREREQ (5,0) +#if defined __PIC__ && !defined OPTIMIZE_FOR_GCC_5 # define check_consistency() \ ({ int __res; \ __asm__ __volatile__ \ |