Fix sparc localplt testcase failures.
authorDavid S. Miller <davem@davemloft.net>
Thu, 1 Sep 2011 00:30:41 +0000 (17:30 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Sep 2011 00:30:41 +0000 (17:30 -0700)
ChangeLog
scripts/data/localplt-sparc-linux-gnu.data
scripts/data/localplt-sparc64-linux-gnu.data
sysdeps/unix/sparc/sysdep.h
sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h
sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h
sysdeps/unix/sysv/linux/sparc/sysdep.h

index 9cab80d77022b6ac27ca9ea664691172d012e099..cdf4bc09e2951c21c6e20140346c5a8b23a6d0fd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2011-08-31  David S. Miller  <davem@davemloft.net>
+
+       * sysdeps/unix/sparc/sysdep.h (SETUP_PIC_REG): Define.
+       * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h (PSEUDO):
+       Reimplement to do errno handling inline.
+       (SYSCALL_ERROR_HANDLER): New macro.
+       (__SYSCALL_STRING): Do not do errno handling in asm.
+       (__CLONE_SYSCALL_STRING): Delete.
+       (__INTERNAL_SYSCALL_STRING): Delete.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h: Include
+       sysdeps/unix/sparc/sysdep.h instead of sysdeps/unix/sysdep.h
+       (PSEUDO): Reimplement to do errno handling inline.
+       (ret, ret_NOERRNO, ret_ERRVAL, r0, r1, MOVE): Don't redefine.
+       (SYSCALL_ERROR_HANDLER): New macro.
+       (__SYSCALL_STRING): Do not do errno handling in asm.
+       (__CLONE_SYSCALL_STRING): Delete.
+       (__INTERNAL_SYSCALL_STRING): Delete.
+       * sysdeps/unix/sysv/linux/sparc/sysdep.h (INLINE_SYSCALL):
+       Implement in terms of INTERNAL_SYSCALL and __set_errno, just like
+       i386.
+       (INTERNAL_SYSCALL_DECL): Declare %g1 var for err state.
+       (inline_syscall*): Add 'err' argument.
+       (INTERNAL_SYSCALL, INTERNAL_SYSCALL_NCS,
+       INTERNAL_SYSCALL_ERROR_P): Likewise and pass it down.
+       (INLINE_CLONE_SYSCALL): Reimplement in terms of __SYSCALL_STRING,
+       INTERNAL_SYSCALL_ERRNO, and INTERNAL_SYSCALL_ERROR_P.
+
+       * scripts/data/localplt-sparc-linux-gnu.data: Remove 'ffs'.
+       * scripts/data/localplt-sparc64-linux-gnu.data: Likewise.
+
 2011-08-30  Andreas Schwab  <schwab@redhat.com>
 
        * elf/rtld.c (dl_main): Relocate objects in dependency order.
index 5ceed16c9b15dd87a8403a9592d50b66c8ab17ab..534fb3d9b422056b194decbc3a08cf9432e13c64 100644 (file)
@@ -10,7 +10,6 @@ libc.so: _Q_mul
 libc.so: _Q_sub
 libc.so: _Unwind_Find_FDE
 libc.so: calloc
-libc.so: ffs
 libc.so: free
 libc.so: malloc
 libc.so: memalign
index 5e6e42d6722ff69a59afb64baf9e257f5f63ccb0..738da78495732833c7e8f08301819e0157d13641 100644 (file)
@@ -12,7 +12,6 @@ libc.so: _Qp_sub
 libc.so: _Qp_xtoq
 libc.so: _Unwind_Find_FDE
 libc.so: calloc
-libc.so: ffs
 libc.so: free
 libc.so: malloc
 libc.so: memalign
index 24225d9622ef7a8defa612f9a11296eed0e3aa56..c8f4ccafa6e183c94547d3ad46de0d3ffc47d14f 100644 (file)
 #define        syscall_error   C_SYMBOL_NAME(__syscall_error)
 #endif
 
+#ifdef PIC
+#define SETUP_PIC_REG(reg, tmp)                                                \
+       .ifndef __sparc_get_pc_thunk.reg;                               \
+       .section .text.__sparc_get_pc_thunk.reg,"axG",@progbits,__sparc_get_pc_thunk.reg,comdat; \
+       .align   32;                                                    \
+       .weak    __sparc_get_pc_thunk.reg;                              \
+       .hidden  __sparc_get_pc_thunk.reg;                              \
+       .type    __sparc_get_pc_thunk.reg, #function;                   \
+__sparc_get_pc_thunk.reg:                                              \
+       jmp     %o7 + 8;                                                \
+        add    %o7, %reg, %##reg;                                      \
+       .previous;                                                      \
+       .endif;                                                         \
+       sethi   %hi(_GLOBAL_OFFSET_TABLE_-4), %##reg;                   \
+       mov     %o7, %##tmp;                                            \
+       call    __sparc_get_pc_thunk.reg;                               \
+        or     %##reg, %lo(_GLOBAL_OFFSET_TABLE_+4), %##reg;           \
+       mov     %##tmp, %o7;
+#endif
+
 #ifdef HAVE_ELF
 #define        ENTRY(name)             \
   .global C_SYMBOL_NAME(name); \
index 3cb0a48c9503241529d8d88fc6505f0d6964c3a3..8af045dc2bee7b5f890cec793f1c09e6c77e8be0 100644 (file)
@@ -57,20 +57,14 @@ C_LABEL(name)                               \
 
 #define LOC(name)  .L##name
 
-       /* If the offset to __syscall_error fits into a signed 22-bit
-        * immediate branch offset, the linker will relax the call into
-        * a normal branch.
-        */
 #define PSEUDO(name, syscall_name, args)       \
        .text;                                  \
-       .globl          __syscall_error;        \
 ENTRY(name);                                   \
        LOADSYSCALL(syscall_name);              \
        ta              0x10;                   \
        bcc             1f;                     \
-        mov            %o7, %g1;               \
-       call            __syscall_error;        \
-        mov            %g1, %o7;               \
+        nop;                                   \
+       SYSCALL_ERROR_HANDLER                   \
 1:
 
 #define PSEUDO_NOERRNO(name, syscall_name, args)\
@@ -88,50 +82,70 @@ ENTRY(name);                                        \
 #define PSEUDO_END(name)                       \
        END(name)
 
-#else  /* __ASSEMBLER__ */
-
-#if defined SHARED && defined DO_VERSIONING && defined PIC \
-    && !defined NO_HIDDEN && !defined NOT_IN_libc
-# define CALL_ERRNO_LOCATION "call   __GI___errno_location;"
+#ifndef PIC
+# define SYSCALL_ERROR_HANDLER                 \
+       mov     %o7, %g1;                       \
+       call    __syscall_error;                \
+        mov    %g1, %o7;
 #else
-# define CALL_ERRNO_LOCATION "call   __errno_location;"
-#endif
+# if RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_HANDLER                        \
+0:     SETUP_PIC_REG(o2,g1)                    \
+       sethi   %hi(rtld_errno), %g1;           \
+       or      %g1, %lo(rtld_errno), %g1;      \
+       ld      [%o2 + %g1], %g1;               \
+       st      %o0, [%g1];                     \
+       jmp     %o7 + 8;                        \
+        mov    -1, %o0;
+# elif defined _LIBC_REENTRANT
+
+#  if USE___THREAD
+#   ifndef NOT_IN_libc
+#    define SYSCALL_ERROR_ERRNO __libc_errno
+#   else
+#    define SYSCALL_ERROR_ERRNO errno
+#   endif
+#   define SYSCALL_ERROR_HANDLER                               \
+0:     SETUP_PIC_REG(o2,g1)                                    \
+       sethi   %tie_hi22(SYSCALL_ERROR_ERRNO), %g1;            \
+       add     %g1, %tie_lo10(SYSCALL_ERROR_ERRNO), %g1;       \
+       ld      [%o2 + %g1], %g1, %tie_ld(SYSCALL_ERROR_ERRNO); \
+       st      %o0, [%g7 + %g1];                               \
+       jmp     %o7 + 8;                                        \
+        mov    -1, %o0;
+#  else
+#  define SYSCALL_ERROR_HANDLER                \
+0:     save    %sp, -96, %sp;          \
+       cfi_def_cfa_register(%fp);      \
+       cfi_window_save;                \
+       cfi_register (%o7, %i7);        \
+       call    __errno_location;       \
+        nop;                           \
+       st      %i0, [%o0];             \
+       jmp     %i7 + 8;                \
+        restore %g0, -1, %o0;
+#  endif
+# else
+#  define SYSCALL_ERROR_HANDLER                \
+0:     SETUP_PIC_REG(o2,g1)            \
+       sethi   %hi(errno), %g1;        \
+       or      %g1, %lo(errno), %g1;   \
+       ld      [%o2 + %g1], %g1;       \
+       st      %o0, [%g1];             \
+       jmp     %o7 + 8;                \
+        mov    -1, %o0;
+# endif        /* _LIBC_REENTRANT */
+#endif /* PIC */
+
+
+#else  /* __ASSEMBLER__ */
 
 #define __SYSCALL_STRING                                               \
        "ta     0x10;"                                                  \
-       "bcs    2f;"                                                    \
-       " nop;"                                                         \
-       "1:"                                                            \
-       ".subsection 2;"                                                \
-       "2:"                                                            \
-       "save   %%sp, -192, %%sp;"                                      \
-       CALL_ERRNO_LOCATION                                             \
-       " nop;"                                                         \
-       "st     %%i0,[%%o0];"                                           \
-       "ba     1b;"                                                    \
-       " restore %%g0, -1, %%o0;"                                      \
-       ".previous;"
-
-#define __CLONE_SYSCALL_STRING                                         \
-       "ta     0x10;"                                                  \
-       "bcs    2f;"                                                    \
-       " sub   %%o1, 1, %%o1;"                                         \
-       "and    %%o0, %%o1, %%o0;"                                      \
-       "1:"                                                            \
-       ".subsection 2;"                                                \
-       "2:"                                                            \
-       "save   %%sp, -192, %%sp;"                                      \
-       CALL_ERRNO_LOCATION                                             \
-       " nop;"                                                         \
-       "st     %%i0, [%%o0];"                                          \
-       "ba     1b;"                                                    \
-       " restore %%g0, -1, %%o0;"                                      \
-       ".previous;"
-
-#define __INTERNAL_SYSCALL_STRING                                      \
-       "ta     0x10;"                                                  \
-       "bcs,a  1f;"                                                    \
-       " sub   %%g0, %%o0, %%o0;"                                      \
+       "bcc    1f;"                                                    \
+       " mov   0, %%g1;"                                               \
+       "sub    %%g0, %%o0, %%o0;"                                      \
+       "mov    1, %%g1;"                                               \
        "1:"
 
 #define __SYSCALL_CLOBBERS                                             \
index 79fa13de75a87749c1864697fc51012995d665bf..bdd1d45bd724f4b0856ce93c3fd05a020f959b3a 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef _LINUX_SPARC64_SYSDEP_H
 #define _LINUX_SPARC64_SYSDEP_H 1
 
-#include <sysdeps/unix/sysdep.h>
+#include <sysdeps/unix/sparc/sysdep.h>
 
 #ifdef IS_IN_rtld
 # include <dl-sysdep.h>                /* Defines RTLD_PRIVATE_ERRNO.  */
@@ -64,20 +64,14 @@ C_LABEL(name)                               \
        cfi_endproc;                    \
        .size name, . - name
 
-       /* If the offset to __syscall_error fits into a signed 22-bit
-        * immediate branch offset, the linker will relax the call into
-        * a normal branch.
-        */
 #define PSEUDO(name, syscall_name, args)       \
        .text;                                  \
-       .globl          __syscall_error;        \
 ENTRY(name);                                   \
        LOADSYSCALL(syscall_name);              \
        ta              0x6d;                   \
        bcc,pt          %xcc, 1f;               \
-        mov            %o7, %g1;               \
-       call            __syscall_error;        \
-        mov            %g1, %o7;               \
+        nop;                                   \
+       SYSCALL_ERROR_HANDLER                   \
 1:
 
 #define        PSEUDO_NOERRNO(name, syscall_name, args)\
@@ -95,51 +89,69 @@ ENTRY(name);                                        \
 #define PSEUDO_END(name)                       \
        END(name)
 
-
-/* Careful here!  This "ret" define can interfere; use jmpl if unsure.  */
-#define ret            retl; nop
-#define ret_NOERRNO    retl; nop
-#define ret_ERRVAL     retl; nop
-#define r0              %o0
-#define r1              %o1
-#define MOVE(x,y)       mov x, y
+#ifndef PIC
+# define SYSCALL_ERROR_HANDLER                 \
+       mov     %o7, %g1;                       \
+       call    __syscall_error;                \
+        mov    %g1, %o7;
+#else
+# if RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_HANDLER                        \
+0:     SETUP_PIC_REG(o2,g1)                    \
+       sethi   %hi(rtld_errno), %g1;           \
+       or      %g1, %lo(rtld_errno), %g1;      \
+       ldx     [%o2 + %g1], %g1;               \
+       st      %o0, [%g1];                     \
+       jmp     %o7 + 8;                        \
+        mov    -1, %o0;
+# elif defined _LIBC_REENTRANT
+
+#  if USE___THREAD
+#   ifndef NOT_IN_libc
+#    define SYSCALL_ERROR_ERRNO __libc_errno
+#   else
+#    define SYSCALL_ERROR_ERRNO errno
+#   endif
+#   define SYSCALL_ERROR_HANDLER                               \
+0:     SETUP_PIC_REG(o2,g1)                                    \
+       sethi   %tie_hi22(SYSCALL_ERROR_ERRNO), %g1;            \
+       add     %g1, %tie_lo10(SYSCALL_ERROR_ERRNO), %g1;       \
+       ldx     [%o2 + %g1], %g1, %tie_ldx(SYSCALL_ERROR_ERRNO);\
+       st      %o0, [%g7 + %g1];                               \
+       jmp     %o7 + 8;                                        \
+        mov    -1, %o0;
+#  else
+#  define SYSCALL_ERROR_HANDLER                \
+0:     save    %sp, -176, %sp;         \
+       cfi_def_cfa_register(%fp);      \
+       cfi_window_save;                \
+       cfi_register (%o7, %i7);        \
+       call    __errno_location;       \
+        nop;                           \
+       st      %i0, [%o0];             \
+       jmp     %i7 + 8;                \
+        restore %g0, -1, %o0;
+#  endif
+# else
+#  define SYSCALL_ERROR_HANDLER                \
+0:     SETUP_PIC_REG(o2,g1)            \
+       sethi   %hi(errno), %g1;        \
+       or      %g1, %lo(errno), %g1;   \
+       ldx     [%o2 + %g1], %g1;       \
+       st      %o0, [%g1];             \
+       jmp     %o7 + 8;                \
+        mov    -1, %o0;
+# endif        /* _LIBC_REENTRANT */
+#endif /* PIC */
 
 #else  /* __ASSEMBLER__ */
 
-#if defined SHARED && defined DO_VERSIONING && defined PIC \
-    && !defined NO_HIDDEN && !defined NOT_IN_libc
-# define CALL_ERRNO_LOCATION "call   __GI___errno_location;"
-#else
-# define CALL_ERRNO_LOCATION "call   __errno_location;"
-#endif
-
 #define __SYSCALL_STRING                                               \
        "ta     0x6d;"                                                  \
        "bcc,pt %%xcc, 1f;"                                             \
-       " nop;"                                                         \
-       "save   %%sp, -192, %%sp;"                                      \
-       CALL_ERRNO_LOCATION                                             \
-       " nop;"                                                         \
-       "st     %%i0,[%%o0];"                                           \
-       "restore %%g0, -1, %%o0;"                                       \
-       "1:"
-
-#define __CLONE_SYSCALL_STRING                                         \
-       "ta     0x6d;"                                                  \
-       "bcc,pt %%xcc, 1f;"                                             \
-       " sub   %%o1, 1, %%o1;"                                         \
-       "save   %%sp, -192, %%sp;"                                      \
-       CALL_ERRNO_LOCATION                                             \
-       " mov   -1, %%i1;"                                              \
-       "st     %%i0,[%%o0];"                                           \
-       "restore %%g0, -1, %%o0;"                                       \
-       "1:"                                                            \
-       "and    %%o0, %%o1, %%o0"
-
-#define __INTERNAL_SYSCALL_STRING                                      \
-       "ta     0x6d;"                                                  \
-       "bcs,a,pt %%xcc, 1f;"                                           \
-       " sub   %%g0, %%o0, %%o0;"                                      \
+       " mov   0, %%g1;"                                               \
+       "sub    %%g0, %%o0, %%o0;"                                      \
+       "mov    1, %%g1;"                                               \
        "1:"
 
 #define __SYSCALL_CLOBBERS                                             \
index 101638a53f6a284ed8fc44a6eca87129bf1c6c3c..f69e1a92ff70c4f5d68ff83a80c32e8c49c8259b 100644 (file)
 #define _LINUX_SPARC_SYSDEP_H 1
 
 #undef INLINE_SYSCALL
-#define INLINE_SYSCALL(name, nr, args...) \
-  inline_syscall##nr(__SYSCALL_STRING, __NR_##name, args)
+#define INLINE_SYSCALL(name, nr, args...)                              \
+({     INTERNAL_SYSCALL_DECL(err);                                     \
+       unsigned int resultvar = INTERNAL_SYSCALL(name, err, nr, args); \
+       if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, err), 0)) \
+         {                                                             \
+           __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, err));      \
+           resultvar = 0xffffffff;                                     \
+         }                                                             \
+       (int) resultvar;                                                \
+})
 
 #undef INTERNAL_SYSCALL_DECL
