Back to index

glibc  2.9
sysdep.h
Go to the documentation of this file.
00001 /* Copyright 2001, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Alexandre Oliva <aoliva@redhat.com>.
00004    Based on ../i386/sysdep.h.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public License as
00008    published by the Free Software Foundation; either version 2 of the
00009    License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public
00017    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00018    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.  */
00020 
00021 #ifndef _LINUX_AM33_SYSDEP_H
00022 #define _LINUX_AM33_SYSDEP_H 1
00023 
00024 /* There is some commonality.  */
00025 #include "../../../am33/sysdep.h"
00026 
00027 /* For Linux we can use the system call table in the header file
00028        /usr/include/asm/unistd.h
00029    of the kernel.  But these symbols do not follow the SYS_* syntax
00030    so we have to redefine the `SYS_ify' macro here.  */
00031 #undef SYS_ify
00032 #define SYS_ify(syscall_name)      __NR_##syscall_name
00033 
00034 /* ELF-like local names start with `.L'.  */
00035 #undef L
00036 #define L(name)      .L##name
00037 
00038 #ifdef __ASSEMBLER__
00039 
00040 /* Linux uses a negative return value to indicate syscall errors,
00041    unlike most Unices, which use the condition codes' carry flag.
00042 
00043    Since version 2.1 the return value of a system call might be
00044    negative even if the call succeeded.  E.g., the `lseek' system call
00045    might return a large offset.  Therefore we must not anymore test
00046    for < 0, but test for a real error by making sure the value in %eax
00047    is a real error number.  Linus said he will make sure the no syscall
00048    returns a value in -1 .. -4095 as a valid result so we can savely
00049    test with -4095.  */
00050 
00051 /* We don't want the label for the error handle to be global when we define
00052    it here.  */
00053 #ifdef PIC
00054 # define SYSCALL_ERROR_LABEL 0f
00055 #else
00056 # define SYSCALL_ERROR_LABEL syscall_error
00057 #endif
00058 
00059 #undef PSEUDO
00060 #define       PSEUDO(name, syscall_name, args)                              \
00061   .text;                                                             \
00062   ENTRY (name)                                                              \
00063     DO_CALL (syscall_name, args);                                    \
00064     cmp -126,d0;                                                     \
00065     bls L(pseudo_end);                                                      \
00066     jmp SYSCALL_ERROR_LABEL;                                                \
00067   L(pseudo_end):                                                     \
00068     mov d0,a0;
00069 
00070 #undef PSEUDO_END
00071 #define       PSEUDO_END(name)                                              \
00072   SYSCALL_ERROR_HANDLER                                                     \
00073   END (name)
00074 
00075 #undef  PSEUDO_NOERROR
00076 #define       PSEUDO_NOERRNO(name, syscall_name, args)                      \
00077   .text;                                                             \
00078   ENTRY (name)                                                              \
00079     DO_CALL (syscall_name, args)
00080 
00081 #undef PSEUDO_END_NOERRNO
00082 #define       PSEUDO_END_NOERRNO(name)                                      \
00083   END (name)
00084 
00085 #define ret_NOERRNO ret
00086 
00087 /* The function has to return the error code.  */
00088 #undef PSEUDO_ERRVAL
00089 #define       PSEUDO_ERRVAL(name, syscall_name, args) \
00090   .text;                                                             \
00091   ENTRY (name)                                                              \
00092     DO_CALL (syscall_name, args);                                    \
00093     clr d1;                                                          \
00094     sub d0,d1,d0
00095 
00096 #undef PSEUDO_END_ERRVAL
00097 #define       PSEUDO_END_ERRVAL(name) \
00098   END (name)
00099 
00100 #define ret_ERRVAL ret
00101 
00102 #ifndef PIC
00103 #define SYSCALL_ERROR_HANDLER      /* Nothing here; code in sysdep.S is used.  */
00104 #else
00105 /* Store (- d0) into errno through the GOT.  */
00106 #ifdef _LIBC_REENTRANT
00107 #define SYSCALL_ERROR_HANDLER                                               \
00108 0:movm [d2,a2],(sp);                                                 \
00109   add -12,sp;                                                        \
00110 1:mov pc,a2;                                                         \
00111   add _GLOBAL_OFFSET_TABLE_-(1b-.),a2;                                      \
00112   clr d2;                                                            \
00113   sub d0,d2;                                                         \
00114   call __errno_location@PLT,[],0;                                    \
00115   mov d2,(a0);                                                              \
00116   add 12,sp;                                                         \
00117   movm (sp),[d2,a2];                                                 \
00118   mov -1,d0;                                                         \
00119   mov d0,a0;                                                         \
00120   jmp L(pseudo_end);
00121 /* A quick note: it is assumed that the call to `__errno_location' does
00122    not modify the stack!  */
00123 #else
00124 #define SYSCALL_ERROR_HANDLER                                               \
00125 0:mov pc,a0;                                                         \
00126   add _GLOBAL_OFFSET_TABLE_-(0b-.),a0;                                      \
00127   clr d1;                                                            \
00128   sub d0,d1;                                                         \
00129   mov (errno@GOT,a0),a1;                                             \
00130   mov d1,(a0);                                                              \
00131   mov -1,d0;                                                         \
00132   mov d0,a0;                                                         \
00133   jmp L(pseudo_end);
00134 #endif /* _LIBC_REENTRANT */
00135 #endif /* PIC */
00136 
00137 /* Linux takes system call arguments in registers:
00138 
00139        syscall number       d0          call-clobbered
00140        arg 1         a0          call-clobbered
00141        arg 2         d1          call-clobbered
00142        arg 3         a3          call-saved
00143        arg 4         a2          call-saved
00144        arg 5         d3          call-saved
00145        arg 6         d2          call-saved
00146 
00147    The stack layout upon entering the function is:
00148 
00149         (24,sp)      Arg# 6
00150         (20,sp)      Arg# 5
00151         (16,sp)      Arg# 4
00152         (12,sp)      Arg# 3
00153          d1          Arg# 2
00154          d0          Arg# 1
00155          (sp)        Return address
00156 
00157    (Of course a function with say 3 arguments does not have entries for
00158    arguments 4, 5 and 6.)  */
00159 
00160 #undef DO_CALL
00161 #define DO_CALL(syscall_name, args)                                         \
00162     PUSHARGS_##args                                                  \
00163     DOARGS_##args                                                    \
00164     mov SYS_ify (syscall_name),d0;                                   \
00165     syscall 0                                                        \
00166     POPARGS_##args
00167 
00168 #define PUSHARGS_0   /* No arguments to push.  */
00169 #define       _DOARGS_0(N)  /* No arguments to frob.  */
00170 #define       DOARGS_0      /* No arguments to frob.  */
00171 #define       POPARGS_0     /* No arguments to pop.  */
00172 
00173 #define PUSHARGS_1   /* No arguments to push.  */
00174 #define       _DOARGS_1(N)  _DOARGS_0 (N-4) mov d0,a0;
00175 #define       DOARGS_1      _DOARGS_1 (4)
00176 #define       POPARGS_1     /* No arguments to pop.  */
00177 
00178 #define PUSHARGS_2   /* No arguments to push.  */
00179 #define       _DOARGS_2(N)  _DOARGS_1 (N-4) /* Argument already in d1.  */
00180 #define       DOARGS_2      _DOARGS_2 (8)
00181 #define       POPARGS_2     /* No arguments to pop.  */
00182 
00183 #define PUSHARGS_3   movm [a3],(sp);
00184 #define       _DOARGS_3(N)  _DOARGS_2 (N-4) mov (N,sp),a3;
00185 #define DOARGS_3     _DOARGS_3 (16)
00186 #define POPARGS_3    ; movm (sp),[a3]
00187 
00188 #define PUSHARGS_4   movm [a2,a3],(sp);
00189 #define       _DOARGS_4(N)  _DOARGS_3 (N-4) mov (N,sp),a2;
00190 #define DOARGS_4     _DOARGS_4 (24)
00191 #define POPARGS_4    ; movm (sp),[a2,a3]
00192 
00193 #define PUSHARGS_5   movm [d3,a2,a3],(sp);
00194 #define       _DOARGS_5(N)  _DOARGS_4 (N-4) mov (N,sp),d3;
00195 #define DOARGS_5     _DOARGS_5 (32)
00196 #define POPARGS_5    ; movm (sp),[d3,a2,a3]
00197 
00198 #define PUSHARGS_6   movm [d2,d3,a2,a3],(sp);
00199 #define       _DOARGS_6(N)  _DOARGS_5 (N-4) mov (N,sp),d2;
00200 #define DOARGS_6     _DOARGS_6 (40)
00201 #define POPARGS_6    ; movm (sp),[d2,d3,a2,a3]
00202 
00203 #else  /* !__ASSEMBLER__ */
00204 
00205 /* Define a macro which expands inline into the wrapper code for a system
00206    call.  */
00207 #undef INLINE_SYSCALL
00208 #define INLINE_SYSCALL(name, nr, args...) \
00209   ({                                                           \
00210     unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args);     \
00211     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0)) \
00212       {                                                               \
00213        __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, ));            \
00214        resultvar = 0xffffffff;                                        \
00215       }                                                               \
00216     (int) resultvar; })
00217 
00218 #define INTERNAL_SYSCALL(name, err, nr, args...)               \
00219 ({                                                             \
00220        register long __sc0 asm ("d0") = __NR_##name;                  \
00221        inline_syscall##nr(name, ## args);                      \
00222        __sc0;                                                  \
00223 })
00224 
00225 #undef INTERNAL_SYSCALL_DECL
00226 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
00227 
00228 #undef INTERNAL_SYSCALL_ERROR_P
00229 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
00230   ((unsigned int) (val) >= (unsigned long)-125)
00231 
00232 #undef INTERNAL_SYSCALL_ERRNO
00233 #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
00234 
00235 #define inline_syscall0(name,dummy...) \
00236 __asm__ __volatile__ ("syscall 0" \
00237                      : "+d" (__sc0) \
00238                      : : "memory")
00239 
00240 #define inline_syscall1(name,arg1) \
00241 register long __sc1 asm ("a0") = (long) (arg1); \
00242 inline_syscall0 (name); \
00243 __asm__ __volatile__ ("" : : "r" (__sc1))
00244 
00245 #define inline_syscall2(name,arg1,arg2) \
00246 register long __sc2 asm ("d1") = (long) (arg2); \
00247 inline_syscall1 (name,(arg1)); \
00248 __asm__ __volatile__ ("" : : "r" (__sc2))
00249 
00250 /* We can't tell whether a3 is going to be eliminated in the enclosing
00251    function, so we have to assume it isn't.  We first load the value
00252    of any arguments into their registers, except for a3 itself, that
00253    may be needed to load the value of the other arguments.  Then, we
00254    save a3's value in some other register, and load the argument value
00255    into a3.  We have to force both a3 and its copy to be live in
00256    different registers at the same time, to avoid having the copy
00257    spilled and the value reloaded into the same register, in which
00258    case we'd be unable to get the value of a3 back, should the stack
00259    slot reference be (offset,a3).  */
00260 #define inline_syscall3(name,arg1,arg2,arg3) \
00261 long __sc3v = (long) (arg3); \
00262 register long __sc1 asm ("a0") = (long) (arg1); \
00263 register long __sc2 asm ("d1") = (long) (arg2); \
00264 register long __sc3 asm ("a3") = __sc3;   \
00265 register long __sc3c; \
00266 __asm__ __volatile__ ("mov %1,%0" : "=&r" (__sc3c) : "r" (__sc3)); \
00267 __sc3 = __sc3v; \
00268 __asm__ __volatile__ ("" : : "r" (__sc3c), "r" (__sc3)); \
00269 inline_syscall0 (name); \
00270 __sc3 = __sc3c; \
00271 __asm__ __volatile__ ("" : : "r" (__sc3), "r" (__sc2), "r" (__sc1))
00272 
00273 #ifdef PIC
00274 /* Since a2 is the PIC register, it requires similar handling as a3
00275    when we're generating PIC, as a2's value may be needed to load
00276    arguments whose values live in global variables.  The difference is
00277    that we don't need to require its value to be live in a register;
00278    it may well be in a stack slot, as long as we save it before
00279    clobbering a3 and restore it after restoring a3.  */
00280 #define inline_syscall4(name,arg1,arg2,arg3,arg4) \
00281 long __sc4v = (long) (arg4); \
00282 long __sc3v = (long) (arg3); \
00283 register long __sc1 asm ("a0") = (long) (arg1); \
00284 register long __sc2 asm ("d1") = (long) (arg2); \
00285 register long __sc3 asm ("a3") = __sc3;   \
00286 register long __sc3c; \
00287 register long __sc4 asm ("a2") = __sc4;   \
00288 long __sc4c = __sc4; \
00289 __sc4 = __sc4v; \
00290 __asm__ __volatile__ ("mov %1,%0" : "=&r" (__sc3c) : "r" (__sc3)); \
00291 __sc3 = __sc3v; \
00292 __asm__ __volatile__ ("" : : "r" (__sc3c), "r" (__sc3), "r" (__sc4)); \
00293 inline_syscall0 (name); \
00294 __sc3 = __sc3c; \
00295 __sc4 = __sc4c; \
00296 __asm__ __volatile__ ("" : : "r" (__sc4), "r" (__sc3), \
00297                           "r" (__sc2), "r" (__sc1))
00298 #else
00299 #define inline_syscall4(name,arg1,arg2,arg3,arg4) \
00300 register long __sc4 asm ("a2") = (long) (arg4); \
00301 inline_syscall3 (name,(arg1),(arg2),(arg3)); \
00302 __asm__ __volatile__ ("" : : "r" (__sc4))
00303 #endif
00304 
00305 #define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5) \
00306 register long __sc5 asm ("d3") = (long) (arg5); \
00307 inline_syscall4 (name,(arg1),(arg2),(arg3),(arg4)); \
00308 __asm__ __volatile__ ("" : : "r" (__sc5))
00309 
00310 #define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
00311 register long __sc6 asm ("d2") = (long) (arg6); \
00312 inline_syscall5 (name,(arg1),(arg2),(arg3),(arg4),(arg5)); \
00313 __asm__ __volatile__ ("" : : "r" (__sc6))
00314 
00315 #endif /* __ASSEMBLER__ */
00316 
00317 #endif /* linux/am33/sysdep.h */