]>
Commit | Line | Data |
---|---|---|
ae828bc6 | 1 | /* Copyright (C) 1992, 93, 95, 96, 97, 98 Free Software Foundation, Inc. |
bfbc5754 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
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 | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
d2f5be2a | 19 | |
ec4b0518 UD |
20 | #ifndef _LINUX_I386_SYSDEP_H |
21 | #define _LINUX_I386_SYSDEP_H 1 | |
22 | ||
d2f5be2a UD |
23 | /* There is some commonality. */ |
24 | #include <sysdeps/unix/i386/sysdep.h> | |
25 | ||
26 | /* For Linux we can use the system call table in the header file | |
27 | /usr/include/asm/unistd.h | |
28 | of the kernel. But these symbols do not follow the SYS_* syntax | |
29 | so we have to redefine the `SYS_ify' macro here. */ | |
30 | #undef SYS_ify | |
6ed0492f | 31 | #define SYS_ify(syscall_name) __NR_##syscall_name |
d2f5be2a | 32 | |
8fb3e007 UD |
33 | /* ELF-like local names start with `.L'. */ |
34 | #undef L | |
35 | #define L(name) .L##name | |
d2f5be2a | 36 | |
66715f83 | 37 | #ifdef __ASSEMBLER__ |
d2f5be2a | 38 | |
cccda09f UD |
39 | /* Linux uses a negative return value to indicate syscall errors, |
40 | unlike most Unices, which use the condition codes' carry flag. | |
41 | ||
42 | Since version 2.1 the return value of a system call might be | |
43 | negative even if the call succeeded. E.g., the `lseek' system call | |
44 | might return a large offset. Therefore we must not anymore test | |
45 | for < 0, but test for a real error by making sure the value in %eax | |
b5791037 UD |
46 | is a real error number. Linus said he will make sure the no syscall |
47 | returns a value in -1 .. -4095 as a valid result so we can savely | |
48 | test with -4095. */ | |
c0fb8a56 UD |
49 | |
50 | /* We don't want the label for the error handle to be global when we define | |
51 | it here. */ | |
52 | #ifdef PIC | |
53 | # define SYSCALL_ERROR_LABEL 0f | |
54 | #else | |
55 | # define SYSCALL_ERROR_LABEL syscall_error | |
56 | #endif | |
57 | ||
d2f5be2a UD |
58 | #undef PSEUDO |
59 | #define PSEUDO(name, syscall_name, args) \ | |
60 | .text; \ | |
d2f5be2a | 61 | ENTRY (name) \ |
c14e4c32 | 62 | DO_CALL (args, syscall_name); \ |
b5791037 | 63 | cmpl $-4095, %eax; \ |
c0fb8a56 | 64 | jae SYSCALL_ERROR_LABEL; \ |
ae828bc6 | 65 | L(pseudo_end): |
d2f5be2a | 66 | |
6ed0492f UD |
67 | #undef PSEUDO_END |
68 | #define PSEUDO_END(name) \ | |
69 | SYSCALL_ERROR_HANDLER \ | |
70 | END (name) | |
71 | ||
edf5b2d7 | 72 | #ifndef PIC |
03a75825 RM |
73 | #define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ |
74 | #else | |
75 | /* Store (- %eax) into errno through the GOT. */ | |
edf5b2d7 | 76 | #ifdef _LIBC_REENTRANT |
03a75825 | 77 | #define SYSCALL_ERROR_HANDLER \ |
c0fb8a56 UD |
78 | 0:pushl %ebx; \ |
79 | call 1f; \ | |
80 | 1:popl %ebx; \ | |
edf5b2d7 | 81 | xorl %edx, %edx; \ |
c0fb8a56 | 82 | addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx; \ |
edf5b2d7 | 83 | subl %eax, %edx; \ |
edf5b2d7 UD |
84 | pushl %edx; \ |
85 | call __errno_location@PLT; \ | |
86 | popl %ecx; \ | |
87 | popl %ebx; \ | |
88 | movl %ecx, (%eax); \ | |
89 | movl $-1, %eax; \ | |
c0fb8a56 | 90 | jmp L(pseudo_end); |
c4029823 | 91 | /* A quick note: it is assumed that the call to `__errno_location' does |
cccda09f | 92 | not modify the stack! */ |
edf5b2d7 UD |
93 | #else |
94 | #define SYSCALL_ERROR_HANDLER \ | |
c0fb8a56 UD |
95 | 0:call 1f; \ |
96 | 1:popl %ecx; \ | |
edf5b2d7 | 97 | xorl %edx, %edx; \ |
c0fb8a56 | 98 | addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx; \ |
edf5b2d7 | 99 | subl %eax, %edx; \ |
03a75825 | 100 | movl errno@GOT(%ecx), %ecx; \ |
edf5b2d7 | 101 | movl %edx, (%ecx); \ |
03a75825 | 102 | movl $-1, %eax; \ |
c0fb8a56 | 103 | jmp L(pseudo_end); |
edf5b2d7 UD |
104 | #endif /* _LIBC_REENTRANT */ |
105 | #endif /* PIC */ | |
03a75825 | 106 | |
d2f5be2a UD |
107 | /* Linux takes system call arguments in registers: |
108 | ||
109 | syscall number %eax call-clobbered | |
110 | arg 1 %ebx call-saved | |
111 | arg 2 %ecx call-clobbered | |
112 | arg 3 %edx call-clobbered | |
113 | arg 4 %esi call-saved | |
114 | arg 5 %edi call-saved | |
115 | ||
116 | The stack layout upon entering the function is: | |
117 | ||
118 | 20(%esp) Arg# 5 | |
119 | 16(%esp) Arg# 4 | |
120 | 12(%esp) Arg# 3 | |
121 | 8(%esp) Arg# 2 | |
122 | 4(%esp) Arg# 1 | |
123 | (%esp) Return address | |
124 | ||
125 | (Of course a function with say 3 arguments does not have entries for | |
126 | arguments 4 and 5.) | |
127 | ||
6ed0492f | 128 | The following code tries hard to be optimal. A general assumption |
03a75825 | 129 | (which is true according to the data books I have) is that |
d2f5be2a UD |
130 | |
131 | 2 * xchg is more expensive than pushl + movl + popl | |
132 | ||
133 | Beside this a neat trick is used. The calling conventions for Linux | |
134 | tell that among the registers used for parameters %ecx and %edx need | |
135 | not be saved. Beside this we may clobber this registers even when | |
136 | they are not used for parameter passing. | |
137 | ||
138 | As a result one can see below that we save the content of the %ebx | |
139 | register in the %edx register when we have less than 3 arguments | |
140 | (2 * movl is less expensive than pushl + popl). | |
141 | ||
142 | Second unlike for the other registers we don't save the content of | |
6ed0492f | 143 | %ecx and %edx when we have more than 1 and 2 registers resp. |
8f5ca04b RM |
144 | |
145 | The code below might look a bit long but we have to take care for | |
63bda0c1 | 146 | the pipelined processors (i586). Here the `pushl' and `popl' |
8f5ca04b RM |
147 | instructions are marked as NP (not pairable) but the exception is |
148 | two consecutive of these instruction. This gives no penalty on | |
63bda0c1 | 149 | other processors though. */ |
d2f5be2a UD |
150 | |
151 | #undef DO_CALL | |
c14e4c32 | 152 | #define DO_CALL(args, syscall_name) \ |
8f5ca04b | 153 | PUSHARGS_##args \ |
d2f5be2a | 154 | DOARGS_##args \ |
c14e4c32 | 155 | movl $SYS_ify (syscall_name), %eax; \ |
8f5ca04b RM |
156 | int $0x80 \ |
157 | POPARGS_##args | |
d2f5be2a | 158 | |
8f5ca04b | 159 | #define PUSHARGS_0 /* No arguments to push. */ |
d2f5be2a | 160 | #define DOARGS_0 /* No arguments to frob. */ |
8f5ca04b RM |
161 | #define POPARGS_0 /* No arguments to pop. */ |
162 | #define _PUSHARGS_0 /* No arguments to push. */ | |
163 | #define _DOARGS_0(n) /* No arguments to frob. */ | |
164 | #define _POPARGS_0 /* No arguments to pop. */ | |
165 | ||
166 | #define PUSHARGS_1 movl %ebx, %edx; PUSHARGS_0 | |
167 | #define DOARGS_1 _DOARGS_1 (4) | |
168 | #define POPARGS_1 POPARGS_0; movl %edx, %ebx | |
169 | #define _PUSHARGS_1 pushl %ebx; _PUSHARGS_0 | |
170 | #define _DOARGS_1(n) movl n(%esp), %ebx; _DOARGS_0(n-4) | |
171 | #define _POPARGS_1 _POPARGS_0; popl %ebx | |
172 | ||
173 | #define PUSHARGS_2 PUSHARGS_1 | |
174 | #define DOARGS_2 _DOARGS_2 (8) | |
175 | #define POPARGS_2 POPARGS_1 | |
176 | #define _PUSHARGS_2 _PUSHARGS_1 | |
d2f5be2a | 177 | #define _DOARGS_2(n) movl n(%esp), %ecx; _DOARGS_1 (n-4) |
8f5ca04b | 178 | #define _POPARGS_2 _POPARGS_1 |
d2f5be2a | 179 | |
8f5ca04b RM |
180 | #define PUSHARGS_3 _PUSHARGS_2 |
181 | #define DOARGS_3 _DOARGS_3 (16) | |
182 | #define POPARGS_3 _POPARGS_3 | |
183 | #define _PUSHARGS_3 _PUSHARGS_2 | |
d2f5be2a | 184 | #define _DOARGS_3(n) movl n(%esp), %edx; _DOARGS_2 (n-4) |
8f5ca04b RM |
185 | #define _POPARGS_3 _POPARGS_2 |
186 | ||
187 | #define PUSHARGS_4 _PUSHARGS_4 | |
188 | #define DOARGS_4 _DOARGS_4 (24) | |
189 | #define POPARGS_4 _POPARGS_4 | |
190 | #define _PUSHARGS_4 pushl %esi; _PUSHARGS_3 | |
191 | #define _DOARGS_4(n) movl n(%esp), %esi; _DOARGS_3 (n-4) | |
192 | #define _POPARGS_4 _POPARGS_3; popl %esi | |
193 | ||
194 | #define PUSHARGS_5 _PUSHARGS_5 | |
195 | #define DOARGS_5 _DOARGS_5 (32) | |
196 | #define POPARGS_5 _POPARGS_5 | |
197 | #define _PUSHARGS_5 pushl %edi; _PUSHARGS_4 | |
198 | #define _DOARGS_5(n) movl n(%esp), %edi; _DOARGS_4 (n-4) | |
199 | #define _POPARGS_5 _POPARGS_4; popl %edi | |
d2f5be2a | 200 | |
66715f83 | 201 | #endif /* __ASSEMBLER__ */ |
ec4b0518 UD |
202 | |
203 | #endif /* linux/i386/sysdep.h */ |