-#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+#define INTERNAL_SYSCALL_DECL(err) \
+       register long err __asm__("g1");
 
 #undef INTERNAL_SYSCALL
 #define INTERNAL_SYSCALL(name, err, nr, args...) \
-  inline_syscall##nr(__INTERNAL_SYSCALL_STRING, __NR_##name, args)
+  inline_syscall##nr(__SYSCALL_STRING, err, __NR_##name, args)
 
 #undef INTERNAL_SYSCALL_NCS
 #define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
-  inline_syscall##nr(__INTERNAL_SYSCALL_STRING, name, args)
+  inline_syscall##nr(__SYSCALL_STRING, err, name, args)
 
 #undef INTERNAL_SYSCALL_ERROR_P
-#define INTERNAL_SYSCALL_ERROR_P(val, err) \
-  ((unsigned long) (val) >= -515L)
+#define INTERNAL_SYSCALL_ERROR_P(val, err) ((err) != 0)
 
 #undef INTERNAL_SYSCALL_ERRNO
 #define INTERNAL_SYSCALL_ERRNO(val, err)       (-(val))
 
-#define inline_syscall0(string,name,dummy...)                          \
+#define inline_syscall0(string,err,name,dummy...)                      \
 ({                                                                     \
        register long __o0 __asm__ ("o0");                              \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1) :                                  \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err) :                                   \
                          __SYSCALL_CLOBBERS);                          \
        __o0;                                                           \
 })
 
-#define inline_syscall1(string,name,arg1)                              \
+#define inline_syscall1(string,err,name,arg1)                          \
 ({                                                                     \
        register long __o0 __asm__ ("o0") = (long)(arg1);               \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1), "1" (__o0) :                      \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err), "1" (__o0) :                       \
                          __SYSCALL_CLOBBERS);                          \
        __o0;                                                           \
 })
 
-#define inline_syscall2(string,name,arg1,arg2)                         \
+#define inline_syscall2(string,err,name,arg1,arg2)                     \
 ({                                                                     \
        register long __o0 __asm__ ("o0") = (long)(arg1);               \
        register long __o1 __asm__ ("o1") = (long)(arg2);               \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1), "1" (__o0), "r" (__o1) :          \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err), "1" (__o0), "r" (__o1) :           \
                          __SYSCALL_CLOBBERS);                          \
        __o0;                                                           \
 })
 
-#define inline_syscall3(string,name,arg1,arg2,arg3)                    \
+#define inline_syscall3(string,err,name,arg1,arg2,arg3)                        \
 ({                                                                     \
        register long __o0 __asm__ ("o0") = (long)(arg1);               \
        register long __o1 __asm__ ("o1") = (long)(arg2);               \
        register long __o2 __asm__ ("o2") = (long)(arg3);               \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1), "1" (__o0), "r" (__o1),           \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err), "1" (__o0), "r" (__o1),            \
                          "r" (__o2) :                                  \
                          __SYSCALL_CLOBBERS);                          \
        __o0;                                                           \
 })
 
-#define inline_syscall4(string,name,arg1,arg2,arg3,arg4)               \
+#define inline_syscall4(string,err,name,arg1,arg2,arg3,arg4)           \
 ({                                                                     \
        register long __o0 __asm__ ("o0") = (long)(arg1);               \
        register long __o1 __asm__ ("o1") = (long)(arg2);               \
        register long __o2 __asm__ ("o2") = (long)(arg3);               \
        register long __o3 __asm__ ("o3") = (long)(arg4);               \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1), "1" (__o0), "r" (__o1),           \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err), "1" (__o0), "r" (__o1),            \
                          "r" (__o2), "r" (__o3) :                      \
                          __SYSCALL_CLOBBERS);                          \
        __o0;                                                           \
 })
 
-#define inline_syscall5(string,name,arg1,arg2,arg3,arg4,arg5)          \
+#define inline_syscall5(string,err,name,arg1,arg2,arg3,arg4,arg5)      \
 ({                                                                     \
        register long __o0 __asm__ ("o0") = (long)(arg1);               \
        register long __o1 __asm__ ("o1") = (long)(arg2);               \
        register long __o2 __asm__ ("o2") = (long)(arg3);               \
        register long __o3 __asm__ ("o3") = (long)(arg4);               \
        register long __o4 __asm__ ("o4") = (long)(arg5);               \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1), "1" (__o0), "r" (__o1),           \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err), "1" (__o0), "r" (__o1),            \
                          "r" (__o2), "r" (__o3), "r" (__o4) :          \
                          __SYSCALL_CLOBBERS);                          \
        __o0;                                                           \
 })
 
