mips/o32: fix internal_syscall5/6/7

Message ID 20170818174451.hhdfihr266nvpwqs@aurel32.net
State New, archived
Headers

Commit Message

Aurelien Jarno Aug. 18, 2017, 5:44 p.m. UTC
  On 2017-08-18 10:32, Maciej W. Rozycki wrote:
> On Fri, 18 Aug 2017, Aurelien Jarno wrote:
> 
> > >  If it's a regression, then it probably is.  What compiler version?  The 
> > > fix for missing trailing label annotation went in r242424, for GCC 7.  If 
> > > it's in handcoded assembly OTOH, then the offending code has to be fixed.
> > 
> > I am using GCC 6, so if the fix went in GCC 7, that's normal the issue
> > is present.
> 
>  OK then; you can use the workaround I suggested to verify MIPS16 
> compilation then.

The workaround didn't work. That said building with GCC 7 fixes the
issue.

> > >  Perhaps we could have separate `__libc_do_syscall5', `__libc_do_syscall6' 
> > > and `__libc_do_syscall7' stubs even, really minimal, with the only code 
> > > required being to load $v0 from the last argument, i.e.:
> > > 
> > > ENTRY(__libc_do_syscall5)
> > > 	lw	v0, 16(sp)
> > > 	syscall
> > > 	move	v1, a3
> > > 	jr	ra
> > > END(__libc_do_syscall5)
> > > 
> > > (and then $sp offsets of 20 and 24 for the other two)?  I'd withdraw any 
> > > concerns about code complication I might have had so far then. :)
> > 
> > That's an interesting idea. If we use a different stub depending on the
> > number of arguments, we can actually pass the syscall number last, which
> > is probably more readable. Could also be used for mips16 in all cases?
> 
>  MIPS16 wrappers do that already, which is also why there is an individual 
> one for each syscall argument count.

Please find below a new patch implementing that. It started to be
complicated to get the MIPS16 related defines used to build the 
equivalent code through GCC to work, so I decided to also implement
__libc_do_syscall0 to __libc_do_syscall4 in libc-do-syscall.S. I looked
at the original code generated by GCC, it's very similar to what I used,
sometimes just a bit longer (sometimes GCC saves the syscall number to
the stack to reload it just after).

I have compiled and tested it on mips O32 little and big endian and found
no regression. Of course it fixes nptl/tst-rwlock15. I have also compiled
it on mips16 O32 little endian, but I haven't tested it besides running
ld.so and libc.so under QEMU.

Changelog:

2017-08-18  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
	    Aurelien Jarno <aurelien@aurel32.net>

	[BZ #21956]
	* sysdeps/unix/sysv/linux/mips/mips32/Makefile [subdir = crypt]
	(libcrypt-sysdep_routines): Add libc-do-syscall.
	[subdir = elf] (sysdep-dl-routines): Likewise.
	[subdir = io] (sysdep_routines): Likewise.
	[subdir = nptl] (libpthread-sysdep_routines): Likewise.
	[subdir = nptl] (libpthread-shared-only-routines): Likewise.
	[subdir = nscd] (nscd-modules): Likewise.
	[subdir = nss] (libnss_db-sysdep_routines): Likewise.
	[subdir = nss] (libnss_db-shared-only-routines): Likewise.
	[subdir = resolv] (libanl-sysdep_routines): Likewise.
	[subdir = resolv] (libanl-shared-only-routines): Likewise.
	[subdir = rt] (librt-sysdep_routines): Likewise.
	[subdir = rt] (librt-shared-only-routines): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libc-do-syscall.S: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h: [!__mips16]
	(INTERNAL_SYSCALL): Make code unconditional.
	[!__mips16] (INTERNAL_SYSCALL_NCS): Likewise.
	[__mips16] (INTERNAL_SYSCALL): Remove.
	[__mips16] (INTERNAL_SYSCALL_NCS): Likewise.
	(__nomips16): Define.
	(__libc_do_syscall_return): Likewise.
	[__mips16] (__libc_do_syscall0): Declare.
	[__mips16] (internal_syscall0): Define.
	[__mips16] (__libc_do_syscall1): Declare.
	[__mips16] (internal_syscall1): Define.
	[__mips16] (__libc_do_syscall2): Declare.
	[__mips16] (internal_syscall2): Define.
	[__mips16] (__libc_do_syscall3): Declare.
	[__mips16] (internal_syscall3): Define.
	[__mips16] (__libc_do_syscall4): Declare.
	[__mips16] (internal_syscall4): Define.
	(internal_syscall0): Guard with !__mips16.
	(internal_syscall1): Guard with !__mips16.
	(internal_syscall2): Guard with !__mips16.
	(internal_syscall3): Guard with !__mips16.
	(internal_syscall4): Guard with !__mips16.
	(FORCE_FRAME_POINTER): Remove.
	(internal_syscall5): Rewrite to call __libc_do_syscall5.
	(internal_syscall6): Rewrite to call __libc_do_syscall6.
	(internal_syscall7): Rewrite to call __libc_do_syscall7.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile: Remove file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c:
	  Likewise
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c:
	  Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c:
	  Likewise.
  

Comments

Maciej W. Rozycki Aug. 18, 2017, 10:27 p.m. UTC | #1
On Fri, 18 Aug 2017, Aurelien Jarno wrote:

> > > I am using GCC 6, so if the fix went in GCC 7, that's normal the issue
> > > is present.
> > 
> >  OK then; you can use the workaround I suggested to verify MIPS16 
> > compilation then.
> 
> The workaround didn't work.

 Hmm, that means there's something wrong with binutils which needs fixing.  
Can you please send me the failing .s file and the command line used to 
assemble it (from `gcc -v')?

