]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/x86_64/sysdep.h
2002-08-26 Roland McGrath <roland@redhat.com>
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / x86_64 / sysdep.h
CommitLineData
c9cf6dde
AJ
1/* Copyright (C) 2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
18
19#ifndef _LINUX_X86_64_SYSDEP_H
20#define _LINUX_X86_64_SYSDEP_H 1
21
22/* There is some commonality. */
23#include <sysdeps/unix/x86_64/sysdep.h>
24#include <bp-sym.h>
25#include <bp-asm.h>
26
27/* For Linux we can use the system call table in the header file
28 /usr/include/asm/unistd.h
29 of the kernel. But these symbols do not follow the SYS_* syntax
30 so we have to redefine the `SYS_ify' macro here. */
31#undef SYS_ify
32#define SYS_ify(syscall_name) __NR_##syscall_name
33
34/* ELF-like local names start with `.L'. */
35#undef L
36#define L(name) .L##name
37
38#ifdef __ASSEMBLER__
39
40/* Linux uses a negative return value to indicate syscall errors,
41 unlike most Unices, which use the condition codes' carry flag.
42
43 Since version 2.1 the return value of a system call might be
44 negative even if the call succeeded. E.g., the `lseek' system call
45 might return a large offset. Therefore we must not anymore test
46 for < 0, but test for a real error by making sure the value in %eax
47 is a real error number. Linus said he will make sure the no syscall
48 returns a value in -1 .. -4095 as a valid result so we can savely
49 test with -4095. */
50
51/* We don't want the label for the error handle to be global when we define
52 it here. */
53#ifdef PIC
54# define SYSCALL_ERROR_LABEL 0f
55#else
56# define SYSCALL_ERROR_LABEL syscall_error
57#endif
58
59#undef PSEUDO
60#define PSEUDO(name, syscall_name, args) \
61 .text; \
62 ENTRY (name) \
63 DO_CALL (args, syscall_name); \
64 cmpq $-4095, %rax; \
65 jae SYSCALL_ERROR_LABEL; \
66 L(pseudo_end):
67
68#undef PSEUDO_END
69#define PSEUDO_END(name) \
70 SYSCALL_ERROR_HANDLER \
71 END (name)
72
73#ifndef PIC
74#define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
75#else
76/* Store (- %rax) into errno through the GOT. */
77#ifdef _LIBC_REENTRANT
78#define SYSCALL_ERROR_HANDLER \
790: \
80 xorq %rdx, %rdx; \
81 subq %rax, %rdx; \
82 pushq %rdx \
83 PUSH_ERRNO_LOCATION_RETURN; \
84 call BP_SYM (__errno_location)@PLT; \
85 POP_ERRNO_LOCATION_RETURN; \
86 popq %rdx; \
87 movq %rdx, (%rax); \
88 orq $-1, %rax; \
89 jmp L(pseudo_end);
90
91/* A quick note: it is assumed that the call to `__errno_location' does
92 not modify the stack! */
93#else
94#define SYSCALL_ERROR_HANDLER \
950:movq errno@GOTPCREL(%RIP), %rcx; \
96 xorq %rdx, %rdx; \
97 subq %rax, %rdx; \
98 movq %rdx, (%rcx); \
99 orq $-1, %rax; \
100 jmp L(pseudo_end);
101#endif /* _LIBC_REENTRANT */
102#endif /* PIC */
103
104/* Linux/x86-64 takes system call arguments in registers:
105
106 Register setup:
107 system call number rax
108 arg 1 rdi
109 arg 2 rsi
110 arg 3 rdx
111 arg 4 rcx
112 arg 5 r8
113 arg 6 r9
114
115 return address from
116 syscall rcx
117 additionally clobered: r12-r15,rbx,rbp
118 eflags from syscall r11
119
120 The compiler is going to form a call by coming here, through PSEUDO, with arguments:
121
122 syscall number in the DO_CALL macro
123 arg 1 rdi
124 arg 2 rsi
125 arg 3 rdx
126 arg 4 r10
127 arg 5 r8
128 arg 6 r9
129
130 We have to take care that the stack is alignedto 16 bytes. When
131 called the stack is not aligned since the return address has just
132 been pushed.
133
134 Syscalls of more than 6 arguments are not supported. */
135
136#undef DO_CALL
137#define DO_CALL(args, syscall_name) \
138 DOARGS_##args \
139 movq $SYS_ify (syscall_name), %rax; \
140 syscall;
141
142#define DOARGS_0 /* nothing */
143#define DOARGS_1 /* nothing */
144#define DOARGS_2 /* nothing */
145#define DOARGS_3 /* nothing */
146#define DOARGS_4 movq %rcx, %r10;
147#define DOARGS_5 DOARGS_4
148#define DOARGS_6 DOARGS_5
149
150#else /* !__ASSEMBLER__ */
151/* Define a macro which expands inline into the wrapper code for a system
152 call. */
153#undef INLINE_SYSCALL
154#define INLINE_SYSCALL(name, nr, args...) \
155 ({ \
156 unsigned long resultvar; \
157 LOAD_ARGS_##nr (args) \
158 asm volatile ( \
159 "movq %1, %%rax\n\t" \
160 "syscall\n\t" \
161 : "=a" (resultvar) \
162 : "i" (__NR_##name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx"); \
163 if (resultvar >= (unsigned long) -4095) \
164 { \
165 __set_errno (-resultvar); \
166 resultvar = (unsigned long) -1; \
167 } \
168 (long) resultvar; })
169
170#define LOAD_ARGS_0()
171#define ASM_ARGS_0
172
173#define LOAD_ARGS_1(a1) \
174 register long int _a1 asm ("rdi") = (long) (a1); \
175 LOAD_ARGS_0 ()
176#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1)
177
178#define LOAD_ARGS_2(a1, a2) \
179 register long int _a2 asm ("rsi") = (long) (a2); \
180 LOAD_ARGS_1 (a1)
181#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2)
182
183#define LOAD_ARGS_3(a1, a2, a3) \
184 register long int _a3 asm ("rdx") = (long) (a3); \
185 LOAD_ARGS_2 (a1, a2)
186#define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3)
187
188#define LOAD_ARGS_4(a1, a2, a3, a4) \
189 register long int _a4 asm ("r10") = (long) (a4); \
190 LOAD_ARGS_3 (a1, a2, a3)
191#define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4)
192
193#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
194 register long int _a5 asm ("r8") = (long) (a5); \
195 LOAD_ARGS_4 (a1, a2, a3, a4)
196#define ASM_ARGS_5 ASM_ARGS_4, "r" (_a5)
197
198#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \
199 register long int _a6 asm ("r9") = (long) (a6); \
200 LOAD_ARGS_5 (a1, a2, a3, a4, a5)
201#define ASM_ARGS_6 ASM_ARGS_5, "r" (_a6)
202
203#endif /* __ASSEMBLER__ */
204
205#endif /* linux/x86_64/sysdep.h */