]>
Commit | Line | Data |
---|---|---|
a77d3c17 | 1 | /* Copyright (C) 2001-2005, 2007, 2011 Free Software Foundation, Inc. |
c9cf6dde AJ |
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> | |
89b91a92 | 26 | #include <tls.h> |
c9cf6dde | 27 | |
ce460d04 RM |
28 | #ifdef IS_IN_rtld |
29 | # include <dl-sysdep.h> /* Defines RTLD_PRIVATE_ERRNO. */ | |
30 | #endif | |
31 | ||
c9cf6dde AJ |
32 | /* For Linux we can use the system call table in the header file |
33 | /usr/include/asm/unistd.h | |
34 | of the kernel. But these symbols do not follow the SYS_* syntax | |
35 | so we have to redefine the `SYS_ify' macro here. */ | |
36 | #undef SYS_ify | |
37 | #define SYS_ify(syscall_name) __NR_##syscall_name | |
38 | ||
3899afcb RM |
39 | /* This is a kludge to make syscalls.list find these under the names |
40 | pread and pwrite, since some kernel headers define those names | |
41 | and some define the *64 names for the same system calls. */ | |
42 | #if !defined __NR_pread && defined __NR_pread64 | |
43 | # define __NR_pread __NR_pread64 | |
44 | #endif | |
45 | #if !defined __NR_pwrite && defined __NR_pwrite64 | |
46 | # define __NR_pwrite __NR_pwrite64 | |
47 | #endif | |
48 | ||
0fe8d5e6 AJ |
49 | /* This is to help the old kernel headers where __NR_semtimedop is not |
50 | available. */ | |
51 | #ifndef __NR_semtimedop | |
52 | # define __NR_semtimedop 220 | |
53 | #endif | |
54 | ||
55 | ||
c9cf6dde AJ |
56 | #ifdef __ASSEMBLER__ |
57 | ||
58 | /* Linux uses a negative return value to indicate syscall errors, | |
59 | unlike most Unices, which use the condition codes' carry flag. | |
60 | ||
61 | Since version 2.1 the return value of a system call might be | |
62 | negative even if the call succeeded. E.g., the `lseek' system call | |
63 | might return a large offset. Therefore we must not anymore test | |
64 | for < 0, but test for a real error by making sure the value in %eax | |
65 | is a real error number. Linus said he will make sure the no syscall | |
66 | returns a value in -1 .. -4095 as a valid result so we can savely | |
67 | test with -4095. */ | |
68 | ||
69 | /* We don't want the label for the error handle to be global when we define | |
70 | it here. */ | |
75fb247e UD |
71 | # ifdef PIC |
72 | # define SYSCALL_ERROR_LABEL 0f | |
73 | # else | |
74 | # define SYSCALL_ERROR_LABEL syscall_error | |
75 | # endif | |
c9cf6dde | 76 | |
75fb247e UD |
77 | # undef PSEUDO |
78 | # define PSEUDO(name, syscall_name, args) \ | |
c9cf6dde AJ |
79 | .text; \ |
80 | ENTRY (name) \ | |
ffa8d2a0 | 81 | DO_CALL (syscall_name, args); \ |
c9cf6dde AJ |
82 | cmpq $-4095, %rax; \ |
83 | jae SYSCALL_ERROR_LABEL; \ | |
84 | L(pseudo_end): | |
85 | ||
75fb247e UD |
86 | # undef PSEUDO_END |
87 | # define PSEUDO_END(name) \ | |
c9cf6dde AJ |
88 | SYSCALL_ERROR_HANDLER \ |
89 | END (name) | |
90 | ||
75fb247e UD |
91 | # undef PSEUDO_NOERRNO |
92 | # define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
9eb88290 UD |
93 | .text; \ |
94 | ENTRY (name) \ | |
95 | DO_CALL (syscall_name, args) | |
96 | ||
75fb247e UD |
97 | # undef PSEUDO_END_NOERRNO |
98 | # define PSEUDO_END_NOERRNO(name) \ | |
9eb88290 UD |
99 | END (name) |
100 | ||
75fb247e | 101 | # define ret_NOERRNO ret |
f38afd78 | 102 | |
75fb247e UD |
103 | # undef PSEUDO_ERRVAL |
104 | # define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
bfef9264 UD |
105 | .text; \ |
106 | ENTRY (name) \ | |
107 | DO_CALL (syscall_name, args); \ | |
f38afd78 | 108 | negq %rax |
bfef9264 | 109 | |
75fb247e UD |
110 | # undef PSEUDO_END_ERRVAL |
111 | # define PSEUDO_END_ERRVAL(name) \ | |
bfef9264 UD |
112 | END (name) |
113 | ||
75fb247e | 114 | # define ret_ERRVAL ret |
9eb88290 | 115 | |
75fb247e UD |
116 | # ifndef PIC |
117 | # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ | |
118 | # elif RTLD_PRIVATE_ERRNO | |
119 | # define SYSCALL_ERROR_HANDLER \ | |
1077a5f2 | 120 | 0: \ |
96c82b3f | 121 | leaq rtld_errno(%rip), %rcx; \ |
ee618985 | 122 | xorl %edx, %edx; \ |
3efdff78 | 123 | subq %rax, %rdx; \ |
89b91a92 | 124 | movl %edx, (%rcx); \ |
5232c939 RM |
125 | orq $-1, %rax; \ |
126 | jmp L(pseudo_end); | |
d063d164 | 127 | # else |
75fb247e UD |
128 | # ifndef NOT_IN_libc |
129 | # define SYSCALL_ERROR_ERRNO __libc_errno | |
130 | # else | |
131 | # define SYSCALL_ERROR_ERRNO errno | |
132 | # endif | |
133 | # define SYSCALL_ERROR_HANDLER \ | |
1077a5f2 | 134 | 0: \ |
0a951d0e | 135 | movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\ |
ee618985 | 136 | xorl %edx, %edx; \ |
ce460d04 | 137 | subq %rax, %rdx; \ |
89b91a92 | 138 | movl %edx, %fs:(%rcx); \ |
5232c939 RM |
139 | orq $-1, %rax; \ |
140 | jmp L(pseudo_end); | |
75fb247e | 141 | # endif /* PIC */ |
c9cf6dde | 142 | |
092fd00d AJ |
143 | /* The Linux/x86-64 kernel expects the system call parameters in |
144 | registers according to the following table: | |
c9cf6dde | 145 | |
092fd00d | 146 | syscall number rax |
c9cf6dde AJ |
147 | arg 1 rdi |
148 | arg 2 rsi | |
149 | arg 3 rdx | |
092fd00d | 150 | arg 4 r10 |
c9cf6dde AJ |
151 | arg 5 r8 |
152 | arg 6 r9 | |
153 | ||
092fd00d | 154 | The Linux kernel uses and destroys internally these registers: |
c9cf6dde AJ |
155 | return address from |
156 | syscall rcx | |
c9cf6dde AJ |
157 | eflags from syscall r11 |
158 | ||
092fd00d AJ |
159 | Normal function call, including calls to the system call stub |
160 | functions in the libc, get the first six parameters passed in | |
161 | registers and the seventh parameter and later on the stack. The | |
162 | register use is as follows: | |
163 | ||
164 | system call number in the DO_CALL macro | |
165 | arg 1 rdi | |
166 | arg 2 rsi | |
167 | arg 3 rdx | |
168 | arg 4 rcx | |
169 | arg 5 r8 | |
170 | arg 6 r9 | |
171 | ||
172 | We have to take care that the stack is aligned to 16 bytes. When | |
173 | called the stack is not aligned since the return address has just | |
174 | been pushed. | |
175 | ||
9eb88290 | 176 | |
092fd00d | 177 | Syscalls of more than 6 arguments are not supported. */ |
c9cf6dde | 178 | |
75fb247e UD |
179 | # undef DO_CALL |
180 | # define DO_CALL(syscall_name, args) \ | |
c9cf6dde | 181 | DOARGS_##args \ |
ee618985 | 182 | movl $SYS_ify (syscall_name), %eax; \ |
c9cf6dde AJ |
183 | syscall; |
184 | ||
75fb247e UD |
185 | # define DOARGS_0 /* nothing */ |
186 | # define DOARGS_1 /* nothing */ | |
187 | # define DOARGS_2 /* nothing */ | |
188 | # define DOARGS_3 /* nothing */ | |
189 | # define DOARGS_4 movq %rcx, %r10; | |
190 | # define DOARGS_5 DOARGS_4 | |
191 | # define DOARGS_6 DOARGS_5 | |
c9cf6dde AJ |
192 | |
193 | #else /* !__ASSEMBLER__ */ | |
194 | /* Define a macro which expands inline into the wrapper code for a system | |
195 | call. */ | |
75fb247e UD |
196 | # undef INLINE_SYSCALL |
197 | # define INLINE_SYSCALL(name, nr, args...) \ | |
369b849f | 198 | ({ \ |
78b767a0 | 199 | unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ |
6aca81bb | 200 | if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0)) \ |
369b849f | 201 | { \ |
6aca81bb | 202 | __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \ |
78b767a0 | 203 | resultvar = (unsigned long int) -1; \ |
369b849f | 204 | } \ |
78b767a0 | 205 | (long int) resultvar; }) |
369b849f | 206 | |
75fb247e UD |
207 | # undef INTERNAL_SYSCALL_DECL |
208 | # define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
6aca81bb | 209 | |
75fb247e | 210 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ |
c9cf6dde | 211 | ({ \ |
78b767a0 | 212 | unsigned long int resultvar; \ |
c9cf6dde | 213 | LOAD_ARGS_##nr (args) \ |
381a0c26 | 214 | LOAD_REGS_##nr \ |
c9cf6dde | 215 | asm volatile ( \ |
c9cf6dde AJ |
216 | "syscall\n\t" \ |
217 | : "=a" (resultvar) \ | |
2edb61e3 | 218 | : "0" (name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx"); \ |
78b767a0 | 219 | (long int) resultvar; }) |
75fb247e UD |
220 | # undef INTERNAL_SYSCALL |
221 | # define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
2edb61e3 | 222 | INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args) |
c9cf6dde | 223 | |
75fb247e UD |
224 | # undef INTERNAL_SYSCALL_ERROR_P |
225 | # define INTERNAL_SYSCALL_ERROR_P(val, err) \ | |
78b767a0 | 226 | ((unsigned long int) (long int) (val) >= -4095L) |
369b849f | 227 | |
75fb247e UD |
228 | # undef INTERNAL_SYSCALL_ERRNO |
229 | # define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) | |
230 | ||
231 | # ifdef SHARED | |
232 | # define INLINE_VSYSCALL(name, nr, args...) \ | |
233 | ({ \ | |
234 | __label__ out; \ | |
235 | __label__ iserr; \ | |
236 | INTERNAL_SYSCALL_DECL (sc_err); \ | |
237 | long int sc_ret; \ | |
238 | \ | |
3c87d79d UD |
239 | __typeof (__vdso_##name) vdsop = __vdso_##name; \ |
240 | PTR_DEMANGLE (vdsop); \ | |
241 | if (vdsop != NULL) \ | |
75fb247e | 242 | { \ |
3c87d79d | 243 | sc_ret = vdsop (args); \ |
75fb247e UD |
244 | if (!INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \ |
245 | goto out; \ | |
246 | if (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err) != ENOSYS) \ | |
247 | goto iserr; \ | |
248 | } \ | |
249 | \ | |
250 | sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, ##args); \ | |
251 | if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \ | |
252 | { \ | |
253 | iserr: \ | |
a77d3c17 UD |
254 | __set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err)); \ |
255 | sc_ret = -1L; \ | |
75fb247e UD |
256 | } \ |
257 | out: \ | |
258 | sc_ret; \ | |
259 | }) | |
260 | # define INTERNAL_VSYSCALL(name, err, nr, args...) \ | |
261 | ({ \ | |
262 | __label__ out; \ | |
263 | long int v_ret; \ | |
264 | \ | |
3c87d79d UD |
265 | __typeof (__vdso_##name) vdsop = __vdso_##name; \ |
266 | PTR_DEMANGLE (vdsop); \ | |
267 | if (vdsop != NULL) \ | |
75fb247e | 268 | { \ |
3c87d79d | 269 | v_ret = vdsop (args); \ |
75fb247e UD |
270 | if (!INTERNAL_SYSCALL_ERROR_P (v_ret, err) \ |
271 | || INTERNAL_SYSCALL_ERRNO (v_ret, err) != ENOSYS) \ | |
272 | goto out; \ | |
273 | } \ | |
274 | v_ret = INTERNAL_SYSCALL (name, err, nr, ##args); \ | |
275 | out: \ | |
276 | v_ret; \ | |
277 | }) | |
278 | ||
75fb247e UD |
279 | # else |
280 | # define INLINE_VSYSCALL(name, nr, args...) \ | |
281 | INLINE_SYSCALL (name, nr, ##args) | |
282 | # define INTERNAL_VSYSCALL(name, err, nr, args...) \ | |
283 | INTERNAL_SYSCALL (name, err, nr, ##args) | |
284 | # endif | |
369b849f | 285 | |
75fb247e UD |
286 | # define LOAD_ARGS_0() |
287 | # define LOAD_REGS_0 | |
288 | # define ASM_ARGS_0 | |
c9cf6dde | 289 | |
75fb247e | 290 | # define LOAD_ARGS_1(a1) \ |
78b767a0 | 291 | long int __arg1 = (long int) (a1); \ |
c9cf6dde | 292 | LOAD_ARGS_0 () |
75fb247e | 293 | # define LOAD_REGS_1 \ |
381a0c26 UD |
294 | register long int _a1 asm ("rdi") = __arg1; \ |
295 | LOAD_REGS_0 | |
75fb247e | 296 | # define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) |
c9cf6dde | 297 | |
75fb247e | 298 | # define LOAD_ARGS_2(a1, a2) \ |
78b767a0 | 299 | long int __arg2 = (long int) (a2); \ |
c9cf6dde | 300 | LOAD_ARGS_1 (a1) |
75fb247e | 301 | # define LOAD_REGS_2 \ |
381a0c26 UD |
302 | register long int _a2 asm ("rsi") = __arg2; \ |
303 | LOAD_REGS_1 | |
75fb247e | 304 | # define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) |
c9cf6dde | 305 | |
75fb247e | 306 | # define LOAD_ARGS_3(a1, a2, a3) \ |
78b767a0 | 307 | long int __arg3 = (long int) (a3); \ |
c9cf6dde | 308 | LOAD_ARGS_2 (a1, a2) |
75fb247e | 309 | # define LOAD_REGS_3 \ |
381a0c26 UD |
310 | register long int _a3 asm ("rdx") = __arg3; \ |
311 | LOAD_REGS_2 | |
75fb247e | 312 | # define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) |
c9cf6dde | 313 | |
75fb247e | 314 | # define LOAD_ARGS_4(a1, a2, a3, a4) \ |
78b767a0 | 315 | long int __arg4 = (long int) (a4); \ |
c9cf6dde | 316 | LOAD_ARGS_3 (a1, a2, a3) |
75fb247e | 317 | # define LOAD_REGS_4 \ |
381a0c26 UD |
318 | register long int _a4 asm ("r10") = __arg4; \ |
319 | LOAD_REGS_3 | |
75fb247e | 320 | # define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) |
c9cf6dde | 321 | |
75fb247e | 322 | # define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ |
78b767a0 | 323 | long int __arg5 = (long int) (a5); \ |
c9cf6dde | 324 | LOAD_ARGS_4 (a1, a2, a3, a4) |
75fb247e | 325 | # define LOAD_REGS_5 \ |
381a0c26 UD |
326 | register long int _a5 asm ("r8") = __arg5; \ |
327 | LOAD_REGS_4 | |
75fb247e | 328 | # define ASM_ARGS_5 ASM_ARGS_4, "r" (_a5) |
c9cf6dde | 329 | |
75fb247e | 330 | # define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ |
78b767a0 | 331 | long int __arg6 = (long int) (a6); \ |
c9cf6dde | 332 | LOAD_ARGS_5 (a1, a2, a3, a4, a5) |
75fb247e | 333 | # define LOAD_REGS_6 \ |
381a0c26 UD |
334 | register long int _a6 asm ("r9") = __arg6; \ |
335 | LOAD_REGS_5 | |
75fb247e | 336 | # define ASM_ARGS_6 ASM_ARGS_5, "r" (_a6) |
c9cf6dde AJ |
337 | |
338 | #endif /* __ASSEMBLER__ */ | |
339 | ||
827b7087 UD |
340 | |
341 | /* Pointer mangling support. */ | |
342 | #if defined NOT_IN_libc && defined IS_IN_rtld | |
343 | /* We cannot use the thread descriptor because in ld.so we use setjmp | |
344 | earlier than the descriptor is initialized. */ | |
3467f5c3 | 345 | # ifdef __ASSEMBLER__ |
4a44ce79 UD |
346 | # define PTR_MANGLE(reg) xorq __pointer_chk_guard_local(%rip), reg; \ |
347 | rolq $17, reg | |
348 | # define PTR_DEMANGLE(reg) rorq $17, reg; \ | |
349 | xorq __pointer_chk_guard_local(%rip), reg | |
3467f5c3 | 350 | # else |
4a44ce79 UD |
351 | # define PTR_MANGLE(reg) asm ("xorq __pointer_chk_guard_local(%%rip), %0\n" \ |
352 | "rolq $17, %0" \ | |
353 | : "=r" (reg) : "0" (reg)) | |
354 | # define PTR_DEMANGLE(reg) asm ("rorq $17, %0\n" \ | |
355 | "xorq __pointer_chk_guard_local(%%rip), %0" \ | |
7725f874 | 356 | : "=r" (reg) : "0" (reg)) |
3467f5c3 | 357 | # endif |
827b7087 | 358 | #else |
3467f5c3 | 359 | # ifdef __ASSEMBLER__ |
4a44ce79 UD |
360 | # define PTR_MANGLE(reg) xorq %fs:POINTER_GUARD, reg; \ |
361 | rolq $17, reg | |
362 | # define PTR_DEMANGLE(reg) rorq $17, reg; \ | |
363 | xorq %fs:POINTER_GUARD, reg | |
3467f5c3 | 364 | # else |
4a44ce79 UD |
365 | # define PTR_MANGLE(var) asm ("xorq %%fs:%c2, %0\n" \ |
366 | "rolq $17, %0" \ | |
367 | : "=r" (var) \ | |
368 | : "0" (var), \ | |
369 | "i" (offsetof (tcbhead_t, \ | |
370 | pointer_guard))) | |
371 | # define PTR_DEMANGLE(var) asm ("rorq $17, %0\n" \ | |
372 | "xorq %%fs:%c2, %0" \ | |
3467f5c3 UD |
373 | : "=r" (var) \ |
374 | : "0" (var), \ | |
375 | "i" (offsetof (tcbhead_t, \ | |
376 | pointer_guard))) | |
3467f5c3 | 377 | # endif |
827b7087 UD |
378 | #endif |
379 | ||
c9cf6dde | 380 | #endif /* linux/x86_64/sysdep.h */ |