]>
Commit | Line | Data |
---|---|---|
d614a753 | 1 | /* Copyright (C) 1992-2020 Free Software Foundation, Inc. |
bfbc5754 | 2 | This file is part of the GNU C Library. |
44129238 | 3 | Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995. |
bfbc5754 UD |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
bfbc5754 UD |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
bfbc5754 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
d2f5be2a | 18 | |
ec4b0518 UD |
19 | #ifndef _LINUX_I386_SYSDEP_H |
20 | #define _LINUX_I386_SYSDEP_H 1 | |
21 | ||
d2f5be2a | 22 | /* There is some commonality. */ |
fb1cf108 | 23 | #include <sysdeps/unix/sysv/linux/sysdep.h> |
d2f5be2a | 24 | #include <sysdeps/unix/i386/sysdep.h> |
131fd126 | 25 | /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */ |
5f5843e3 | 26 | #include <dl-sysdep.h> |
739d440d | 27 | #include <tls.h> |
d2f5be2a | 28 | |
ce460d04 | 29 | |
d2f5be2a UD |
30 | /* For Linux we can use the system call table in the header file |
31 | /usr/include/asm/unistd.h | |
32 | of the kernel. But these symbols do not follow the SYS_* syntax | |
33 | so we have to redefine the `SYS_ify' macro here. */ | |
34 | #undef SYS_ify | |
6ed0492f | 35 | #define SYS_ify(syscall_name) __NR_##syscall_name |
d2f5be2a | 36 | |
627c69c8 L |
37 | #ifndef I386_USE_SYSENTER |
38 | # if defined USE_DL_SYSINFO \ | |
39 | && (IS_IN (libc) || IS_IN (libpthread)) | |
40 | # define I386_USE_SYSENTER 1 | |
41 | # else | |
42 | # define I386_USE_SYSENTER 0 | |
43 | # endif | |
5f5843e3 UD |
44 | #endif |
45 | ||
95b09777 L |
46 | /* Since GCC 5 and above can properly spill %ebx with PIC when needed, |
47 | we can inline syscalls with 6 arguments if GCC 5 or above is used | |
48 | to compile glibc. Disable GCC 5 optimization when compiling for | |
3b33d6ed AZ |
49 | profiling or when -fno-omit-frame-pointer is used since asm ("ebp") |
50 | can't be used to put the 6th argument in %ebp for syscall. */ | |
51 | #if __GNUC_PREREQ (5,0) && !defined PROF && CAN_USE_REGISTER_ASM_EBP | |
95b09777 L |
52 | # define OPTIMIZE_FOR_GCC_5 |
53 | #endif | |
54 | ||
c2afe833 RM |
55 | #ifdef __ASSEMBLER__ |
56 | ||
cccda09f UD |
57 | /* Linux uses a negative return value to indicate syscall errors, |
58 | unlike most Unices, which use the condition codes' carry flag. | |
59 | ||
60 | Since version 2.1 the return value of a system call might be | |
61 | negative even if the call succeeded. E.g., the `lseek' system call | |
62 | might return a large offset. Therefore we must not anymore test | |
63 | for < 0, but test for a real error by making sure the value in %eax | |
b5791037 UD |
64 | is a real error number. Linus said he will make sure the no syscall |
65 | returns a value in -1 .. -4095 as a valid result so we can savely | |
66 | test with -4095. */ | |
c0fb8a56 UD |
67 | |
68 | /* We don't want the label for the error handle to be global when we define | |
69 | it here. */ | |
fb1cf108 | 70 | #define SYSCALL_ERROR_LABEL __syscall_error |
c0fb8a56 | 71 | |
d2f5be2a UD |
72 | #undef PSEUDO |
73 | #define PSEUDO(name, syscall_name, args) \ | |
74 | .text; \ | |
d2f5be2a | 75 | ENTRY (name) \ |
ffa8d2a0 | 76 | DO_CALL (syscall_name, args); \ |
b5791037 | 77 | cmpl $-4095, %eax; \ |
842a39cd | 78 | jae SYSCALL_ERROR_LABEL |
d2f5be2a | 79 | |
6ed0492f UD |
80 | #undef PSEUDO_END |
81 | #define PSEUDO_END(name) \ | |
82 | SYSCALL_ERROR_HANDLER \ | |
83 | END (name) | |
84 | ||
9eb88290 UD |
85 | #undef PSEUDO_NOERRNO |
86 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
87 | .text; \ | |
88 | ENTRY (name) \ | |
89 | DO_CALL (syscall_name, args) | |
90 | ||
91 | #undef PSEUDO_END_NOERRNO | |
92 | #define PSEUDO_END_NOERRNO(name) \ | |
93 | END (name) | |
94 | ||
95 | #define ret_NOERRNO ret | |
96 | ||
bfef9264 UD |
97 | /* The function has to return the error code. */ |
98 | #undef PSEUDO_ERRVAL | |
99 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
100 | .text; \ | |
101 | ENTRY (name) \ | |
102 | DO_CALL (syscall_name, args); \ | |
103 | negl %eax | |
104 | ||
105 | #undef PSEUDO_END_ERRVAL | |
106 | #define PSEUDO_END_ERRVAL(name) \ | |
107 | END (name) | |
108 | ||
109 | #define ret_ERRVAL ret | |
110 | ||
fb1cf108 | 111 | #define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.c is used. */ |
f051627f UD |
112 | |
113 | /* The original calling convention for system calls on Linux/i386 is | |
114 | to use int $0x80. */ | |
627c69c8 L |
115 | #if I386_USE_SYSENTER |
116 | # ifdef PIC | |
5f5843e3 UD |
117 | # define ENTER_KERNEL call *%gs:SYSINFO_OFFSET |
118 | # else | |
119 | # define ENTER_KERNEL call *_dl_sysinfo | |
120 | # endif | |
121 | #else | |
122 | # define ENTER_KERNEL int $0x80 | |
123 | #endif | |
f051627f | 124 | |
d2f5be2a UD |
125 | /* Linux takes system call arguments in registers: |
126 | ||
127 | syscall number %eax call-clobbered | |
128 | arg 1 %ebx call-saved | |
129 | arg 2 %ecx call-clobbered | |
130 | arg 3 %edx call-clobbered | |
131 | arg 4 %esi call-saved | |
132 | arg 5 %edi call-saved | |
b2bcd249 | 133 | arg 6 %ebp call-saved |
d2f5be2a UD |
134 | |
135 | The stack layout upon entering the function is: | |
136 | ||
b2bcd249 | 137 | 24(%esp) Arg# 6 |
d2f5be2a UD |
138 | 20(%esp) Arg# 5 |
139 | 16(%esp) Arg# 4 | |
140 | 12(%esp) Arg# 3 | |
141 | 8(%esp) Arg# 2 | |
142 | 4(%esp) Arg# 1 | |
143 | (%esp) Return address | |
144 | ||
145 | (Of course a function with say 3 arguments does not have entries for | |
b2bcd249 | 146 | arguments 4, 5, and 6.) |
d2f5be2a | 147 | |
6ed0492f | 148 | The following code tries hard to be optimal. A general assumption |
03a75825 | 149 | (which is true according to the data books I have) is that |
d2f5be2a UD |
150 | |
151 | 2 * xchg is more expensive than pushl + movl + popl | |
152 | ||
153 | Beside this a neat trick is used. The calling conventions for Linux | |
154 | tell that among the registers used for parameters %ecx and %edx need | |
155 | not be saved. Beside this we may clobber this registers even when | |
156 | they are not used for parameter passing. | |
157 | ||
158 | As a result one can see below that we save the content of the %ebx | |
159 | register in the %edx register when we have less than 3 arguments | |
160 | (2 * movl is less expensive than pushl + popl). | |
161 | ||
162 | Second unlike for the other registers we don't save the content of | |
6ed0492f | 163 | %ecx and %edx when we have more than 1 and 2 registers resp. |
8f5ca04b RM |
164 | |
165 | The code below might look a bit long but we have to take care for | |
63bda0c1 | 166 | the pipelined processors (i586). Here the `pushl' and `popl' |
8f5ca04b RM |
167 | instructions are marked as NP (not pairable) but the exception is |
168 | two consecutive of these instruction. This gives no penalty on | |
63bda0c1 | 169 | other processors though. */ |
d2f5be2a UD |
170 | |
171 | #undef DO_CALL | |
ffa8d2a0 | 172 | #define DO_CALL(syscall_name, args) \ |
8f5ca04b | 173 | PUSHARGS_##args \ |
d2f5be2a | 174 | DOARGS_##args \ |
c14e4c32 | 175 | movl $SYS_ify (syscall_name), %eax; \ |
f051627f | 176 | ENTER_KERNEL \ |
8f5ca04b | 177 | POPARGS_##args |
d2f5be2a | 178 | |
8f5ca04b | 179 | #define PUSHARGS_0 /* No arguments to push. */ |
d2f5be2a | 180 | #define DOARGS_0 /* No arguments to frob. */ |
8f5ca04b RM |
181 | #define POPARGS_0 /* No arguments to pop. */ |
182 | #define _PUSHARGS_0 /* No arguments to push. */ | |
183 | #define _DOARGS_0(n) /* No arguments to frob. */ | |
184 | #define _POPARGS_0 /* No arguments to pop. */ | |
185 | ||
bd4f43b4 | 186 | #define PUSHARGS_1 movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0 |
8f5ca04b | 187 | #define DOARGS_1 _DOARGS_1 (4) |
bd4f43b4 | 188 | #define POPARGS_1 POPARGS_0; movl %edx, %ebx; L(RESTBX1): |
62d01985 UD |
189 | #define _PUSHARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \ |
190 | cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0 | |
8f5ca04b | 191 | #define _DOARGS_1(n) movl n(%esp), %ebx; _DOARGS_0(n-4) |
62d01985 UD |
192 | #define _POPARGS_1 _POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \ |
193 | cfi_restore (ebx); L(POPBX1): | |
8f5ca04b RM |
194 | |
195 | #define PUSHARGS_2 PUSHARGS_1 | |
196 | #define DOARGS_2 _DOARGS_2 (8) | |
197 | #define POPARGS_2 POPARGS_1 | |
198 | #define _PUSHARGS_2 _PUSHARGS_1 | |
d2f5be2a | 199 | #define _DOARGS_2(n) movl n(%esp), %ecx; _DOARGS_1 (n-4) |
8f5ca04b | 200 | #define _POPARGS_2 _POPARGS_1 |
d2f5be2a | 201 | |
8f5ca04b RM |
202 | #define PUSHARGS_3 _PUSHARGS_2 |
203 | #define DOARGS_3 _DOARGS_3 (16) | |
204 | #define POPARGS_3 _POPARGS_3 | |
205 | #define _PUSHARGS_3 _PUSHARGS_2 | |
d2f5be2a | 206 | #define _DOARGS_3(n) movl n(%esp), %edx; _DOARGS_2 (n-4) |
8f5ca04b RM |
207 | #define _POPARGS_3 _POPARGS_2 |
208 | ||
209 | #define PUSHARGS_4 _PUSHARGS_4 | |
210 | #define DOARGS_4 _DOARGS_4 (24) | |
211 | #define POPARGS_4 _POPARGS_4 | |
62d01985 UD |
212 | #define _PUSHARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \ |
213 | cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3 | |
8f5ca04b | 214 | #define _DOARGS_4(n) movl n(%esp), %esi; _DOARGS_3 (n-4) |
62d01985 UD |
215 | #define _POPARGS_4 _POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \ |
216 | cfi_restore (esi); L(POPSI1): | |
8f5ca04b RM |
217 | |
218 | #define PUSHARGS_5 _PUSHARGS_5 | |
219 | #define DOARGS_5 _DOARGS_5 (32) | |
220 | #define POPARGS_5 _POPARGS_5 | |
62d01985 UD |
221 | #define _PUSHARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \ |
222 | cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4 | |
8f5ca04b | 223 | #define _DOARGS_5(n) movl n(%esp), %edi; _DOARGS_4 (n-4) |
62d01985 UD |
224 | #define _POPARGS_5 _POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \ |
225 | cfi_restore (edi); L(POPDI1): | |
d2f5be2a | 226 | |
0da7bcc5 | 227 | #define PUSHARGS_6 _PUSHARGS_6 |
46c38bd7 | 228 | #define DOARGS_6 _DOARGS_6 (40) |
0da7bcc5 | 229 | #define POPARGS_6 _POPARGS_6 |
62d01985 UD |
230 | #define _PUSHARGS_6 pushl %ebp; cfi_adjust_cfa_offset (4); \ |
231 | cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5 | |
0da7bcc5 | 232 | #define _DOARGS_6(n) movl n(%esp), %ebp; _DOARGS_5 (n-4) |
62d01985 UD |
233 | #define _POPARGS_6 _POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \ |
234 | cfi_restore (ebp); L(POPBP1): | |
0da7bcc5 | 235 | |
adcb550c UD |
236 | #else /* !__ASSEMBLER__ */ |
237 | ||
fb1cf108 L |
238 | extern int __syscall_error (int) |
239 | attribute_hidden __attribute__ ((__regparm__ (1))); | |
240 | ||
23c4baa2 | 241 | #ifndef OPTIMIZE_FOR_GCC_5 |
78e5779b UD |
242 | /* We need some help from the assembler to generate optimal code. We |
243 | define some macros here which later will be used. */ | |
e3e35cfc UD |
244 | asm (".L__X'%ebx = 1\n\t" |
245 | ".L__X'%ecx = 2\n\t" | |
246 | ".L__X'%edx = 2\n\t" | |
247 | ".L__X'%eax = 3\n\t" | |
248 | ".L__X'%esi = 3\n\t" | |
249 | ".L__X'%edi = 3\n\t" | |
250 | ".L__X'%ebp = 3\n\t" | |
251 | ".L__X'%esp = 3\n\t" | |
78e5779b UD |
252 | ".macro bpushl name reg\n\t" |
253 | ".if 1 - \\name\n\t" | |
254 | ".if 2 - \\name\n\t" | |
7a114794 | 255 | "error\n\t" |
78e5779b UD |
256 | ".else\n\t" |
257 | "xchgl \\reg, %ebx\n\t" | |
258 | ".endif\n\t" | |
259 | ".endif\n\t" | |
260 | ".endm\n\t" | |
261 | ".macro bpopl name reg\n\t" | |
262 | ".if 1 - \\name\n\t" | |
263 | ".if 2 - \\name\n\t" | |
7a114794 | 264 | "error\n\t" |
78e5779b UD |
265 | ".else\n\t" |
266 | "xchgl \\reg, %ebx\n\t" | |
267 | ".endif\n\t" | |
268 | ".endif\n\t" | |
78e5779b UD |
269 | ".endm\n\t"); |
270 | ||
a9fe4c5a JM |
271 | /* Six-argument syscalls use an out-of-line helper, because an inline |
272 | asm using all registers apart from %esp cannot work reliably and | |
273 | the assembler does not support describing an asm that saves and | |
274 | restores %ebp itself as a separate stack frame. This structure | |
275 | stores the arguments not passed in registers; %edi is passed with a | |
276 | pointer to this structure. */ | |
277 | struct libc_do_syscall_args | |
278 | { | |
279 | int ebx, edi, ebp; | |
280 | }; | |
98ad631c | 281 | #endif |
a9fe4c5a | 282 | |
adcb550c UD |
283 | /* Define a macro which expands inline into the wrapper code for a system |
284 | call. */ | |
285 | #undef INLINE_SYSCALL | |
fb1cf108 L |
286 | #if IS_IN (libc) |
287 | # define INLINE_SYSCALL(name, nr, args...) \ | |
288 | ({ \ | |
289 | unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ | |
290 | __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, )) \ | |
291 | ? __syscall_error (-INTERNAL_SYSCALL_ERRNO (resultvar, )) \ | |
292 | : (int) resultvar; }) | |
293 | #else | |
294 | # define INLINE_SYSCALL(name, nr, args...) \ | |
ce460d04 | 295 | ({ \ |
6aca81bb | 296 | unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ |
a1ffb40e | 297 | if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \ |
ce460d04 | 298 | { \ |
6aca81bb | 299 | __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \ |
ce460d04 RM |
300 | resultvar = 0xffffffff; \ |
301 | } \ | |
302 | (int) resultvar; }) | |
fb1cf108 L |
303 | #endif |
304 | ||
305 | /* Set error number and return -1. Return the internal function, | |
306 | __syscall_error, which sets errno from the negative error number | |
307 | and returns -1, to avoid PIC. */ | |
308 | #undef INLINE_SYSCALL_ERROR_RETURN_VALUE | |
309 | #define INLINE_SYSCALL_ERROR_RETURN_VALUE(resultvar) \ | |
310 | __syscall_error (-(resultvar)) | |
ce460d04 | 311 | |
b8386c28 AZ |
312 | # define VDSO_NAME "LINUX_2.6" |
313 | # define VDSO_HASH 61765110 | |
314 | ||
1395ef21 | 315 | /* List of system calls which are supported as vsyscalls. */ |
b8a7c7da AZ |
316 | # define HAVE_CLOCK_GETTIME_VSYSCALL "__vdso_clock_gettime" |
317 | # define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday" | |
1395ef21 | 318 | |
ce460d04 RM |
319 | /* Define a macro which expands inline into the wrapper code for a system |
320 | call. This use is for internal calls that do not need to handle errors | |
321 | normally. It will never touch errno. This returns just what the kernel | |
2edb61e3 UD |
322 | gave back. |
323 | ||
324 | The _NCS variant allows non-constant syscall numbers but it is not | |
325 | possible to use more than four parameters. */ | |
ce460d04 | 326 | #undef INTERNAL_SYSCALL |
a9fe4c5a JM |
327 | #define INTERNAL_SYSCALL_MAIN_0(name, err, args...) \ |
328 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 0, args) | |
329 | #define INTERNAL_SYSCALL_MAIN_1(name, err, args...) \ | |
330 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 1, args) | |
331 | #define INTERNAL_SYSCALL_MAIN_2(name, err, args...) \ | |
332 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 2, args) | |
333 | #define INTERNAL_SYSCALL_MAIN_3(name, err, args...) \ | |
334 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 3, args) | |
335 | #define INTERNAL_SYSCALL_MAIN_4(name, err, args...) \ | |
336 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 4, args) | |
337 | #define INTERNAL_SYSCALL_MAIN_5(name, err, args...) \ | |
338 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 5, args) | |
339 | /* Each object using 6-argument inline syscalls must include a | |
340 | definition of __libc_do_syscall. */ | |
23c4baa2 | 341 | #ifdef OPTIMIZE_FOR_GCC_5 |
98ad631c L |
342 | # define INTERNAL_SYSCALL_MAIN_6(name, err, args...) \ |
343 | INTERNAL_SYSCALL_MAIN_INLINE(name, err, 6, args) | |
344 | #else /* GCC 5 */ | |
345 | # define INTERNAL_SYSCALL_MAIN_6(name, err, arg1, arg2, arg3, \ | |
346 | arg4, arg5, arg6) \ | |
a9fe4c5a JM |
347 | struct libc_do_syscall_args _xv = \ |
348 | { \ | |
349 | (int) (arg1), \ | |
350 | (int) (arg5), \ | |
351 | (int) (arg6) \ | |
352 | }; \ | |
353 | asm volatile ( \ | |
354 | "movl %1, %%eax\n\t" \ | |
355 | "call __libc_do_syscall" \ | |
356 | : "=a" (resultvar) \ | |
357 | : "i" (__NR_##name), "c" (arg2), "d" (arg3), "S" (arg4), "D" (&_xv) \ | |
358 | : "memory", "cc") | |
98ad631c | 359 | #endif /* GCC 5 */ |
a9fe4c5a | 360 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ |
5f5843e3 | 361 | ({ \ |
7a114794 | 362 | register unsigned int resultvar; \ |
a9fe4c5a JM |
363 | INTERNAL_SYSCALL_MAIN_##nr (name, err, args); \ |
364 | (int) resultvar; }) | |
627c69c8 | 365 | #if I386_USE_SYSENTER |
23c4baa2 | 366 | # ifdef OPTIMIZE_FOR_GCC_5 |
627c69c8 | 367 | # ifdef PIC |
98ad631c L |
368 | # define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ |
369 | LOADREGS_##nr(args) \ | |
370 | asm volatile ( \ | |
371 | "call *%%gs:%P2" \ | |
372 | : "=a" (resultvar) \ | |
373 | : "a" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \ | |
374 | ASMARGS_##nr(args) : "memory", "cc") | |
375 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ | |
376 | ({ \ | |
377 | register unsigned int resultvar; \ | |
378 | LOADREGS_##nr(args) \ | |
379 | asm volatile ( \ | |
380 | "call *%%gs:%P2" \ | |
381 | : "=a" (resultvar) \ | |
382 | : "a" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ | |
383 | ASMARGS_##nr(args) : "memory", "cc"); \ | |
384 | (int) resultvar; }) | |
385 | # else | |
386 | # define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ | |
387 | LOADREGS_##nr(args) \ | |
388 | asm volatile ( \ | |
389 | "call *_dl_sysinfo" \ | |
390 | : "=a" (resultvar) \ | |
391 | : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc") | |
392 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ | |
393 | ({ \ | |
394 | register unsigned int resultvar; \ | |
395 | LOADREGS_##nr(args) \ | |
396 | asm volatile ( \ | |
397 | "call *_dl_sysinfo" \ | |
398 | : "=a" (resultvar) \ | |
399 | : "a" (name) ASMARGS_##nr(args) : "memory", "cc"); \ | |
400 | (int) resultvar; }) | |
401 | # endif | |
402 | # else /* GCC 5 */ | |
627c69c8 | 403 | # ifdef PIC |
98ad631c | 404 | # define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ |
7a114794 | 405 | EXTRAVAR_##nr \ |
5f5843e3 UD |
406 | asm volatile ( \ |
407 | LOADARGS_##nr \ | |
408 | "movl %1, %%eax\n\t" \ | |
409 | "call *%%gs:%P2\n\t" \ | |
410 | RESTOREARGS_##nr \ | |
411 | : "=a" (resultvar) \ | |
412 | : "i" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \ | |
a9fe4c5a | 413 | ASMFMT_##nr(args) : "memory", "cc") |
98ad631c | 414 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ |
2edb61e3 UD |
415 | ({ \ |
416 | register unsigned int resultvar; \ | |
417 | EXTRAVAR_##nr \ | |
418 | asm volatile ( \ | |
419 | LOADARGS_##nr \ | |
420 | "call *%%gs:%P2\n\t" \ | |
421 | RESTOREARGS_##nr \ | |
422 | : "=a" (resultvar) \ | |
423 | : "0" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ | |
424 | ASMFMT_##nr(args) : "memory", "cc"); \ | |
425 | (int) resultvar; }) | |
98ad631c L |
426 | # else |
427 | # define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ | |
7a114794 | 428 | EXTRAVAR_##nr \ |
adcb550c | 429 | asm volatile ( \ |
44129238 | 430 | LOADARGS_##nr \ |
78e5779b | 431 | "movl %1, %%eax\n\t" \ |
5f5843e3 | 432 | "call *_dl_sysinfo\n\t" \ |
44129238 | 433 | RESTOREARGS_##nr \ |
adcb550c | 434 | : "=a" (resultvar) \ |
a9fe4c5a | 435 | : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc") |
98ad631c | 436 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ |
2edb61e3 UD |
437 | ({ \ |
438 | register unsigned int resultvar; \ | |
439 | EXTRAVAR_##nr \ | |
440 | asm volatile ( \ | |
441 | LOADARGS_##nr \ | |
442 | "call *_dl_sysinfo\n\t" \ | |
443 | RESTOREARGS_##nr \ | |
444 | : "=a" (resultvar) \ | |
445 | : "0" (name) ASMFMT_##nr(args) : "memory", "cc"); \ | |
446 | (int) resultvar; }) | |
98ad631c L |
447 | # endif |
448 | # endif /* GCC 5 */ | |
5f5843e3 | 449 | #else |
23c4baa2 | 450 | # ifdef OPTIMIZE_FOR_GCC_5 |
98ad631c L |
451 | # define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ |
452 | LOADREGS_##nr(args) \ | |
453 | asm volatile ( \ | |
454 | "int $0x80" \ | |
455 | : "=a" (resultvar) \ | |
456 | : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc") | |
457 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ | |
458 | ({ \ | |
459 | register unsigned int resultvar; \ | |
460 | LOADREGS_##nr(args) \ | |
461 | asm volatile ( \ | |
462 | "int $0x80" \ | |
463 | : "=a" (resultvar) \ | |
464 | : "a" (name) ASMARGS_##nr(args) : "memory", "cc"); \ | |
465 | (int) resultvar; }) | |
466 | # else /* GCC 5 */ | |
467 | # define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ | |
7a114794 | 468 | EXTRAVAR_##nr \ |
5f5843e3 UD |
469 | asm volatile ( \ |
470 | LOADARGS_##nr \ | |
471 | "movl %1, %%eax\n\t" \ | |
7a114794 | 472 | "int $0x80\n\t" \ |
5f5843e3 UD |
473 | RESTOREARGS_##nr \ |
474 | : "=a" (resultvar) \ | |
a9fe4c5a | 475 | : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc") |
98ad631c | 476 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ |
2edb61e3 UD |
477 | ({ \ |
478 | register unsigned int resultvar; \ | |
479 | EXTRAVAR_##nr \ | |
480 | asm volatile ( \ | |
481 | LOADARGS_##nr \ | |
482 | "int $0x80\n\t" \ | |
483 | RESTOREARGS_##nr \ | |
484 | : "=a" (resultvar) \ | |
485 | : "0" (name) ASMFMT_##nr(args) : "memory", "cc"); \ | |
486 | (int) resultvar; }) | |
98ad631c | 487 | # endif /* GCC 5 */ |
5f5843e3 | 488 | #endif |
adcb550c | 489 | |
6aca81bb UD |
490 | #undef INTERNAL_SYSCALL_DECL |
491 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
492 | ||
f4447671 | 493 | #undef INTERNAL_SYSCALL_ERROR_P |
6aca81bb UD |
494 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ |
495 | ((unsigned int) (val) >= 0xfffff001u) | |
f4447671 UD |
496 | |
497 | #undef INTERNAL_SYSCALL_ERRNO | |
6aca81bb | 498 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) |
f4447671 | 499 | |
44129238 | 500 | #define LOADARGS_0 |
7a114794 | 501 | #ifdef __PIC__ |
627c69c8 | 502 | # if I386_USE_SYSENTER && defined PIC |
7a114794 UD |
503 | # define LOADARGS_1 \ |
504 | "bpushl .L__X'%k3, %k3\n\t" | |
505 | # define LOADARGS_5 \ | |
506 | "movl %%ebx, %4\n\t" \ | |
507 | "movl %3, %%ebx\n\t" | |
508 | # else | |
509 | # define LOADARGS_1 \ | |
510 | "bpushl .L__X'%k2, %k2\n\t" | |
511 | # define LOADARGS_5 \ | |
512 | "movl %%ebx, %3\n\t" \ | |
513 | "movl %2, %%ebx\n\t" | |
514 | # endif | |
515 | # define LOADARGS_2 LOADARGS_1 | |
516 | # define LOADARGS_3 \ | |
517 | "xchgl %%ebx, %%edi\n\t" | |
518 | # define LOADARGS_4 LOADARGS_3 | |
5f5843e3 | 519 | #else |
7a114794 UD |
520 | # define LOADARGS_1 |
521 | # define LOADARGS_2 | |
522 | # define LOADARGS_3 | |
523 | # define LOADARGS_4 | |
524 | # define LOADARGS_5 | |
5f5843e3 | 525 | #endif |
44129238 UD |
526 | |
527 | #define RESTOREARGS_0 | |
7a114794 | 528 | #ifdef __PIC__ |
627c69c8 | 529 | # if I386_USE_SYSENTER && defined PIC |
7a114794 | 530 | # define RESTOREARGS_1 \ |
5f5843e3 | 531 | "bpopl .L__X'%k3, %k3\n\t" |
7a114794 UD |
532 | # define RESTOREARGS_5 \ |
533 | "movl %4, %%ebx" | |
534 | # else | |
535 | # define RESTOREARGS_1 \ | |
44129238 | 536 | "bpopl .L__X'%k2, %k2\n\t" |
7a114794 UD |
537 | # define RESTOREARGS_5 \ |
538 | "movl %3, %%ebx" | |
539 | # endif | |
540 | # define RESTOREARGS_2 RESTOREARGS_1 | |
541 | # define RESTOREARGS_3 \ | |
542 | "xchgl %%edi, %%ebx\n\t" | |
543 | # define RESTOREARGS_4 RESTOREARGS_3 | |
544 | #else | |
545 | # define RESTOREARGS_1 | |
546 | # define RESTOREARGS_2 | |
547 | # define RESTOREARGS_3 | |
548 | # define RESTOREARGS_4 | |
549 | # define RESTOREARGS_5 | |
5f5843e3 | 550 | #endif |
44129238 | 551 | |
23c4baa2 | 552 | #ifdef OPTIMIZE_FOR_GCC_5 |
98ad631c L |
553 | # define LOADREGS_0() |
554 | # define ASMARGS_0() | |
555 | # define LOADREGS_1(arg1) \ | |
556 | LOADREGS_0 () | |
557 | # define ASMARGS_1(arg1) \ | |
558 | ASMARGS_0 (), "b" ((unsigned int) (arg1)) | |
559 | # define LOADREGS_2(arg1, arg2) \ | |
560 | LOADREGS_1 (arg1) | |
561 | # define ASMARGS_2(arg1, arg2) \ | |
562 | ASMARGS_1 (arg1), "c" ((unsigned int) (arg2)) | |
563 | # define LOADREGS_3(arg1, arg2, arg3) \ | |
564 | LOADREGS_2 (arg1, arg2) | |
565 | # define ASMARGS_3(arg1, arg2, arg3) \ | |
566 | ASMARGS_2 (arg1, arg2), "d" ((unsigned int) (arg3)) | |
567 | # define LOADREGS_4(arg1, arg2, arg3, arg4) \ | |
568 | LOADREGS_3 (arg1, arg2, arg3) | |
569 | # define ASMARGS_4(arg1, arg2, arg3, arg4) \ | |
570 | ASMARGS_3 (arg1, arg2, arg3), "S" ((unsigned int) (arg4)) | |
571 | # define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \ | |
572 | LOADREGS_4 (arg1, arg2, arg3, arg4) | |
573 | # define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \ | |
574 | ASMARGS_4 (arg1, arg2, arg3, arg4), "D" ((unsigned int) (arg5)) | |
575 | # define LOADREGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ | |
576 | register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \ | |
577 | LOADREGS_5 (arg1, arg2, arg3, arg4, arg5) | |
578 | # define ASMARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ | |
579 | ASMARGS_5 (arg1, arg2, arg3, arg4, arg5), "r" (_a6) | |
580 | #endif /* GCC 5 */ | |
581 | ||
7bb38c70 | 582 | #define ASMFMT_0() |
7a114794 UD |
583 | #ifdef __PIC__ |
584 | # define ASMFMT_1(arg1) \ | |
585 | , "cd" (arg1) | |
586 | # define ASMFMT_2(arg1, arg2) \ | |
3a370de8 | 587 | , "d" (arg1), "c" (arg2) |
7a114794 UD |
588 | # define ASMFMT_3(arg1, arg2, arg3) \ |
589 | , "D" (arg1), "c" (arg2), "d" (arg3) | |
590 | # define ASMFMT_4(arg1, arg2, arg3, arg4) \ | |
591 | , "D" (arg1), "c" (arg2), "d" (arg3), "S" (arg4) | |
592 | # define ASMFMT_5(arg1, arg2, arg3, arg4, arg5) \ | |
593 | , "0" (arg1), "m" (_xv), "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5) | |
594 | #else | |
595 | # define ASMFMT_1(arg1) \ | |
596 | , "b" (arg1) | |
597 | # define ASMFMT_2(arg1, arg2) \ | |
598 | , "b" (arg1), "c" (arg2) | |
599 | # define ASMFMT_3(arg1, arg2, arg3) \ | |
600 | , "b" (arg1), "c" (arg2), "d" (arg3) | |
601 | # define ASMFMT_4(arg1, arg2, arg3, arg4) \ | |
602 | , "b" (arg1), "c" (arg2), "d" (arg3), "S" (arg4) | |
603 | # define ASMFMT_5(arg1, arg2, arg3, arg4, arg5) \ | |
604 | , "b" (arg1), "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5) | |
605 | #endif | |
606 | ||
607 | #define EXTRAVAR_0 | |
608 | #define EXTRAVAR_1 | |
609 | #define EXTRAVAR_2 | |
610 | #define EXTRAVAR_3 | |
611 | #define EXTRAVAR_4 | |
612 | #ifdef __PIC__ | |
613 | # define EXTRAVAR_5 int _xv; | |
614 | #else | |
615 | # define EXTRAVAR_5 | |
616 | #endif | |
adcb550c | 617 | |
dbfc1e02 | 618 | /* Consistency check for position-independent code. */ |
23c4baa2 | 619 | #if defined __PIC__ && !defined OPTIMIZE_FOR_GCC_5 |
dbfc1e02 UD |
620 | # define check_consistency() \ |
621 | ({ int __res; \ | |
622 | __asm__ __volatile__ \ | |
d8e0ca50 | 623 | (LOAD_PIC_REG_STR (cx) ";" \ |
dbfc1e02 UD |
624 | "subl %%ebx, %%ecx;" \ |
625 | "je 1f;" \ | |
626 | "ud2;" \ | |
627 | "1:\n" \ | |
dbfc1e02 UD |
628 | : "=c" (__res)); \ |
629 | __res; }) | |
630 | #endif | |
631 | ||
66715f83 | 632 | #endif /* __ASSEMBLER__ */ |
ec4b0518 | 633 | |
827b7087 UD |
634 | |
635 | /* Pointer mangling support. */ | |
a3848485 | 636 | #if IS_IN (rtld) |
827b7087 UD |
637 | /* We cannot use the thread descriptor because in ld.so we use setjmp |
638 | earlier than the descriptor is initialized. Using a global variable | |
639 | is too complicated here since we have no PC-relative addressing mode. */ | |
640 | #else | |
3467f5c3 | 641 | # ifdef __ASSEMBLER__ |
4a44ce79 UD |
642 | # define PTR_MANGLE(reg) xorl %gs:POINTER_GUARD, reg; \ |
643 | roll $9, reg | |
644 | # define PTR_DEMANGLE(reg) rorl $9, reg; \ | |
645 | xorl %gs:POINTER_GUARD, reg | |
3467f5c3 | 646 | # else |
4a44ce79 UD |
647 | # define PTR_MANGLE(var) asm ("xorl %%gs:%c2, %0\n" \ |
648 | "roll $9, %0" \ | |
649 | : "=r" (var) \ | |
650 | : "0" (var), \ | |
651 | "i" (offsetof (tcbhead_t, \ | |
652 | pointer_guard))) | |
653 | # define PTR_DEMANGLE(var) asm ("rorl $9, %0\n" \ | |
654 | "xorl %%gs:%c2, %0" \ | |
3467f5c3 UD |
655 | : "=r" (var) \ |
656 | : "0" (var), \ | |
657 | "i" (offsetof (tcbhead_t, \ | |
658 | pointer_guard))) | |
3467f5c3 | 659 | # endif |
827b7087 UD |
660 | #endif |
661 | ||
ec4b0518 | 662 | #endif /* linux/i386/sysdep.h */ |