-/* Copyright (C) 2001,02,03 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
#ifndef _LINUX_X86_64_SYSDEP_H
#define _LINUX_X86_64_SYSDEP_H 1
/* There is some commonality. */
+#include <sysdeps/unix/sysv/linux/sysdep.h>
#include <sysdeps/unix/x86_64/sysdep.h>
-#include <bp-sym.h>
-#include <bp-asm.h>
#include <tls.h>
-#ifdef IS_IN_rtld
-# include <dl-sysdep.h> /* Defines RTLD_PRIVATE_ERRNO. */
-#endif
+/* Defines RTLD_PRIVATE_ERRNO. */
+#include <dl-sysdep.h>
/* For Linux we can use the system call table in the header file
/usr/include/asm/unistd.h
/* 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
+# ifdef PIC
+# define SYSCALL_ERROR_LABEL 0f
+# else
+# define SYSCALL_ERROR_LABEL syscall_error
+# endif
-#undef PSEUDO
-#define PSEUDO(name, syscall_name, args) \
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name) \
DO_CALL (syscall_name, args); \
cmpq $-4095, %rax; \
- jae SYSCALL_ERROR_LABEL; \
- L(pseudo_end):
+ jae SYSCALL_ERROR_LABEL
-#undef PSEUDO_END
-#define PSEUDO_END(name) \
+# undef PSEUDO_END
+# define PSEUDO_END(name) \
SYSCALL_ERROR_HANDLER \
END (name)
-#undef PSEUDO_NOERRNO
-#define PSEUDO_NOERRNO(name, syscall_name, args) \
+# undef PSEUDO_NOERRNO
+# define PSEUDO_NOERRNO(name, syscall_name, args) \
.text; \
ENTRY (name) \
DO_CALL (syscall_name, args)
-#undef PSEUDO_END_NOERRNO
-#define PSEUDO_END_NOERRNO(name) \
+# undef PSEUDO_END_NOERRNO
+# define PSEUDO_END_NOERRNO(name) \
END (name)
-#define ret_NOERRNO ret
+# define ret_NOERRNO ret
-#undef PSEUDO_ERRVAL
-#define PSEUDO_ERRVAL(name, syscall_name, args) \
+# undef PSEUDO_ERRVAL
+# define PSEUDO_ERRVAL(name, syscall_name, args) \
.text; \
ENTRY (name) \
DO_CALL (syscall_name, args); \
negq %rax
-#undef PSEUDO_END_ERRVAL
-#define PSEUDO_END_ERRVAL(name) \
+# undef PSEUDO_END_ERRVAL
+# define PSEUDO_END_ERRVAL(name) \
END (name)
-#define ret_ERRVAL ret
+# define ret_ERRVAL ret
-#ifndef PIC
-#define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
-#elif RTLD_PRIVATE_ERRNO
-# define SYSCALL_ERROR_HANDLER \
-0: \
- leaq errno(%rip), %rcx; \
- xorq %rdx, %rdx; \
- subq %rax, %rdx; \
- movl %edx, (%rcx); \
- orq $-1, %rax; \
- jmp L(pseudo_end);
-#elif USE___THREAD
-# ifndef NOT_IN_libc
-# define SYSCALL_ERROR_ERRNO __libc_errno
+# if defined PIC && RTLD_PRIVATE_ERRNO
+# define SYSCALL_SET_ERRNO \
+ lea rtld_errno(%rip), %RCX_LP; \
+ neg %eax; \
+ movl %eax, (%rcx)
# else
-# define SYSCALL_ERROR_ERRNO errno
-# endif
-# define SYSCALL_ERROR_HANDLER \
-0: \
+# if IS_IN (libc)
+# define SYSCALL_ERROR_ERRNO __libc_errno
+# else
+# define SYSCALL_ERROR_ERRNO errno
+# endif
+# define SYSCALL_SET_ERRNO \
movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\
- xorq %rdx, %rdx; \
- subq %rax, %rdx; \
- movl %edx, %fs:(%rcx); \
- orq $-1, %rax; \
- jmp L(pseudo_end);
-#elif defined _LIBC_REENTRANT
-/* Store (- %rax) into errno through the GOT.
- Note that errno occupies only 4 bytes. */
-# define SYSCALL_ERROR_HANDLER \
+ neg %eax; \
+ movl %eax, %fs:(%rcx);
+# endif
+
+# ifndef PIC
+# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
+# else
+# define SYSCALL_ERROR_HANDLER \
0: \
- xorq %rdx, %rdx; \
- subq %rax, %rdx; \
- pushq %rdx; \
- cfi_adjust_cfa_offset(8); \
- PUSH_ERRNO_LOCATION_RETURN; \
- call BP_SYM (__errno_location)@PLT; \
- POP_ERRNO_LOCATION_RETURN; \
- popq %rdx; \
- cfi_adjust_cfa_offset(-8); \
- movl %edx, (%rax); \
- orq $-1, %rax; \
- jmp L(pseudo_end);
-
-/* A quick note: it is assumed that the call to `__errno_location' does
- not modify the stack! */
-#else /* Not _LIBC_REENTRANT. */
-# define SYSCALL_ERROR_HANDLER \
-0:movq errno@GOTPCREL(%RIP), %rcx; \
- xorq %rdx, %rdx; \
- subq %rax, %rdx; \
- movl %edx, (%rcx); \
- orq $-1, %rax; \
- jmp L(pseudo_end);
-#endif /* PIC */
+ SYSCALL_SET_ERRNO; \
+ or $-1, %RAX_LP; \
+ ret;
+# endif /* PIC */
/* The Linux/x86-64 kernel expects the system call parameters in
registers according to the following table:
The Linux kernel uses and destroys internally these registers:
return address from
syscall rcx
- additionally clobered: r12-r15,rbx,rbp
eflags from syscall r11
Normal function call, including calls to the system call stub
Syscalls of more than 6 arguments are not supported. */
-#undef DO_CALL
-#define DO_CALL(syscall_name, args) \
+# undef DO_CALL
+# define DO_CALL(syscall_name, args) \
DOARGS_##args \
- movq $SYS_ify (syscall_name), %rax; \
+ movl $SYS_ify (syscall_name), %eax; \
syscall;
-#define DOARGS_0 /* nothing */
-#define DOARGS_1 /* nothing */
-#define DOARGS_2 /* nothing */
-#define DOARGS_3 /* nothing */
-#define DOARGS_4 movq %rcx, %r10;
-#define DOARGS_5 DOARGS_4
-#define DOARGS_6 DOARGS_5
+# define DOARGS_0 /* nothing */
+# define DOARGS_1 /* nothing */
+# define DOARGS_2 /* nothing */
+# define DOARGS_3 /* nothing */
+# define DOARGS_4 movq %rcx, %r10;
+# define DOARGS_5 DOARGS_4
+# define DOARGS_6 DOARGS_5
#else /* !__ASSEMBLER__ */
/* Define a macro which expands inline into the wrapper code for a system
call. */
-#undef INLINE_SYSCALL
-#define INLINE_SYSCALL(name, nr, args...) \
+# undef INLINE_SYSCALL
+# define INLINE_SYSCALL(name, nr, args...) \
({ \
- unsigned long resultvar = INTERNAL_SYSCALL (name, , nr, args); \
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0)) \
+ unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args); \
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \
- resultvar = (unsigned long) -1; \
+ resultvar = (unsigned long int) -1; \
} \
- (long) resultvar; })
+ (long int) resultvar; })
-#undef INTERNAL_SYSCALL_DECL
-#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+/* Define a macro with explicit types for arguments, which expands inline
+ into the wrapper code for a system call. It should be used when size
+ of any argument > size of long int. */
+# undef INLINE_SYSCALL_TYPES
+# define INLINE_SYSCALL_TYPES(name, nr, args...) \
+ ({ \
+ unsigned long int resultvar = INTERNAL_SYSCALL_TYPES (name, , nr, args); \
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \
+ { \
+ __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \
+ resultvar = (unsigned long int) -1; \
+ } \
+ (long int) resultvar; })
+
+# undef INTERNAL_SYSCALL_DECL
+# define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+
+/* Registers clobbered by syscall. */
+# define REGISTERS_CLOBBERED_BY_SYSCALL "cc", "r11", "cx"
+
+/* Create a variable 'name' based on type 'X' to avoid explicit types.
+ This is mainly used set use 64-bits arguments in x32. */
+#define TYPEFY(X, name) __typeof__ ((X) - (X)) name
+/* Explicit cast the argument to avoid integer from pointer warning on
+ x32. */
+#define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
#undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...) \
- ({ \
- unsigned long resultvar; \
- LOAD_ARGS_##nr (args) \
- asm volatile ( \
- "movq %1, %%rax\n\t" \
- "syscall\n\t" \
- : "=a" (resultvar) \
- : "i" (__NR_##name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx"); \
- (long) resultvar; })
-
-#undef INTERNAL_SYSCALL_ERROR_P
-#define INTERNAL_SYSCALL_ERROR_P(val, err) \
- ((unsigned long) (val) >= -4095L)
-
-#undef INTERNAL_SYSCALL_ERRNO
-#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
-
-#define LOAD_ARGS_0()
-#define ASM_ARGS_0
-
-#define LOAD_ARGS_1(a1) \
- register long int _a1 asm ("rdi") = (long) (a1); \
- LOAD_ARGS_0 ()
-#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1)
-
-#define LOAD_ARGS_2(a1, a2) \
- register long int _a2 asm ("rsi") = (long) (a2); \
- LOAD_ARGS_1 (a1)
-#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2)
-
-#define LOAD_ARGS_3(a1, a2, a3) \
- register long int _a3 asm ("rdx") = (long) (a3); \
- LOAD_ARGS_2 (a1, a2)
-#define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3)
-
-#define LOAD_ARGS_4(a1, a2, a3, a4) \
- register long int _a4 asm ("r10") = (long) (a4); \
- LOAD_ARGS_3 (a1, a2, a3)
-#define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4)
-
-#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
- register long int _a5 asm ("r8") = (long) (a5); \
- LOAD_ARGS_4 (a1, a2, a3, a4)
-#define ASM_ARGS_5 ASM_ARGS_4, "r" (_a5)
-
-#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \
- register long int _a6 asm ("r9") = (long) (a6); \
- LOAD_ARGS_5 (a1, a2, a3, a4, a5)
-#define ASM_ARGS_6 ASM_ARGS_5, "r" (_a6)
+#define INTERNAL_SYSCALL(name, err, nr, args...) \
+ internal_syscall##nr (SYS_ify (name), err, args)
+
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
+ internal_syscall##nr (number, err, args)
+
+#undef internal_syscall0
+#define internal_syscall0(number, err, dummy...) \
+({ \
+ unsigned long int resultvar; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+#undef internal_syscall1
+#define internal_syscall1(number, err, arg1) \
+({ \
+ unsigned long int resultvar; \
+ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
+ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number), "r" (_a1) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+#undef internal_syscall2
+#define internal_syscall2(number, err, arg1, arg2) \
+({ \
+ unsigned long int resultvar; \
+ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \
+ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
+ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \
+ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number), "r" (_a1), "r" (_a2) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+#undef internal_syscall3
+#define internal_syscall3(number, err, arg1, arg2, arg3) \
+({ \
+ unsigned long int resultvar; \
+ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \
+ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \
+ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
+ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \
+ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \
+ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+#undef internal_syscall4
+#define internal_syscall4(number, err, arg1, arg2, arg3, arg4) \
+({ \
+ unsigned long int resultvar; \
+ TYPEFY (arg4, __arg4) = ARGIFY (arg4); \
+ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \
+ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \
+ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
+ register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \
+ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \
+ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \
+ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+#undef internal_syscall5
+#define internal_syscall5(number, err, arg1, arg2, arg3, arg4, arg5) \
+({ \
+ unsigned long int resultvar; \
+ TYPEFY (arg5, __arg5) = ARGIFY (arg5); \
+ TYPEFY (arg4, __arg4) = ARGIFY (arg4); \
+ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \
+ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \
+ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
+ register TYPEFY (arg5, _a5) asm ("r8") = __arg5; \
+ register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \
+ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \
+ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \
+ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4), \
+ "r" (_a5) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+#undef internal_syscall6
+#define internal_syscall6(number, err, arg1, arg2, arg3, arg4, arg5, arg6) \
+({ \
+ unsigned long int resultvar; \
+ TYPEFY (arg6, __arg6) = ARGIFY (arg6); \
+ TYPEFY (arg5, __arg5) = ARGIFY (arg5); \
+ TYPEFY (arg4, __arg4) = ARGIFY (arg4); \
+ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \
+ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \
+ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \
+ register TYPEFY (arg6, _a6) asm ("r9") = __arg6; \
+ register TYPEFY (arg5, _a5) asm ("r8") = __arg5; \
+ register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \
+ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \
+ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \
+ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \
+ asm volatile ( \
+ "syscall\n\t" \
+ : "=a" (resultvar) \
+ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4), \
+ "r" (_a5), "r" (_a6) \
+ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \
+ (long int) resultvar; \
+})
+
+# undef INTERNAL_SYSCALL_ERROR_P
+# define INTERNAL_SYSCALL_ERROR_P(val, err) \
+ ((unsigned long int) (long int) (val) >= -4095L)
+
+# undef INTERNAL_SYSCALL_ERRNO
+# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+
+# define VDSO_NAME "LINUX_2.6"
+# define VDSO_HASH 61765110
+
+/* List of system calls which are supported as vsyscalls. */
+# define HAVE_CLOCK_GETTIME_VSYSCALL 1
+# define HAVE_GETTIMEOFDAY_VSYSCALL 1
+# define HAVE_GETCPU_VSYSCALL 1
+
+# define SINGLE_THREAD_BY_GLOBAL 1
#endif /* __ASSEMBLER__ */
+
+/* Pointer mangling support. */
+#if IS_IN (rtld)
+/* We cannot use the thread descriptor because in ld.so we use setjmp
+ earlier than the descriptor is initialized. */
+# ifdef __ASSEMBLER__
+# define PTR_MANGLE(reg) xor __pointer_chk_guard_local(%rip), reg; \
+ rol $2*LP_SIZE+1, reg
+# define PTR_DEMANGLE(reg) ror $2*LP_SIZE+1, reg; \
+ xor __pointer_chk_guard_local(%rip), reg
+# else
+# define PTR_MANGLE(reg) asm ("xor __pointer_chk_guard_local(%%rip), %0\n" \
+ "rol $2*" LP_SIZE "+1, %0" \
+ : "=r" (reg) : "0" (reg))
+# define PTR_DEMANGLE(reg) asm ("ror $2*" LP_SIZE "+1, %0\n" \
+ "xor __pointer_chk_guard_local(%%rip), %0" \
+ : "=r" (reg) : "0" (reg))
+# endif
+#else
+# ifdef __ASSEMBLER__
+# define PTR_MANGLE(reg) xor %fs:POINTER_GUARD, reg; \
+ rol $2*LP_SIZE+1, reg
+# define PTR_DEMANGLE(reg) ror $2*LP_SIZE+1, reg; \
+ xor %fs:POINTER_GUARD, reg
+# else
+# define PTR_MANGLE(var) asm ("xor %%fs:%c2, %0\n" \
+ "rol $2*" LP_SIZE "+1, %0" \
+ : "=r" (var) \
+ : "0" (var), \
+ "i" (offsetof (tcbhead_t, \
+ pointer_guard)))
+# define PTR_DEMANGLE(var) asm ("ror $2*" LP_SIZE "+1, %0\n" \
+ "xor %%fs:%c2, %0" \
+ : "=r" (var) \
+ : "0" (var), \
+ "i" (offsetof (tcbhead_t, \
+ pointer_guard)))
+# endif
+#endif
+
+/* How to pass the off{64}_t argument on p{readv,writev}{64}. */
+#undef LO_HI_LONG
+#define LO_HI_LONG(val) (val), 0
+
+/* Each shadow stack slot takes 8 bytes. Assuming that each stack
+ frame takes 256 bytes, this is used to compute shadow stack size
+ from stack size. */
+#define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5
+
#endif /* linux/x86_64/sysdep.h */