> > > That's an interesting idea. If we use a different stub depending on the
> > > number of arguments, we can actually pass the syscall number last, which
> > > is probably more readable. Could also be used for mips16 in all cases?
> > 
> >  MIPS16 wrappers do that already, which is also why there is an individual 
> > one for each syscall argument count.
> 
> Please find below a new patch implementing that. It started to be
> complicated to get the MIPS16 related defines used to build the 
> equivalent code through GCC to work, so I decided to also implement
> __libc_do_syscall0 to __libc_do_syscall4 in libc-do-syscall.S. I looked
> at the original code generated by GCC, it's very similar to what I used,
> sometimes just a bit longer (sometimes GCC saves the syscall number to
> the stack to reload it just after).

 The MIPS16 wrappers were split into individual files so that only ones 
that are actually used by `ld.so' are pulled.  I think it would be good if 
we preserved that.  I'll see if I can experiment with keeping the original 
MIPS16 0-3 wrappers.

  Maciej
  
Aurelien Jarno Aug. 19, 2017, 12:44 p.m. UTC | #2
On 2017-08-18 23:27, Maciej W. Rozycki wrote:
> On Fri, 18 Aug 2017, Aurelien Jarno wrote:
> 
> > > > I am using GCC 6, so if the fix went in GCC 7, that's normal the issue
> > > > is present.
> > > 
> > >  OK then; you can use the workaround I suggested to verify MIPS16 
> > > compilation then.
> > 
> > The workaround didn't work.
> 
>  Hmm, that means there's something wrong with binutils which needs fixing.  
> Can you please send me the failing .s file and the command line used to 
> assemble it (from `gcc -v')?

Please find that attached.