-#define inline_syscall6(string,name,arg1,arg2,arg3,arg4,arg5,arg6)     \
+#define inline_syscall6(string,err,name,arg1,arg2,arg3,arg4,arg5,arg6) \
 ({                                                                     \
        register long __o0 __asm__ ("o0") = (long)(arg1);               \
        register long __o1 __asm__ ("o1") = (long)(arg2);               \
        register long __o3 __asm__ ("o3") = (long)(arg4);               \
        register long __o4 __asm__ ("o4") = (long)(arg5);               \
        register long __o5 __asm__ ("o5") = (long)(arg6);               \
-       register long __g1 __asm__ ("g1") = name;                       \
-       __asm __volatile (string : "=r" (__g1), "=r" (__o0) :           \
-                         "0" (__g1), "1" (__o0), "r" (__o1),           \
+       err = name;                                                     \
+       __asm __volatile (string : "=r" (err), "=r" (__o0) :            \
+                         "0" (err), "1" (__o0), "r" (__o1),            \
                          "r" (__o2), "r" (__o3), "r" (__o4),           \
                          "r" (__o5) :                                  \
                          __SYSCALL_CLOBBERS);                          \
        register long __o3 __asm__ ("o3") = (long)(arg4);               \
        register long __o4 __asm__ ("o4") = (long)(arg5);               \
        register long __g1 __asm__ ("g1") = __NR_clone;                 \
-       __asm __volatile (__CLONE_SYSCALL_STRING :                      \
+       __asm __volatile (__SYSCALL_STRING :                            \
                          "=r" (__g1), "=r" (__o0), "=r" (__o1) :       \
                          "0" (__g1), "1" (__o0), "2" (__o1),           \
                          "r" (__o2), "r" (__o3), "r" (__o4) :          \
                          __SYSCALL_CLOBBERS);                          \
+       if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (__o0, __g1), 0)) \
+         {                                                             \
+           __set_errno (INTERNAL_SYSCALL_ERRNO (__o0, __g1));          \
+           __o0 = -1L;                                                 \
+         }                                                             \
+       else                                                            \
+         {                                                             \
+           __o0 &= (__o1 - 1);                                         \
+         }                                                             \
        __o0;                                                           \
 })