blob: b06d392a2357ce12a98cf83062182b74fdf5526c [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/* Copyright (C) 1992,1993,1995-2000,2002-2006,2007
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
20
21#ifndef _LINUX_I386_SYSDEP_H
22#define _LINUX_I386_SYSDEP_H 1
23
24#include <sys/syscall.h>
25#include <common/sysdep.h>
26
27#ifdef __ASSEMBLER__
28
29/* Syntactic details of assembler. */
30
31/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */
32#define ALIGNARG(log2) 1<<log2
33/* For ELF we need the `.type' directive to make shared libs work right. */
34#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
35#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
36
37/* In ELF C symbols are asm symbols. */
38#undef NO_UNDERSCORES
39#define NO_UNDERSCORES
40
41/* Define an entry point visible from C.
42
43 There is currently a bug in gdb which prevents us from specifying
44 incomplete stabs information. Fake some entries here which specify
45 the current source file. */
46#define ENTRY(name) \
47 STABS_CURRENT_FILE1("") \
48 STABS_CURRENT_FILE(name) \
49 ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
50 ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
51 .align ALIGNARG(4); \
52 STABS_FUN(name) \
53 C_LABEL(name) \
54 cfi_startproc; \
55 CALL_MCOUNT
56
57#undef END
58#define END(name) \
59 cfi_endproc; \
60 ASM_SIZE_DIRECTIVE(name) \
61 STABS_FUN_END(name)
62
63#ifdef HAVE_CPP_ASM_DEBUGINFO
64/* Disable that goop, because we just pass -g through to the assembler
65 and it generates proper line number information directly. */
66# define STABS_CURRENT_FILE1(name)
67# define STABS_CURRENT_FILE(name)
68# define STABS_FUN(name)
69# define STABS_FUN_END(name)
70#else
71/* Remove the following two lines once the gdb bug is fixed. */
72#define STABS_CURRENT_FILE(name) \
73 STABS_CURRENT_FILE1 (#name)
74#define STABS_CURRENT_FILE1(name) \
75 1: .stabs name,100,0,0,1b;
76/* Emit stabs definition lines. We use F(0,1) and define t(0,1) as `int',
77 the same way gcc does it. */
78#define STABS_FUN(name) STABS_FUN2(name, name##:F(0,1))
79#define STABS_FUN2(name, namestr) \
80 .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0; \
81 .stabs #namestr,36,0,0,name;
82#define STABS_FUN_END(name) \
83 1: .stabs "",36,0,0,1b-name;
84#endif
85
86/* If compiled for profiling, call `mcount' at the start of each function. */
87#ifdef PROF
88/* The mcount code relies on a normal frame pointer being on the stack
89 to locate our caller, so push one just for its benefit. */
90#define CALL_MCOUNT \
91 pushl %ebp; cfi_adjust_cfa_offset (4); movl %esp, %ebp; \
92 cfi_def_cfa_register (ebp); call JUMPTARGET(mcount); \
93 popl %ebp; cfi_def_cfa (esp, 4);
94#else
95#define CALL_MCOUNT /* Do nothing. */
96#endif
97
98#ifdef NO_UNDERSCORES
99/* Since C identifiers are not normally prefixed with an underscore
100 on this system, the asm identifier `syscall_error' intrudes on the
101 C name space. Make sure we use an innocuous name. */
102#define syscall_error __syscall_error
103#define mcount _mcount
104#endif
105
106#undef JUMPTARGET
107#ifdef __PIC__
108#define JUMPTARGET(name) name##@PLT
109#define SYSCALL_PIC_SETUP \
110 pushl %ebx; \
111 cfi_adjust_cfa_offset (4); \
112 call 0f; \
1130: popl %ebx; \
114 cfi_adjust_cfa_offset (-4); \
115 addl $_GLOBAL_OFFSET_TABLE+[.-0b], %ebx;
116
117
118# define SETUP_PIC_REG(reg) \
119 .ifndef __x86.get_pc_thunk.reg; \
120 .section .gnu.linkonce.t.__x86.get_pc_thunk.reg,"ax",@progbits; \
121 .globl __x86.get_pc_thunk.reg; \
122 .hidden __x86.get_pc_thunk.reg; \
123 .type __x86.get_pc_thunk.reg,@function; \
124__x86.get_pc_thunk.reg: \
125 movl (%esp), %e##reg; \
126 ret; \
127 .size __x86.get_pc_thunk.reg, . - __x86.get_pc_thunk.reg; \
128 .previous; \
129 .endif; \
130 call __x86.get_pc_thunk.reg
131
132# define LOAD_PIC_REG(reg) \
133 SETUP_PIC_REG(reg); addl $_GLOBAL_OFFSET_TABLE_, %e##reg
134
135#else
136#define JUMPTARGET(name) name
137#define SYSCALL_PIC_SETUP /* Nothing. */
138#endif
139
140/* Local label name for asm code. */
141#ifndef L
142#ifdef HAVE_ELF
143#define L(name) .L##name
144#else
145#define L(name) name
146#endif
147#endif
148
149/* Avoid conflics with thunk section */
150#undef __i686
151#endif /* __ASSEMBLER__ */
152
153#ifndef offsetof
154# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
155#endif
156
157/* For Linux we can use the system call table in the header file
158 /usr/include/asm/unistd.h
159 of the kernel. But these symbols do not follow the SYS_* syntax
160 so we have to redefine the `SYS_ify' macro here. */
161#undef SYS_ify
162#define SYS_ify(syscall_name) __NR_##syscall_name
163
164#if defined USE_DL_SYSINFO \
165 && (!defined NOT_IN_libc || defined IS_IN_libpthread)
166# define I386_USE_SYSENTER 1
167#else
168# undef I386_USE_SYSENTER
169#endif
170
171#ifdef __ASSEMBLER__
172
173/* Linux uses a negative return value to indicate syscall errors,
174 unlike most Unices, which use the condition codes' carry flag.
175
176 Since version 2.1 the return value of a system call might be
177 negative even if the call succeeded. E.g., the `lseek' system call
178 might return a large offset. Therefore we must not anymore test
179 for < 0, but test for a real error by making sure the value in %eax
180 is a real error number. Linus said he will make sure the no syscall
181 returns a value in -1 .. -4095 as a valid result so we can savely
182 test with -4095. */
183
184/* We don't want the label for the error handle to be global when we define
185 it here. */
186#ifdef __PIC__
187# define SYSCALL_ERROR_LABEL 0f
188#else
189# define SYSCALL_ERROR_LABEL syscall_error
190#endif
191
192#undef PSEUDO
193#define PSEUDO(name, syscall_name, args) \
194 .text; \
195 ENTRY (name) \
196 DO_CALL (syscall_name, args); \
197 cmpl $-4095, %eax; \
198 jae SYSCALL_ERROR_LABEL; \
199 L(pseudo_end):
200
201#undef PSEUDO_END
202#define PSEUDO_END(name) \
203 SYSCALL_ERROR_HANDLER \
204 END (name)
205
206#undef PSEUDO_NOERRNO
207#define PSEUDO_NOERRNO(name, syscall_name, args) \
208 .text; \
209 ENTRY (name) \
210 DO_CALL (syscall_name, args)
211
212#undef PSEUDO_END_NOERRNO
213#define PSEUDO_END_NOERRNO(name) \
214 END (name)
215
216#define ret_NOERRNO ret
217
218/* The function has to return the error code. */
219#undef PSEUDO_ERRVAL
220#define PSEUDO_ERRVAL(name, syscall_name, args) \
221 .text; \
222 ENTRY (name) \
223 DO_CALL (syscall_name, args); \
224 negl %eax
225
226#undef PSEUDO_END_ERRVAL
227#define PSEUDO_END_ERRVAL(name) \
228 END (name)
229
230#define ret_ERRVAL ret
231
232#ifndef __PIC__
233# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
234#else
235
236# ifdef RTLD_PRIVATE_ERRNO
237# define SYSCALL_ERROR_HANDLER \
2380:SETUP_PIC_REG(cx); \
239 addl $_GLOBAL_OFFSET_TABLE_, %ecx; \
240 xorl %edx, %edx; \
241 subl %eax, %edx; \
242 movl %edx, rtld_errno@GOTOFF(%ecx); \
243 orl $-1, %eax; \
244 jmp L(pseudo_end);
245
246# elif defined _LIBC_REENTRANT
247
248# if defined USE___THREAD
249# ifndef NOT_IN_libc
250# define SYSCALL_ERROR_ERRNO __libc_errno
251# else
252# define SYSCALL_ERROR_ERRNO errno
253# endif
254# define SYSCALL_ERROR_HANDLER \
2550:SETUP_PIC_REG (cx); \
256 addl $_GLOBAL_OFFSET_TABLE_, %ecx; \
257 movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx; \
258 xorl %edx, %edx; \
259 subl %eax, %edx; \
260 SYSCALL_ERROR_HANDLER_TLS_STORE (%edx, %ecx); \
261 orl $-1, %eax; \
262 jmp L(pseudo_end);
263# ifndef NO_TLS_DIRECT_SEG_REFS
264# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \
265 movl src, %gs:(destoff)
266# else
267# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \
268 addl %gs:0, destoff; \
269 movl src, (destoff)
270# endif
271# else
272# define SYSCALL_ERROR_HANDLER \
2730:pushl %ebx; \
274 cfi_adjust_cfa_offset (4); \
275 cfi_rel_offset (ebx, 0); \
276 SETUP_PIC_REG (bx); \
277 addl $_GLOBAL_OFFSET_TABLE_, %ebx; \
278 xorl %edx, %edx; \
279 subl %eax, %edx; \
280 pushl %edx; \
281 cfi_adjust_cfa_offset (4); \
282 call __errno_location@PLT; \
283 popl %ecx; \
284 cfi_adjust_cfa_offset (-4); \
285 popl %ebx; \
286 cfi_adjust_cfa_offset (-4); \
287 cfi_restore (ebx); \
288 movl %ecx, (%eax); \
289 orl $-1, %eax; \
290 jmp L(pseudo_end);
291/* A quick note: it is assumed that the call to `__errno_location' does
292 not modify the stack! */
293# endif
294# else
295/* Store (- %eax) into errno through the GOT. */
296# define SYSCALL_ERROR_HANDLER \
2970:SETUP_PIC_REG(cx); \
298 addl $_GLOBAL_OFFSET_TABLE_, %ecx; \
299 xorl %edx, %edx; \
300 subl %eax, %edx; \
301 movl errno@GOT(%ecx), %ecx; \
302 movl %edx, (%ecx); \
303 orl $-1, %eax; \
304 jmp L(pseudo_end);
305# endif /* _LIBC_REENTRANT */
306#endif /* __PIC__ */
307
308
309/* The original calling convention for system calls on Linux/i386 is
310 to use int $0x80. */
311#ifdef I386_USE_SYSENTER
312# ifdef SHARED
313# define ENTER_KERNEL call *%gs:SYSINFO_OFFSET
314# else
315# define ENTER_KERNEL call *_dl_sysinfo
316# endif
317#else
318# define ENTER_KERNEL int $0x80
319#endif
320
321/* Linux takes system call arguments in registers:
322
323 syscall number %eax call-clobbered
324 arg 1 %ebx call-saved
325 arg 2 %ecx call-clobbered
326 arg 3 %edx call-clobbered
327 arg 4 %esi call-saved
328 arg 5 %edi call-saved
329 arg 6 %ebp call-saved
330
331 The stack layout upon entering the function is:
332
333 24(%esp) Arg# 6
334 20(%esp) Arg# 5
335 16(%esp) Arg# 4
336 12(%esp) Arg# 3
337 8(%esp) Arg# 2
338 4(%esp) Arg# 1
339 (%esp) Return address
340
341 (Of course a function with say 3 arguments does not have entries for
342 arguments 4, 5, and 6.)
343
344 The following code tries hard to be optimal. A general assumption
345 (which is true according to the data books I have) is that
346
347 2 * xchg is more expensive than pushl + movl + popl
348
349 Beside this a neat trick is used. The calling conventions for Linux
350 tell that among the registers used for parameters %ecx and %edx need
351 not be saved. Beside this we may clobber this registers even when
352 they are not used for parameter passing.
353
354 As a result one can see below that we save the content of the %ebx
355 register in the %edx register when we have less than 3 arguments
356 (2 * movl is less expensive than pushl + popl).
357
358 Second unlike for the other registers we don't save the content of
359 %ecx and %edx when we have more than 1 and 2 registers resp.
360
361 The code below might look a bit long but we have to take care for
362 the pipelined processors (i586). Here the `pushl' and `popl'
363 instructions are marked as NP (not pairable) but the exception is
364 two consecutive of these instruction. This gives no penalty on
365 other processors though. */
366
367#undef DO_CALL
368#define DO_CALL(syscall_name, args) \
369 PUSHARGS_##args \
370 DOARGS_##args \
371 movl $SYS_ify (syscall_name), %eax; \
372 ENTER_KERNEL \
373 POPARGS_##args
374
375#define PUSHARGS_0 /* No arguments to push. */
376#define DOARGS_0 /* No arguments to frob. */
377#define POPARGS_0 /* No arguments to pop. */
378#define _PUSHARGS_0 /* No arguments to push. */
379#define _DOARGS_0(n) /* No arguments to frob. */
380#define _POPARGS_0 /* No arguments to pop. */
381
382#define PUSHARGS_1 movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0
383#define DOARGS_1 _DOARGS_1 (4)
384#define POPARGS_1 POPARGS_0; movl %edx, %ebx; L(RESTBX1):
385#define _PUSHARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \
386 cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0
387#define _DOARGS_1(n) movl n(%esp), %ebx; _DOARGS_0(n-4)
388#define _POPARGS_1 _POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \
389 cfi_restore (ebx); L(POPBX1):
390
391#define PUSHARGS_2 PUSHARGS_1
392#define DOARGS_2 _DOARGS_2 (8)
393#define POPARGS_2 POPARGS_1
394#define _PUSHARGS_2 _PUSHARGS_1
395#define _DOARGS_2(n) movl n(%esp), %ecx; _DOARGS_1 (n-4)
396#define _POPARGS_2 _POPARGS_1
397
398#define PUSHARGS_3 _PUSHARGS_2
399#define DOARGS_3 _DOARGS_3 (16)
400#define POPARGS_3 _POPARGS_3
401#define _PUSHARGS_3 _PUSHARGS_2
402#define _DOARGS_3(n) movl n(%esp), %edx; _DOARGS_2 (n-4)
403#define _POPARGS_3 _POPARGS_2
404
405#define PUSHARGS_4 _PUSHARGS_4
406#define DOARGS_4 _DOARGS_4 (24)
407#define POPARGS_4 _POPARGS_4
408#define _PUSHARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \
409 cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3
410#define _DOARGS_4(n) movl n(%esp), %esi; _DOARGS_3 (n-4)
411#define _POPARGS_4 _POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \
412 cfi_restore (esi); L(POPSI1):
413
414#define PUSHARGS_5 _PUSHARGS_5
415#define DOARGS_5 _DOARGS_5 (32)
416#define POPARGS_5 _POPARGS_5
417#define _PUSHARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \
418 cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4
419#define _DOARGS_5(n) movl n(%esp), %edi; _DOARGS_4 (n-4)
420#define _POPARGS_5 _POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \
421 cfi_restore (edi); L(POPDI1):
422
423#define PUSHARGS_6 _PUSHARGS_6
424#define DOARGS_6 _DOARGS_6 (40)
425#define POPARGS_6 _POPARGS_6
426#define _PUSHARGS_6 pushl %ebp; cfi_adjust_cfa_offset (4); \
427 cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5
428#define _DOARGS_6(n) movl n(%esp), %ebp; _DOARGS_5 (n-4)
429#define _POPARGS_6 _POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \
430 cfi_restore (ebp); L(POPBP1):
431
432#endif /* __ASSEMBLER__ */
433
434
435/* Pointer mangling support. */
436#if defined NOT_IN_libc && defined IS_IN_rtld
437/* We cannot use the thread descriptor because in ld.so we use setjmp
438 earlier than the descriptor is initialized. Using a global variable
439 is too complicated here since we have no PC-relative addressing mode. */
440#else
441# ifdef __ASSEMBLER__
442# define PTR_MANGLE(reg) xorl %gs:POINTER_GUARD, reg; \
443 roll $9, reg
444# define PTR_DEMANGLE(reg) rorl $9, reg; \
445 xorl %gs:POINTER_GUARD, reg
446# else
447# define PTR_MANGLE(var) __asm__ ("xorl %%gs:%c2, %0\n" \
448 "roll $9, %0" \
449 : "=r" (var) \
450 : "0" (var), \
451 "i" (offsetof (tcbhead_t, \
452 pointer_guard)))
453# define PTR_DEMANGLE(var) __asm__ ("rorl $9, %0\n" \
454 "xorl %%gs:%c2, %0" \
455 : "=r" (var) \
456 : "0" (var), \
457 "i" (offsetof (tcbhead_t, \
458 pointer_guard)))
459# endif
460#endif
461
462#endif /* linux/i386/sysdep.h */