> > > > That's an interesting idea. If we use a different stub depending on the
> > > > number of arguments, we can actually pass the syscall number last, which
> > > > is probably more readable. Could also be used for mips16 in all cases?
> > > 
> > >  MIPS16 wrappers do that already, which is also why there is an individual 
> > > one for each syscall argument count.
> > 
> > Please find below a new patch implementing that. It started to be
> > complicated to get the MIPS16 related defines used to build the 
> > equivalent code through GCC to work, so I decided to also implement
> > __libc_do_syscall0 to __libc_do_syscall4 in libc-do-syscall.S. I looked
> > at the original code generated by GCC, it's very similar to what I used,
> > sometimes just a bit longer (sometimes GCC saves the syscall number to
> > the stack to reload it just after).
> 
>  The MIPS16 wrappers were split into individual files so that only ones 
> that are actually used by `ld.so' are pulled.  I think it would be good if 
> we preserved that.  I'll see if I can experiment with keeping the original 
> MIPS16 0-3 wrappers.

For what I have seen, ld.so already uses syscalls with 1 to 4 arguments.
It doesn't use any syscall without argument though. So it's only 4
instructions overhead.

Aurelien
  

Patch

diff --git a/sysdeps/unix/sysv/linux/mips/mips32/Makefile b/sysdeps/unix/sysv/linux/mips/mips32/Makefile
index 33b461500c..d0bb1fc200 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/Makefile
+++ b/sysdeps/unix/sysv/linux/mips/mips32/Makefile
@@ -1,8 +1,44 @@ 
+ifeq ($(subdir),crypt)
+libcrypt-sysdep_routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),elf)
+sysdep-dl-routines += libc-do-syscall
+endif
+
 ifeq ($(subdir),conform)
 # For bugs 17786 and 21278.
 conformtest-xfail-conds += mips-o32-linux
 endif
 
+ifeq ($(subdir),io)
+sysdep_routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += libc-do-syscall
+libpthread-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),nscd)
+nscd-modules += libc-do-syscall
+endif
+
+ifeq ($(subdir),nss)
+libnss_db-sysdep_routines += libc-do-syscall
+libnss_db-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),resolv)
+libanl-sysdep_routines += libc-do-syscall
+libanl-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),rt)
+librt-sysdep_routines += libc-do-syscall
+librt-shared-only-routines += libc-do-syscall
+endif
+
 ifeq ($(subdir),stdlib)
 tests += bug-getcontext-mips-gp
 endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libc-do-syscall.S b/sysdeps/unix/sysv/linux/mips/mips32/libc-do-syscall.S
new file mode 100644
index 0000000000..e6777f6967
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libc-do-syscall.S
@@ -0,0 +1,105 @@ 
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <sys/asm.h>
+
+	.text
+	.set    nomips16
+
+#ifdef __mips16
+
+/* long long __libc_do_syscall0 (long arg1, long number)  */
+	.hidden __libc_do_syscall0
+ENTRY(__libc_do_syscall0)
+        move    v0, a0
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall0)
+
+
+/* long long __libc_do_syscall1 (long arg1, long number)  */
+	.hidden __libc_do_syscall1
+ENTRY(__libc_do_syscall1)
+        move    v0, a1
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall1)
+
+/* long long __libc_do_syscall2 (long arg1, long arg2, long number)  */
+	.hidden __libc_do_syscall2
+ENTRY(__libc_do_syscall2)
+        move    v0, a2
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall2)
+
+/* long long __libc_do_syscall3 (long arg1, long arg2, long arg3,
+				 long number)  */
+	.hidden __libc_do_syscall3
+ENTRY(__libc_do_syscall3)
+        move    v0, a3
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall3)
+
+/* long long __libc_do_syscall4 (long arg1, long arg2, long arg3, long arg4,
+				 long number)  */
+	.hidden __libc_do_syscall4
+ENTRY(__libc_do_syscall4)
+        lw      v0, 16(sp)
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall4)
+
+#endif /* !__mips16 */
+
+/* long long __libc_do_syscall5 (long arg1, long arg2, long arg3, long arg4,
+				 long arg5, long number)  */
+	.hidden __libc_do_syscall5
+ENTRY(__libc_do_syscall5)
+        lw      v0, 20(sp)
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall5)
+
+/* long long __libc_do_syscall6 (long arg1, long arg2, long arg3, long arg4,
+				 long arg5, long arg6, long number)  */
+	.hidden __libc_do_syscall6
+ENTRY(__libc_do_syscall6)
+        lw      v0, 24(sp)
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall6)
+
+/* long long __libc_do_syscall7 (long arg1, long arg2, long arg3, long arg4,
+				 long arg5, long arg6, long arg7,
+				 long number)  */
+	.hidden __libc_do_syscall7
+ENTRY(__libc_do_syscall7)
+        lw      v0, 28(sp)
+        syscall
+        move    v1, a3
+        jr      ra
+END(__libc_do_syscall7)
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile b/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
deleted file mode 100644
index fa9fcb7e6f..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@ 
-ifeq ($(subdir),misc)
-sysdep_routines += mips16-syscall0 mips16-syscall1 mips16-syscall2
-sysdep_routines += mips16-syscall3 mips16-syscall4 mips16-syscall5
-sysdep_routines += mips16-syscall6 mips16-syscall7
-CFLAGS-mips16-syscall0.c += -fexceptions
-CFLAGS-mips16-syscall1.c += -fexceptions
-CFLAGS-mips16-syscall2.c += -fexceptions
-CFLAGS-mips16-syscall3.c += -fexceptions
-CFLAGS-mips16-syscall4.c += -fexceptions
-CFLAGS-mips16-syscall5.c += -fexceptions
-CFLAGS-mips16-syscall6.c += -fexceptions
-CFLAGS-mips16-syscall7.c += -fexceptions
-endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions b/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
deleted file mode 100644
index 73bcfb566c..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
+++ /dev/null
@@ -1,6 +0,0 @@ 
-libc {
-  GLIBC_PRIVATE {
-    __mips16_syscall0; __mips16_syscall1; __mips16_syscall2; __mips16_syscall3;
-    __mips16_syscall4; __mips16_syscall5; __mips16_syscall6; __mips16_syscall7;
-  }
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
deleted file mode 100644
index 880e9908e8..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
+++ /dev/null
@@ -1,89 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef MIPS16_SYSCALL_H
-#define MIPS16_SYSCALL_H 1
-
-#define __nomips16 __attribute__ ((nomips16))
-
-union __mips16_syscall_return
-  {
-    long long val;
-    struct
-      {
-	long v0;
-	long v1;
-      }
-    reg;
-  };
-
-long long __nomips16 __mips16_syscall0 (long number);
-#define __mips16_syscall0(dummy, number)				\
-	__mips16_syscall0 ((long) (number))
-
-long long __nomips16 __mips16_syscall1 (long a0,
-					long number);
-#define __mips16_syscall1(a0, number)					\
-	__mips16_syscall1 ((long) (a0),					\
-			   (long) (number))
-
-long long __nomips16 __mips16_syscall2 (long a0, long a1,
-					long number);
-#define __mips16_syscall2(a0, a1, number)				\
-	__mips16_syscall2 ((long) (a0), (long) (a1),			\
-			   (long) (number))
-
-long long __nomips16 __mips16_syscall3 (long a0, long a1, long a2,
-					long number);
-#define __mips16_syscall3(a0, a1, a2, number)				\
-	__mips16_syscall3 ((long) (a0), (long) (a1), (long) (a2),	\
-			   (long) (number))
-
-long long __nomips16 __mips16_syscall4 (long a0, long a1, long a2, long a3,
-					long number);
-#define __mips16_syscall4(a0, a1, a2, a3, number)			\
-	__mips16_syscall4 ((long) (a0), (long) (a1), (long) (a2),	\
-			   (long) (a3),					\
-			   (long) (number))
-
-long long __nomips16 __mips16_syscall5 (long a0, long a1, long a2, long a3,
-					long a4,
-					long number);
-#define __mips16_syscall5(a0, a1, a2, a3, a4, number)			\
-	__mips16_syscall5 ((long) (a0), (long) (a1), (long) (a2),	\
-			   (long) (a3), (long) (a4),			\
-			   (long) (number))
-
-long long __nomips16 __mips16_syscall6 (long a0, long a1, long a2, long a3,
-					long a4, long a5,
-					long number);
-#define __mips16_syscall6(a0, a1, a2, a3, a4, a5, number)		\
-	__mips16_syscall6 ((long) (a0), (long) (a1), (long) (a2),	\
-			   (long) (a3), (long) (a4), (long) (a5),	\
-			   (long) (number))
-
-long long __nomips16 __mips16_syscall7 (long a0, long a1, long a2, long a3,
-					long a4, long a5, long a6,
-					long number);
-#define __mips16_syscall7(a0, a1, a2, a3, a4, a5, a6, number)		\
-	__mips16_syscall7 ((long) (a0), (long) (a1), (long) (a2),	\
-			   (long) (a3), (long) (a4), (long) (a5),	\
-			   (long) (a6),					\
-			   (long) (number))
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
deleted file mode 100644
index 490245b34e..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
+++ /dev/null
@@ -1,30 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall0
-
-long long __nomips16
-__mips16_syscall0 (long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 0);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
deleted file mode 100644
index 3061e8accb..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
+++ /dev/null
@@ -1,32 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall1
-
-long long __nomips16
-__mips16_syscall1 (long a0,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 1,
-					a0);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
deleted file mode 100644
index 440a4ed285..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
+++ /dev/null
@@ -1,32 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall2
-
-long long __nomips16
-__mips16_syscall2 (long a0, long a1,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 2,
-					a0, a1);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
deleted file mode 100644
index c3f83fc1f6..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
+++ /dev/null
@@ -1,32 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall3
-
-long long __nomips16
-__mips16_syscall3 (long a0, long a1, long a2,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 3,
-					a0, a1, a2);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
deleted file mode 100644
index 496297d296..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
+++ /dev/null
@@ -1,32 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall4
-
-long long __nomips16
-__mips16_syscall4 (long a0, long a1, long a2, long a3,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 4,
-					a0, a1, a2, a3);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
deleted file mode 100644
index ad265d88e2..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
+++ /dev/null
@@ -1,33 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall5
-
-long long __nomips16
-__mips16_syscall5 (long a0, long a1, long a2, long a3,
-		   long a4,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 5,
-					a0, a1, a2, a3, a4);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
deleted file mode 100644
index bfbd395ed3..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
+++ /dev/null
@@ -1,33 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall6
-
-long long __nomips16
-__mips16_syscall6 (long a0, long a1, long a2, long a3,
-		   long a4, long a5,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 6,
-					a0, a1, a2, a3, a4, a5);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c b/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
deleted file mode 100644
index e1267616dc..0000000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
+++ /dev/null
@@ -1,33 +0,0 @@ 
-/* MIPS16 syscall wrappers.
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <mips16-syscall.h>
-
-#undef __mips16_syscall7
-
-long long __nomips16
-__mips16_syscall7 (long a0, long a1, long a2, long a3,
-		   long a4, long a5, long a6,
-		   long number)
-{
-  union __mips16_syscall_return ret;
-  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 7,
-					a0, a1, a2, a3, a4, a5, a6);
-  return ret.val;
-}
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
index e9e3ee7e82..31d70c0189 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
@@ -98,45 +98,100 @@ 
 #undef INTERNAL_SYSCALL
 #undef INTERNAL_SYSCALL_NCS
 
+#define INTERNAL_SYSCALL(name, err, nr, args...)			\
+	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
+			      "IK" (SYS_ify (name)),			\
+			      SYS_ify(name), err, args)
+
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
+			      "r" (__s0),				\
+			      number, err, args)
+
+#define __nomips16 __attribute__ ((nomips16))
+
+union __libc_do_syscall_return
+  {
+    long long val;
+    struct
+      {
+	long v0;
+	long v1;
+      }
+    reg;
+  };
+
 #ifdef __mips16
-/* There's no MIPS16 syscall instruction, so we go through out-of-line
-   standard MIPS wrappers.  These do use inline snippets below though,
-   through INTERNAL_SYSCALL_MIPS16.  Spilling the syscall number to
-   memory gives the best code in that case, avoiding the need to save
-   and restore a static register.  */
+/* There's no MIPS16 syscall instruction, so we always need to go through
+   out-of-line standard MIPS wrappers.  */
+
+long long __nomips16 __libc_do_syscall0 (long number);
 
-# include <mips16-syscall.h>
+# define internal_syscall0(v0_init, input, number, err, dummy)		\
+({									\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall0 (number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
+})
 
-# define INTERNAL_SYSCALL(name, err, nr, args...)			\
-	INTERNAL_SYSCALL_NCS (SYS_ify (name), err, nr, args)
+long long __nomips16 __libc_do_syscall1 (long arg1, long number);
 
-# define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+# define internal_syscall1(v0_init, input, number, err, arg1)		\
 ({									\
-	union __mips16_syscall_return _sc_ret;				\
-	_sc_ret.val = __mips16_syscall##nr (args, number);		\
-	err = _sc_ret.reg.v1;						\
-	_sc_ret.reg.v0;							\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall1 ((long) (arg1),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
 })
 
-# define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...)		\
-	internal_syscall##nr ("lw\t%0, %2\n\t",				\
-			      "R" (number),				\
-			      0, err, args)
+long long __nomips16 __libc_do_syscall2 (long arg1, long arg2, long number);
 
-#else /* !__mips16 */
-# define INTERNAL_SYSCALL(name, err, nr, args...)			\
-	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
-			      "IK" (SYS_ify (name)),			\
-			      0, err, args)
+# define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
+({									\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall2 ((long) (arg1),		\
+					      (long) (arg2),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
+})
 
-# define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
-	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
-			      "r" (__s0),				\
-			      number, err, args)
+long long __nomips16 __libc_do_syscall3 (long arg1, long arg2, long arg3,
+					 long number);
 
-#endif /* !__mips16 */
+# define internal_syscall3(v0_init, input, number, err,			\
+			   arg1, arg2, arg3)				\
+({									\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall3 ((long) (arg1),		\
+					      (long) (arg2),		\
+					      (long) (arg3),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
+})
+
+long long __nomips16 __libc_do_syscall4 (long arg1, long arg2, long arg3,
+					 long arg4, long number);
 
-#define internal_syscall0(v0_init, input, number, err, dummy...)	\
+# define internal_syscall4(v0_init, input, number, err,			\
+			   arg1, arg2, arg3, arg4)			\
+({									\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall4 ((long) (arg1),		\
+					      (long) (arg2),		\
+					      (long) (arg3),		\
+					      (long) (arg4),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
+})
+
+#else /* !__mips16 */
+
+# define internal_syscall0(v0_init, input, number, err, dummy...)	\
 ({									\
 	long _sys_result;						\
 									\
@@ -159,7 +214,7 @@ 
 	_sys_result;							\
 })
 
-#define internal_syscall1(v0_init, input, number, err, arg1)		\
+# define internal_syscall1(v0_init, input, number, err, arg1)		\
 ({									\
 	long _sys_result;						\
 									\
@@ -183,7 +238,7 @@ 
 	_sys_result;							\
 })
 
-#define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
+# define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
 ({									\
 	long _sys_result;						\
 									\
@@ -208,8 +263,8 @@ 
 	_sys_result;							\
 })
 
-#define internal_syscall3(v0_init, input, number, err,			\
-			  arg1, arg2, arg3)				\
+# define internal_syscall3(v0_init, input, number, err,			\
+			   arg1, arg2, arg3)				\
 ({									\
 	long _sys_result;						\
 									\
@@ -235,8 +290,8 @@ 
 	_sys_result;							\
 })
 
-#define internal_syscall4(v0_init, input, number, err,			\
-			  arg1, arg2, arg3, arg4)			\
+# define internal_syscall4(v0_init, input, number, err,			\
+			   arg1, arg2, arg3, arg4)			\
 ({									\
 	long _sys_result;						\
 									\
@@ -262,110 +317,65 @@ 
 	_sys_result;							\
 })
 
-/* We need to use a frame pointer for the functions in which we
-   adjust $sp around the syscall, or debug information and unwind
-   information will be $sp relative and thus wrong during the syscall.  As
-   of GCC 4.7, this is sufficient.  */
-#define FORCE_FRAME_POINTER						\
-  void *volatile __fp_force __attribute__ ((unused)) = alloca (4)
+#endif /* !__mips16 */
+
+/* Out-of-line standard MIPS wrappers used for 5, 6, and 7 argument syscall
+   which requires arguments in stack.  */
+
+long long __nomips16 __libc_do_syscall5 (long arg1, long arg2, long arg3,
+					 long arg4, long arg5, long number);
 
 #define internal_syscall5(v0_init, input, number, err,			\
 			  arg1, arg2, arg3, arg4, arg5)			\
 ({									\
-	long _sys_result;						\
-									\
-	FORCE_FRAME_POINTER;						\
-	{								\
-	register long __s0 asm ("$16") __attribute__ ((unused))		\
-	  = (number);							\
-	register long __v0 asm ("$2");					\
-	register long __a0 asm ("$4") = (long) (arg1);			\
-	register long __a1 asm ("$5") = (long) (arg2);			\
-	register long __a2 asm ("$6") = (long) (arg3);			\
-	register long __a3 asm ("$7") = (long) (arg4);			\
-	__asm__ volatile (						\
-	".set\tnoreorder\n\t"						\
-	"subu\t$29, 32\n\t"						\
-	"sw\t%6, 16($29)\n\t"						\
-	v0_init								\
-	"syscall\n\t"							\
-	"addiu\t$29, 32\n\t"						\
-	".set\treorder"							\
-	: "=r" (__v0), "+r" (__a3)					\
-	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\
-	  "r" ((long) (arg5))						\
-	: __SYSCALL_CLOBBERS);						\
-	err = __a3;							\
-	_sys_result = __v0;						\
-	}								\
-	_sys_result;							\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall5 ((long) (arg1),		\
+					      (long) (arg2),		\
+					      (long) (arg3),		\
+					      (long) (arg4),		\
+					      (long) (arg5),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
 })
 
+long long __nomips16 __libc_do_syscall6 (long arg1, long arg2, long arg3,
+					 long arg4, long arg5, long arg6,
+					 long number);
+
 #define internal_syscall6(v0_init, input, number, err,			\
 			  arg1, arg2, arg3, arg4, arg5, arg6)		\
 ({									\
-	long _sys_result;						\
-									\
-	FORCE_FRAME_POINTER;						\
-	{								\
-	register long __s0 asm ("$16") __attribute__ ((unused))		\
-	  = (number);							\
-	register long __v0 asm ("$2");					\
-	register long __a0 asm ("$4") = (long) (arg1);			\
-	register long __a1 asm ("$5") = (long) (arg2);			\
-	register long __a2 asm ("$6") = (long) (arg3);			\
-	register long __a3 asm ("$7") = (long) (arg4);			\
-	__asm__ volatile (						\
-	".set\tnoreorder\n\t"						\
-	"subu\t$29, 32\n\t"						\
-	"sw\t%6, 16($29)\n\t"						\
-	"sw\t%7, 20($29)\n\t"						\
-	v0_init								\
-	"syscall\n\t"							\
-	"addiu\t$29, 32\n\t"						\
-	".set\treorder"							\
-	: "=r" (__v0), "+r" (__a3)					\
-	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\
-	  "r" ((long) (arg5)), "r" ((long) (arg6))			\
-	: __SYSCALL_CLOBBERS);						\
-	err = __a3;							\
-	_sys_result = __v0;						\
-	}								\
-	_sys_result;							\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall6 ((long) (arg1),		\
+					      (long) (arg2),		\
+					      (long) (arg3),		\
+					      (long) (arg4),		\
+					      (long) (arg5),		\
+					      (long) (arg6),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
 })
 
+long long __nomips16 __libc_do_syscall7 (long arg1, long arg2, long arg3,
+					 long arg4, long arg5, long arg6,
+					 long arg7, long number);
+
 #define internal_syscall7(v0_init, input, number, err,			\
 			  arg1, arg2, arg3, arg4, arg5, arg6, arg7)	\
 ({									\
-	long _sys_result;						\
-									\
-	FORCE_FRAME_POINTER;						\
-	{								\
-	register long __s0 asm ("$16") __attribute__ ((unused))		\
-	  = (number);							\
-	register long __v0 asm ("$2");					\
-	register long __a0 asm ("$4") = (long) (arg1);			\
-	register long __a1 asm ("$5") = (long) (arg2);			\
-	register long __a2 asm ("$6") = (long) (arg3);			\
-	register long __a3 asm ("$7") = (long) (arg4);			\
-	__asm__ volatile (						\
-	".set\tnoreorder\n\t"						\
-	"subu\t$29, 32\n\t"						\
-	"sw\t%6, 16($29)\n\t"						\
-	"sw\t%7, 20($29)\n\t"						\
-	"sw\t%8, 24($29)\n\t"						\
-	v0_init								\
-	"syscall\n\t"							\
-	"addiu\t$29, 32\n\t"						\
-	".set\treorder"							\
-	: "=r" (__v0), "+r" (__a3)					\
-	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\
-	  "r" ((long) (arg5)), "r" ((long) (arg6)), "r" ((long) (arg7))	\
-	: __SYSCALL_CLOBBERS);						\
-	err = __a3;							\
-	_sys_result = __v0;						\
-	}								\
-	_sys_result;							\
+	union __libc_do_syscall_return _sys_result;			\
+	_sys_result.val = __libc_do_syscall7 ((long) (arg1),		\
+					      (long) (arg2),		\
+					      (long) (arg3),		\
+					      (long) (arg4),		\
+					      (long) (arg5),		\
+					      (long) (arg6),		\
+					      (long) (arg7),		\
+					      number);			\
+	err = _sys_result.reg.v1;					\
+	_sys_result.reg.v0;						\
 })
 
 #define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \