[05/23] linux: Replace INLINE_SYSCALL_ERROR_RETURN_VALUE with __syscall_error

Message ID 20201109201826.120534-6-adhemerval.zanella@linaro.org
State Superseded
Headers
Series Simplify internal Linux syscall |

Commit Message

Adhemerval Zanella Nov. 9, 2020, 8:18 p.m. UTC
  The INLINE_SYSCALL_ERROR_RETURN_VALUE macro was added as a way to
optimize i686 errno setting when {INTERNAL,INLINE}_SYSCALL is called
(since calling__x86.get_pc_thunk.reg to load PC into reg to access
errno is costly for the cases where there is no error).

However this i686 optimizations was also remove by fcb78a55058f,
which consolidate INLINE_SYSCALL semantic and removed i686
INLINE_SYSCALL_ERROR_RETURN_VALUE definition.

This patch adds this optimization back, but in a more generic way.
Each architecture/ABI might select how __syscall_error is emitted,
either by using a static inline or using a external call.  To avoid
the potential PLT call overhead, for the latter __syscall_error is
added on each library that issues {INTERNAL,INLINE}_SYSCALL as a
hidden symbol (and this follow the idea of moving all the libpthread
and librt to libc).

No semantic changes expected, checked with a build against all
affected ABIs.
---
 sysdeps/unix/sysv/linux/Makefile              |  9 ++++-
 sysdeps/unix/sysv/linux/aarch64/sysdep.c      |  1 -
 sysdeps/unix/sysv/linux/adjtime.c             |  2 +-
 sysdeps/unix/sysv/linux/alpha/fxstat64.c      |  2 +-
 sysdeps/unix/sysv/linux/alpha/lxstat64.c      |  2 +-
 sysdeps/unix/sysv/linux/alpha/xstat64.c       |  2 +-
 sysdeps/unix/sysv/linux/arc/sysdep.c          |  8 ++--
 sysdeps/unix/sysv/linux/arc/sysdep.h          |  5 ---
 sysdeps/unix/sysv/linux/faccessat.c           |  4 +-
 sysdeps/unix/sysv/linux/fchmodat.c            |  2 +-
 sysdeps/unix/sysv/linux/fcntl_nocancel.c      |  2 +-
 sysdeps/unix/sysv/linux/fstatat.c             |  4 +-
 sysdeps/unix/sysv/linux/fstatat64.c           |  2 +-
 sysdeps/unix/sysv/linux/futimens.c            |  2 +-
 sysdeps/unix/sysv/linux/fxstat.c              |  2 +-
 sysdeps/unix/sysv/linux/fxstat64.c            |  2 +-
 sysdeps/unix/sysv/linux/fxstatat.c            |  2 +-
 sysdeps/unix/sysv/linux/fxstatat64.c          |  2 +-
 sysdeps/unix/sysv/linux/getdents.c            |  2 +-
 sysdeps/unix/sysv/linux/hppa/sysdep.c         |  2 -
 sysdeps/unix/sysv/linux/i386/brk.c            |  2 +-
 sysdeps/unix/sysv/linux/i386/sysdep.c         |  1 -
 sysdeps/unix/sysv/linux/i386/sysdep.h         |  3 --
 sysdeps/unix/sysv/linux/lxstat.c              |  2 +-
 sysdeps/unix/sysv/linux/lxstat64.c            |  2 +-
 .../unix/sysv/linux/mips/mips64/fxstatat64.c  |  2 +-
 sysdeps/unix/sysv/linux/mknodat.c             |  2 +-
 sysdeps/unix/sysv/linux/mmap.c                |  2 +-
 sysdeps/unix/sysv/linux/mmap64.c              |  2 +-
 sysdeps/unix/sysv/linux/mq_open.c             |  2 +-
 sysdeps/unix/sysv/linux/mq_unlink.c           |  2 +-
 sysdeps/unix/sysv/linux/powerpc/sysdep.c      |  1 -
 sysdeps/unix/sysv/linux/prlimit.c             |  4 +-
 sysdeps/unix/sysv/linux/setegid.c             |  2 +-
 sysdeps/unix/sysv/linux/seteuid.c             |  2 +-
 sysdeps/unix/sysv/linux/shmat.c               |  2 +-
 sysdeps/unix/sysv/linux/speed.c               |  4 +-
 sysdeps/unix/sysv/linux/syscall_error.c       | 30 +++++++++++++++
 sysdeps/unix/sysv/linux/sysdep.h              | 37 ++++++++++++-------
 sysdeps/unix/sysv/linux/tcsendbrk.c           |  2 +-
 sysdeps/unix/sysv/linux/tcsetattr.c           |  2 +-
 sysdeps/unix/sysv/linux/ustat.c               |  4 +-
 sysdeps/unix/sysv/linux/utimensat.c           |  2 +-
 sysdeps/unix/sysv/linux/xmknod.c              |  2 +-
 sysdeps/unix/sysv/linux/xmknodat.c            |  2 +-
 sysdeps/unix/sysv/linux/xstat.c               |  2 +-
 sysdeps/unix/sysv/linux/xstat64.c             |  2 +-
 sysdeps/unix/sysv/linux/xstatconv.c           | 12 +++---
 48 files changed, 113 insertions(+), 80 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/syscall_error.c
  

Comments

Joseph Myers Nov. 9, 2020, 10:14 p.m. UTC | #1
On Mon, 9 Nov 2020, Adhemerval Zanella via Libc-alpha wrote:

> +/* The errno setting might be set either inline or with a helper function.
> +   For some ABIs (x86_64 for instance), handling it inline might generate
> +   less code; while for others (i686) a function call is preferable.
> +
> +   To use the helper function the ABI must define SYSCALL_ERROR_FUNC, it will
> +   build a hidden function on each shared object that issue direct syscall
> +   with {INLINE,INTERNAL}_SYSCALL_CALL.  */
> +
> +#ifdef SYSCALL_ERROR_FUNC

The current convention would be to have SYSCALL_ERROR_FUNC always defined 
and make the choice using #if not #ifdef.
  
Adhemerval Zanella Nov. 11, 2020, 4:31 p.m. UTC | #2
On 09/11/2020 19:14, Joseph Myers wrote:
> On Mon, 9 Nov 2020, Adhemerval Zanella via Libc-alpha wrote:
> 
>> +/* The errno setting might be set either inline or with a helper function.
>> +   For some ABIs (x86_64 for instance), handling it inline might generate
>> +   less code; while for others (i686) a function call is preferable.
>> +
>> +   To use the helper function the ABI must define SYSCALL_ERROR_FUNC, it will
>> +   build a hidden function on each shared object that issue direct syscall
>> +   with {INLINE,INTERNAL}_SYSCALL_CALL.  */
>> +
>> +#ifdef SYSCALL_ERROR_FUNC
> 
> The current convention would be to have SYSCALL_ERROR_FUNC always defined 
> and make the choice using #if not #ifdef.
> 

Right, I think it would be better to move it to auxiliary header then.
  

Patch

diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 09604e128b..241b5f2c53 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -41,7 +41,7 @@  update-syscall-lists: arch-syscall.h
 endif
 
 ifeq ($(subdir),csu)
-sysdep_routines += errno-loc
+sysdep_routines += errno-loc syscall_error
 endif
 
 ifeq ($(subdir),assert)
@@ -283,7 +283,8 @@  tests += tst-fallocate tst-fallocate64 tst-o_path-locks
 endif
 
 ifeq ($(subdir),elf)
-sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir
+sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir \
+			syscall_error
 
 libof-lddlibc4 = lddlibc4
 
@@ -295,6 +296,8 @@  endif
 ifeq ($(subdir),rt)
 CFLAGS-mq_send.c += -fexceptions
 CFLAGS-mq_receive.c += -fexceptions
+librt-routines += syscall_error
+librt-shared-only-routines += syscall_error
 endif
 
 ifeq ($(subdir),nscd)
@@ -303,5 +306,7 @@  CFLAGS-gai.c += -DNEED_NETLINK
 endif
 
 ifeq ($(subdir),nptl)
+libpthread-routines += syscall_error
+libpthread-shared-only-routines += syscall_error
 tests += tst-align-clone tst-getpid1
 endif
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.c b/sysdeps/unix/sysv/linux/aarch64/sysdep.c
index b6c01e1aec..6b88f3484f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.c
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.c
@@ -16,7 +16,6 @@ 
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
 #include <errno.h>
 
 long __syscall_error (long err);
diff --git a/sysdeps/unix/sysv/linux/adjtime.c b/sysdeps/unix/sysv/linux/adjtime.c
index 8e7c8cc5da..1a1a37acd3 100644
--- a/sysdeps/unix/sysv/linux/adjtime.c
+++ b/sysdeps/unix/sysv/linux/adjtime.c
@@ -37,7 +37,7 @@  __adjtime64 (const struct __timeval64 *itv, struct __timeval64 *otv)
       tmp.tv_sec = itv->tv_sec + itv->tv_usec / 1000000L;
       tmp.tv_usec = itv->tv_usec % 1000000L;
       if (tmp.tv_sec > MAX_SEC || tmp.tv_sec < MIN_SEC)
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+	return __syscall_error (-EINVAL);
       tntx.offset = tmp.tv_usec + tmp.tv_sec * 1000000L;
       tntx.modes = ADJ_OFFSET_SINGLESHOT;
     }
diff --git a/sysdeps/unix/sysv/linux/alpha/fxstat64.c b/sysdeps/unix/sysv/linux/alpha/fxstat64.c
index bcfb55050c..806ef66598 100644
--- a/sysdeps/unix/sysv/linux/alpha/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/alpha/fxstat64.c
@@ -40,7 +40,7 @@  __fxstat64 (int vers, int fd, struct stat64 *buf)
 	int r = INTERNAL_SYSCALL_CALL (fstat, fd, &kbuf);
 	if (r == 0)
 	  return __xstat_conv (vers, &kbuf, buf);
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+	return __syscall_error (r);
       }
     }
 }
diff --git a/sysdeps/unix/sysv/linux/alpha/lxstat64.c b/sysdeps/unix/sysv/linux/alpha/lxstat64.c
index 7424b2f621..0499b0f8f1 100644
--- a/sysdeps/unix/sysv/linux/alpha/lxstat64.c
+++ b/sysdeps/unix/sysv/linux/alpha/lxstat64.c
@@ -41,7 +41,7 @@  __lxstat64 (int vers, const char *name, struct stat64 *buf)
 	int r = INTERNAL_SYSCALL_CALL (lstat, name, &kbuf);
 	if (r == 0)
 	  return __xstat_conv (vers, &kbuf, buf);
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+	return __syscall_error (r);
       }
     }
 }
diff --git a/sysdeps/unix/sysv/linux/alpha/xstat64.c b/sysdeps/unix/sysv/linux/alpha/xstat64.c
index 59f7ddae7f..b08ade68d4 100644
--- a/sysdeps/unix/sysv/linux/alpha/xstat64.c
+++ b/sysdeps/unix/sysv/linux/alpha/xstat64.c
@@ -41,7 +41,7 @@  __xstat64 (int vers, const char *name, struct stat64 *buf)
 	int r = INTERNAL_SYSCALL_CALL (stat, name, &kbuf);
 	if (r == 0)
 	  return __xstat_conv (vers, &kbuf, buf);
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+	return __syscall_error (r);
       }
     }
 }
diff --git a/sysdeps/unix/sysv/linux/arc/sysdep.c b/sysdeps/unix/sysv/linux/arc/sysdep.c
index f33d646798..fe904d723b 100644
--- a/sysdeps/unix/sysv/linux/arc/sysdep.c
+++ b/sysdeps/unix/sysv/linux/arc/sysdep.c
@@ -16,9 +16,11 @@ 
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
 #include <errno.h>
 
+extern long int __syscall_error (long int);
+libc_hidden_proto (__syscall_error)
+
 /* All syscall handlers land here to avoid generated code bloat due to
    GOT reference  to errno_location or it's equivalent.  */
 long int
@@ -28,6 +30,4 @@  __syscall_error (long int err_no)
   return -1;
 }
 
-#if IS_IN (libc)
-hidden_def (__syscall_error)
-#endif
+libc_hidden_def (__syscall_error)
diff --git a/sysdeps/unix/sysv/linux/arc/sysdep.h b/sysdeps/unix/sysv/linux/arc/sysdep.h
index 8465a2f623..4ab44f6925 100644
--- a/sysdeps/unix/sysv/linux/arc/sysdep.h
+++ b/sysdeps/unix/sysv/linux/arc/sysdep.h
@@ -134,11 +134,6 @@  L (call_syscall_err):			ASM_LINE_SEP	\
 
 # define SINGLE_THREAD_BY_GLOBAL		1
 
-# if IS_IN (libc)
-extern long int __syscall_error (long int);
-hidden_proto (__syscall_error)
-# endif
-
 # define ARC_TRAP_INSN	"trap_s 0	\n\t"
 
 # undef INTERNAL_SYSCALL_NCS
diff --git a/sysdeps/unix/sysv/linux/faccessat.c b/sysdeps/unix/sysv/linux/faccessat.c
index 5d078371b5..a54cc65767 100644
--- a/sysdeps/unix/sysv/linux/faccessat.c
+++ b/sysdeps/unix/sysv/linux/faccessat.c
@@ -34,7 +34,7 @@  faccessat (int fd, const char *file, int mode, int flag)
     return ret;
 
   if (flag & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS))
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   if ((flag == 0 || ((flag & ~AT_EACCESS) == 0 && ! __libc_enable_secure)))
     return INLINE_SYSCALL (faccessat, 3, fd, file, mode);
@@ -70,6 +70,6 @@  faccessat (int fd, const char *file, int mode, int flag)
   if (granted == mode)
     return 0;
 
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EACCES);
+  return __syscall_error (-EACCES);
 #endif /* !__ASSUME_FACCESSAT2 */
 }
diff --git a/sysdeps/unix/sysv/linux/fchmodat.c b/sysdeps/unix/sysv/linux/fchmodat.c
index 5531f1aa6f..f1408b6f6a 100644
--- a/sysdeps/unix/sysv/linux/fchmodat.c
+++ b/sysdeps/unix/sysv/linux/fchmodat.c
@@ -31,7 +31,7 @@  fchmodat (int fd, const char *file, mode_t mode, int flag)
   if (flag == 0)
     return INLINE_SYSCALL (fchmodat, 3, fd, file, mode);
   else if (flag != AT_SYMLINK_NOFOLLOW)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
   else
     {
       /* The kernel system call does not have a mode argument.
diff --git a/sysdeps/unix/sysv/linux/fcntl_nocancel.c b/sysdeps/unix/sysv/linux/fcntl_nocancel.c
index a16fc75cb7..2e2ae72a9d 100644
--- a/sysdeps/unix/sysv/linux/fcntl_nocancel.c
+++ b/sysdeps/unix/sysv/linux/fcntl_nocancel.c
@@ -56,7 +56,7 @@  __fcntl64_nocancel_adjusted (int fd, int cmd, void *arg)
       if (!syscall_error (res))
 	return fex.type == F_OWNER_GID ? -fex.pid : fex.pid;
 
-      return INLINE_SYSCALL_ERROR_RETURN_VALUE (-res);
+      return __syscall_error (res);
     }
 
   return INLINE_SYSCALL_CALL (fcntl64, fd, cmd, (void *) arg);
diff --git a/sysdeps/unix/sysv/linux/fstatat.c b/sysdeps/unix/sysv/linux/fstatat.c
index 5ba1b99372..ba58232472 100644
--- a/sysdeps/unix/sysv/linux/fstatat.c
+++ b/sysdeps/unix/sysv/linux/fstatat.c
@@ -35,7 +35,7 @@  __fstatat (int fd, const char *file, struct stat *buf, int flag)
   if (r == 0 && (buf->__st_ino_pad != 0
 		 || buf->__st_size_pad != 0
 		 || buf->__st_blocks_pad != 0))
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+    return __syscall_error (-EOVERFLOW);
 # else
 #  ifdef __NR_fstatat64
   /* Old KABIs with old non-LFS support, e.g. arm, i386, hppa, m68k, mips32,
@@ -47,7 +47,7 @@  __fstatat (int fd, const char *file, struct stat *buf, int flag)
       if (! in_ino_t_range (st64.st_ino)
 	  || ! in_off_t_range (st64.st_size)
 	  || ! in_blkcnt_t_range (st64.st_blocks))
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	return __syscall_error (-EOVERFLOW);
 
       /* Clear internal pad and reserved fields.  */
       memset (buf, 0, sizeof (*buf));
diff --git a/sysdeps/unix/sysv/linux/fstatat64.c b/sysdeps/unix/sysv/linux/fstatat64.c
index a788940390..831a5b8e54 100644
--- a/sysdeps/unix/sysv/linux/fstatat64.c
+++ b/sysdeps/unix/sysv/linux/fstatat64.c
@@ -47,7 +47,7 @@  __fstatat64_time64 (int fd, const char *file, struct __stat64_t64 *buf,
       return 0;
     }
   if (-r != ENOSYS)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+    return __syscall_error (r);
 #endif
 
 #if XSTAT_IS_XSTAT64
diff --git a/sysdeps/unix/sysv/linux/futimens.c b/sysdeps/unix/sysv/linux/futimens.c
index 2c698b4e85..756a61a935 100644
--- a/sysdeps/unix/sysv/linux/futimens.c
+++ b/sysdeps/unix/sysv/linux/futimens.c
@@ -32,7 +32,7 @@  int
 __futimens64 (int fd, const struct __timespec64 tsp64[2])
 {
   if (fd < 0)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF);
+    return __syscall_error (-EBADF);
 
   return __utimensat64_helper (fd, NULL, &tsp64[0], 0);
 }
diff --git a/sysdeps/unix/sysv/linux/fxstat.c b/sysdeps/unix/sysv/linux/fxstat.c
index 649bb95252..fabf8e66f8 100644
--- a/sysdeps/unix/sysv/linux/fxstat.c
+++ b/sysdeps/unix/sysv/linux/fxstat.c
@@ -52,7 +52,7 @@  __fxstat (int vers, int fd, struct stat *buf)
     default:
       {
 # if STAT_IS_KERNEL_STAT
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+	return __syscall_error (-EINVAL);
 # else
 	struct stat64 buf64;
 	int r = INLINE_SYSCALL_CALL (fstat64, fd, &buf64);
diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
index 4bd926bf01..5a81f87e2a 100644
--- a/sysdeps/unix/sysv/linux/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/fxstat64.c
@@ -50,7 +50,7 @@  ___fxstat64 (int vers, int fd, struct stat64 *buf)
      and x86_64.  */
   if (vers == _STAT_VER_KERNEL || vers == _STAT_VER_LINUX)
     return INLINE_SYSCALL_CALL (fstat, fd, buf);
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 # else
   /* New 32-bit kABIs with only 64-bit time_t support, e.g. arc, riscv32.  */
   struct statx tmp;
diff --git a/sysdeps/unix/sysv/linux/fxstatat.c b/sysdeps/unix/sysv/linux/fxstatat.c
index 2083e18eac..b3a1750e1b 100644
--- a/sysdeps/unix/sysv/linux/fxstatat.c
+++ b/sysdeps/unix/sysv/linux/fxstatat.c
@@ -41,7 +41,7 @@  __fxstatat (int vers, int fd, const char *file, struct stat *st, int flag)
       int r = INLINE_SYSCALL_CALL (fstatat64, fd, file, st, flag);
       return r ?: stat_overflow (st);
     }
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 #else
   /* Old kABIs with old non-LFS support, e.g. arm, i386, hppa, m68k, mips32,
      microblaze, s390, sh, powerpc32, and sparc32.  */
diff --git a/sysdeps/unix/sysv/linux/fxstatat64.c b/sysdeps/unix/sysv/linux/fxstatat64.c
index 8a505451d9..a0bdb137f1 100644
--- a/sysdeps/unix/sysv/linux/fxstatat64.c
+++ b/sysdeps/unix/sysv/linux/fxstatat64.c
@@ -63,7 +63,7 @@  __fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
   if (vers == _STAT_VER_LINUX)
     return INLINE_SYSCALL_CALL (fstatat64, fd, file, st, flag);
 #endif
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 }
 
 compat_symbol (libc, __fxstatat64, __fxstatat64, GLIBC_2_4);
diff --git a/sysdeps/unix/sysv/linux/getdents.c b/sysdeps/unix/sysv/linux/getdents.c
index a76be2e5e7..a5041e4ebb 100644
--- a/sysdeps/unix/sysv/linux/getdents.c
+++ b/sysdeps/unix/sysv/linux/getdents.c
@@ -98,7 +98,7 @@  __getdents (int fd, void *buf0, size_t nbytes)
               __lseek64 (fd, last_offset, SEEK_SET);
               return outp->b - buf;
             }
-	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	  return __syscall_error (-EOVERFLOW);
         }
 
       last_offset = d_off;
diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep.c b/sysdeps/unix/sysv/linux/hppa/sysdep.c
index 8f05bfc9c9..8c06b6fc80 100644
--- a/sysdeps/unix/sysv/linux/hppa/sysdep.c
+++ b/sysdeps/unix/sysv/linux/hppa/sysdep.c
@@ -15,8 +15,6 @@ 
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdarg.h>
-#include <sysdep.h>
 #include <errno.h>
 
 /* This routine is jumped to by all the syscall handlers, to stash
diff --git a/sysdeps/unix/sysv/linux/i386/brk.c b/sysdeps/unix/sysv/linux/i386/brk.c
index 021b6d37a0..900fb0a031 100644
--- a/sysdeps/unix/sysv/linux/i386/brk.c
+++ b/sysdeps/unix/sysv/linux/i386/brk.c
@@ -39,7 +39,7 @@  __brk (void *addr)
   void *newbrk = (void *) INTERNAL_SYSCALL_CALL (brk, addr);
   __curbrk = newbrk;
   if (newbrk < addr)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (ENOMEM);
+    return __syscall_error (-ENOMEM);
   return 0;
 }
 weak_alias (__brk, brk)
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.c b/sysdeps/unix/sysv/linux/i386/sysdep.c
index 0a9058d505..e6228406dd 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.c
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.c
@@ -16,7 +16,6 @@ 
    <https://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
-#include <sysdep.h>
 
 /* This routine is jumped to by all the syscall handlers, to stash
    an error number into errno.  ERROR is the negative error number
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index bfb5de3b45..4680013de4 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -236,9 +236,6 @@ 
 
 #else	/* !__ASSEMBLER__ */
 
-extern int __syscall_error (int)
-  attribute_hidden __attribute__ ((__regparm__ (1)));
-
 #ifndef OPTIMIZE_FOR_GCC_5
 /* We need some help from the assembler to generate optimal code.  We
    define some macros here which later will be used.  */
diff --git a/sysdeps/unix/sysv/linux/lxstat.c b/sysdeps/unix/sysv/linux/lxstat.c
index 913618eab9..c86cfb349a 100644
--- a/sysdeps/unix/sysv/linux/lxstat.c
+++ b/sysdeps/unix/sysv/linux/lxstat.c
@@ -53,7 +53,7 @@  __lxstat (int vers, const char *name, struct stat *buf)
     default:
       {
 # if STAT_IS_KERNEL_STAT
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+	return __syscall_error (-EINVAL);
 # else
 	struct stat64 buf64;
 	int r = INLINE_SYSCALL_CALL (lstat64, name, &buf64);
diff --git a/sysdeps/unix/sysv/linux/lxstat64.c b/sysdeps/unix/sysv/linux/lxstat64.c
index 277b54b305..3e0fb8b25d 100644
--- a/sysdeps/unix/sysv/linux/lxstat64.c
+++ b/sysdeps/unix/sysv/linux/lxstat64.c
@@ -81,7 +81,7 @@  ___lxstat64 (int vers, const char *name, struct stat64 *buf)
 # endif /* STAT_IS_KERNEL_STAT  */
 #endif /* XSTAT_IS_XSTAT64  */
 
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 }
 
 #if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c b/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c
index f40a2c5aa8..6bea711cd0 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c
+++ b/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c
@@ -35,7 +35,7 @@  __fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
       int r = INLINE_SYSCALL_CALL (newfstatat, fd, file, &kst, flag);;
       return r ?: __xstat64_conv (vers, &kst, st);
     }
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 }
 
 compat_symbol (libc, __fxstatat64, __fxstatat64, GLIBC_2_4);
diff --git a/sysdeps/unix/sysv/linux/mknodat.c b/sysdeps/unix/sysv/linux/mknodat.c
index 279a4404f5..aa298483d5 100644
--- a/sysdeps/unix/sysv/linux/mknodat.c
+++ b/sysdeps/unix/sysv/linux/mknodat.c
@@ -28,7 +28,7 @@  __mknodat (int fd, const char *path, mode_t mode, dev_t dev)
      32-bit.  */
   unsigned int k_dev = dev;
   if (k_dev != dev)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   return INLINE_SYSCALL_CALL (mknodat, fd, path, mode, k_dev);
 }
diff --git a/sysdeps/unix/sysv/linux/mmap.c b/sysdeps/unix/sysv/linux/mmap.c
index 22f276bb14..9952625219 100644
--- a/sysdeps/unix/sysv/linux/mmap.c
+++ b/sysdeps/unix/sysv/linux/mmap.c
@@ -36,7 +36,7 @@  __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
   MMAP_CHECK_PAGE_UNIT ();
 
   if (offset & MMAP_OFF_LOW_MASK)
-    return (void *) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return (void *) __syscall_error (-EINVAL);
 
 #ifdef __NR_mmap2
   return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, fd,
diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c
index 8074deb466..0eed429e48 100644
--- a/sysdeps/unix/sysv/linux/mmap64.c
+++ b/sysdeps/unix/sysv/linux/mmap64.c
@@ -49,7 +49,7 @@  __mmap64 (void *addr, size_t len, int prot, int flags, int fd, off64_t offset)
   MMAP_CHECK_PAGE_UNIT ();
 
   if (offset & MMAP_OFF_MASK)
-    return (void *) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return (void *) __syscall_error (-EINVAL);
 
   MMAP_PREPARE (addr, len, prot, flags, fd, offset);
 #ifdef __NR_mmap2
diff --git a/sysdeps/unix/sysv/linux/mq_open.c b/sysdeps/unix/sysv/linux/mq_open.c
index c88dc580e4..542f9b7097 100644
--- a/sysdeps/unix/sysv/linux/mq_open.c
+++ b/sysdeps/unix/sysv/linux/mq_open.c
@@ -33,7 +33,7 @@  mqd_t
 __mq_open (const char *name, int oflag, ...)
 {
   if (name[0] != '/')
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   mode_t mode = 0;
   struct mq_attr *attr = NULL;
diff --git a/sysdeps/unix/sysv/linux/mq_unlink.c b/sysdeps/unix/sysv/linux/mq_unlink.c
index 701bc86438..741c4e5776 100644
--- a/sysdeps/unix/sysv/linux/mq_unlink.c
+++ b/sysdeps/unix/sysv/linux/mq_unlink.c
@@ -24,7 +24,7 @@  int
 mq_unlink (const char *name)
 {
   if (name[0] != '/')
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   int ret = INTERNAL_SYSCALL_CALL (mq_unlink, name + 1);
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.c b/sysdeps/unix/sysv/linux/powerpc/sysdep.c
index 37f0f1f53e..1bf5ea6f62 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sysdep.c
+++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.c
@@ -15,7 +15,6 @@ 
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
 #include <errno.h>
 
 /* This routine is jumped to by all the syscall handlers, to stash
diff --git a/sysdeps/unix/sysv/linux/prlimit.c b/sysdeps/unix/sysv/linux/prlimit.c
index e12eb4e9bc..0a8e6a519e 100644
--- a/sysdeps/unix/sysv/linux/prlimit.c
+++ b/sysdeps/unix/sysv/linux/prlimit.c
@@ -58,7 +58,7 @@  prlimit (__pid_t pid, enum __rlimit_resource resource,
 	{
 	  if ((new_rlimit == NULL)
 	      && (old_rlimit64_mem.rlim_cur != RLIM64_INFINITY))
-	    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	    return __syscall_error (-EOVERFLOW);
 	  old_rlimit->rlim_cur = RLIM_INFINITY;
 	}
       old_rlimit->rlim_max = old_rlimit64_mem.rlim_max;
@@ -66,7 +66,7 @@  prlimit (__pid_t pid, enum __rlimit_resource resource,
 	{
 	  if ((new_rlimit == NULL)
 	      && (old_rlimit64_mem.rlim_max != RLIM64_INFINITY))
-	    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	    return __syscall_error (-EOVERFLOW);
 	  old_rlimit->rlim_max = RLIM_INFINITY;
 	}
     }
diff --git a/sysdeps/unix/sysv/linux/setegid.c b/sysdeps/unix/sysv/linux/setegid.c
index ce8bead278..ea135b9084 100644
--- a/sysdeps/unix/sysv/linux/setegid.c
+++ b/sysdeps/unix/sysv/linux/setegid.c
@@ -26,7 +26,7 @@  setegid (gid_t gid)
   int result;
 
   if (gid == (gid_t) ~0)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
 #ifdef __NR_setresgid32
   result = INLINE_SETXID_SYSCALL (setresgid32, 3, -1, gid, -1);
diff --git a/sysdeps/unix/sysv/linux/seteuid.c b/sysdeps/unix/sysv/linux/seteuid.c
index 4519ac2db6..5259adee85 100644
--- a/sysdeps/unix/sysv/linux/seteuid.c
+++ b/sysdeps/unix/sysv/linux/seteuid.c
@@ -26,7 +26,7 @@  seteuid (uid_t uid)
   int result;
 
   if (uid == (uid_t) ~0)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
 #ifdef __NR_setresuid32
   result = INLINE_SETXID_SYSCALL (setresuid32, 3, -1, uid, -1);
diff --git a/sysdeps/unix/sysv/linux/shmat.c b/sysdeps/unix/sysv/linux/shmat.c
index 98291fe972..3a1f483f09 100644
--- a/sysdeps/unix/sysv/linux/shmat.c
+++ b/sysdeps/unix/sysv/linux/shmat.c
@@ -36,7 +36,7 @@  shmat (int shmid, const void *shmaddr, int shmflg)
   resultvar = INTERNAL_SYSCALL_CALL (ipc, IPCOP_shmat, shmid, shmflg,
 				     &raddr, shmaddr);
   if (syscall_error (resultvar))
-    return (void *) INLINE_SYSCALL_ERROR_RETURN_VALUE (-resultvar);
+    return (void *) __syscall_error (resultvar);
 
   return raddr;
 #endif
diff --git a/sysdeps/unix/sysv/linux/speed.c b/sysdeps/unix/sysv/linux/speed.c
index d7d74ddb67..9df2f250c6 100644
--- a/sysdeps/unix/sysv/linux/speed.c
+++ b/sysdeps/unix/sysv/linux/speed.c
@@ -56,7 +56,7 @@  cfsetospeed (struct termios *termios_p, speed_t speed)
 {
   if ((speed & ~CBAUD) != 0
       && (speed < B57600 || speed > __MAX_BAUD))
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
 #if _HAVE_STRUCT_TERMIOS_C_OSPEED
   termios_p->c_ospeed = speed;
@@ -78,7 +78,7 @@  cfsetispeed (struct termios *termios_p, speed_t speed)
 {
   if ((speed & ~CBAUD) != 0
       && (speed < B57600 || speed > __MAX_BAUD))
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
 #if _HAVE_STRUCT_TERMIOS_C_ISPEED
   termios_p->c_ispeed = speed;
diff --git a/sysdeps/unix/sysv/linux/syscall_error.c b/sysdeps/unix/sysv/linux/syscall_error.c
new file mode 100644
index 0000000000..e7818a36da
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/syscall_error.c
@@ -0,0 +1,30 @@ 
+/* Linux wrappers for setting errno.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <errno.h>
+
+#ifdef SYSCALL_ERROR_FUNC
+long int
+SYSCALL_ERROR_FUNC_ATTR
+__syscall_error (long int error)
+{
+  __set_errno (-error);
+  return -1L;
+}
+#endif
diff --git a/sysdeps/unix/sysv/linux/sysdep.h b/sysdeps/unix/sysv/linux/sysdep.h
index 66bac892a5..6c0d1f9f6f 100644
--- a/sysdeps/unix/sysv/linux/sysdep.h
+++ b/sysdeps/unix/sysv/linux/sysdep.h
@@ -30,14 +30,34 @@  syscall_error (unsigned long int val)
   return val > -4096UL;
 }
 
+/* The errno setting might be set either inline or with a helper function.
+   For some ABIs (x86_64 for instance), handling it inline might generate
+   less code; while for others (i686) a function call is preferable.
+
+   To use the helper function the ABI must define SYSCALL_ERROR_FUNC, it will
+   build a hidden function on each shared object that issue direct syscall
+   with {INLINE,INTERNAL}_SYSCALL_CALL.  */
+
+#ifdef SYSCALL_ERROR_FUNC
+# ifndef SYSCALL_ERROR_FUNC_ATTR
+#  define SYSCALL_ERROR_FUNC_ATTR
+# endif
+long int __syscall_error (long int err) attribute_hidden
+  SYSCALL_ERROR_FUNC_ATTR;
+#else
+static inline long int
+__syscall_error (long int err)
+{
+  __set_errno (-err);
+  return -1L;
+}
+#endif
+
 static inline long int
 syscall_ret (unsigned long int val)
 {
   if (syscall_error (val))
-    {
-      __set_errno (-val);
-      return -1;
-    }
+    return __syscall_error (val);
   return val;
 }
 
@@ -49,15 +69,6 @@  syscall_ret (unsigned long int val)
   syscall_ret (INTERNAL_SYSCALL (__VA_ARGS__))
 #endif
 
-/* Set error number and return -1.  A target may choose to return the
-   internal function, __syscall_error, which sets errno and returns -1.
-   We use -1l, instead of -1, so that it can be casted to (void *).  */
-#define INLINE_SYSCALL_ERROR_RETURN_VALUE(err)  \
-  ({						\
-    __set_errno (err);				\
-    -1l;					\
-  })
-
 /* Provide a dummy argument that can be used to force register
    alignment for register pairs if required by the syscall ABI.  */
 #ifdef __ASSUME_ALIGNED_REGISTER_PAIRS
diff --git a/sysdeps/unix/sysv/linux/tcsendbrk.c b/sysdeps/unix/sysv/linux/tcsendbrk.c
index 5d81d86bb2..d77acd064d 100644
--- a/sysdeps/unix/sysv/linux/tcsendbrk.c
+++ b/sysdeps/unix/sysv/linux/tcsendbrk.c
@@ -39,6 +39,6 @@  tcsendbreak (int fd, int duration)
   /* ioctl can't send a break of any other duration for us.
      This could be changed to use trickery (e.g. lower speed and
      send a '\0') to send the break, but for now just return an error.  */
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 #endif
 }
diff --git a/sysdeps/unix/sysv/linux/tcsetattr.c b/sysdeps/unix/sysv/linux/tcsetattr.c
index 50b2b0af8a..978e182e17 100644
--- a/sysdeps/unix/sysv/linux/tcsetattr.c
+++ b/sysdeps/unix/sysv/linux/tcsetattr.c
@@ -58,7 +58,7 @@  __tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
       cmd = TCSETSF;
       break;
     default:
-      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+      return __syscall_error (-EINVAL);
     }
 
   k_termios.c_iflag = termios_p->c_iflag & ~IBAUD0;
diff --git a/sysdeps/unix/sysv/linux/ustat.c b/sysdeps/unix/sysv/linux/ustat.c
index e38b792705..1df6f28794 100644
--- a/sysdeps/unix/sysv/linux/ustat.c
+++ b/sysdeps/unix/sysv/linux/ustat.c
@@ -31,7 +31,7 @@ 
     unsigned long long int k_dev;				\
     k_dev = dev & ((1ULL << 32) - 1);				\
     if (k_dev != dev)						\
-     return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);		\
+     return __syscall_error (-EINVAL);		\
     (unsigned int) k_dev;					\
   })
 # endif
@@ -50,7 +50,7 @@  __old_ustat (dev_t dev, struct ustat *ubuf)
 # ifdef __NR_ustat
   return INLINE_SYSCALL_CALL (ustat, DEV_TO_KDEV (dev), ubuf);
 # else
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (ENOSYS);
+  return __syscall_error (-ENOSYS);
 # endif
 }
 compat_symbol (libc, __old_ustat, ustat, GLIBC_2_0);
diff --git a/sysdeps/unix/sysv/linux/utimensat.c b/sysdeps/unix/sysv/linux/utimensat.c
index aef34916e8..15a40a6174 100644
--- a/sysdeps/unix/sysv/linux/utimensat.c
+++ b/sysdeps/unix/sysv/linux/utimensat.c
@@ -71,7 +71,7 @@  __utimensat64 (int fd, const char *file, const struct __timespec64 tsp64[2],
                int flags)
 {
   if (file == NULL)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   return __utimensat64_helper (fd, file, &tsp64[0], flags);
 }
diff --git a/sysdeps/unix/sysv/linux/xmknod.c b/sysdeps/unix/sysv/linux/xmknod.c
index 10e874a514..c3b31f9c97 100644
--- a/sysdeps/unix/sysv/linux/xmknod.c
+++ b/sysdeps/unix/sysv/linux/xmknod.c
@@ -31,7 +31,7 @@  attribute_compat_text_section
 __xmknod (int vers, const char *path, mode_t mode, dev_t *dev)
 {
   if (vers != _MKNOD_VER)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   return __mknodat (AT_FDCWD, path, mode, *dev);
 }
diff --git a/sysdeps/unix/sysv/linux/xmknodat.c b/sysdeps/unix/sysv/linux/xmknodat.c
index 17ffea16c9..9b2bdd872f 100644
--- a/sysdeps/unix/sysv/linux/xmknodat.c
+++ b/sysdeps/unix/sysv/linux/xmknodat.c
@@ -28,7 +28,7 @@  int
 __xmknodat (int vers, int fd, const char *file, mode_t mode, dev_t *dev)
 {
   if (vers != _MKNOD_VER)
-    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+    return __syscall_error (-EINVAL);
 
   return __mknodat (fd, file, mode, *dev);
 }
diff --git a/sysdeps/unix/sysv/linux/xstat.c b/sysdeps/unix/sysv/linux/xstat.c
index 3eb2d8c51b..1394d6235c 100644
--- a/sysdeps/unix/sysv/linux/xstat.c
+++ b/sysdeps/unix/sysv/linux/xstat.c
@@ -52,7 +52,7 @@  __xstat (int vers, const char *name, struct stat *buf)
     default:
       {
 # if STAT_IS_KERNEL_STAT
-	return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+	return __syscall_error (-EINVAL);
 # else
 	struct stat64 buf64;
 	int r = INLINE_SYSCALL_CALL (stat64, name, &buf64);
diff --git a/sysdeps/unix/sysv/linux/xstat64.c b/sysdeps/unix/sysv/linux/xstat64.c
index dd4f808c7a..06579c9d63 100644
--- a/sysdeps/unix/sysv/linux/xstat64.c
+++ b/sysdeps/unix/sysv/linux/xstat64.c
@@ -78,7 +78,7 @@  ___xstat64 (int vers, const char *name, struct stat64 *buf)
 # endif /* STAT_IS_KERNEL_STAT  */
 #endif /* XSTAT_IS_XSTAT64  */
 
-  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+  return __syscall_error (-EINVAL);
 }
 
 #if XSTAT_IS_XSTAT64
diff --git a/sysdeps/unix/sysv/linux/xstatconv.c b/sysdeps/unix/sysv/linux/xstatconv.c
index b100e07783..552e762fda 100644
--- a/sysdeps/unix/sysv/linux/xstatconv.c
+++ b/sysdeps/unix/sysv/linux/xstatconv.c
@@ -96,7 +96,7 @@  __xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf)
       break;
 
     default:
-      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+      return __syscall_error (-EINVAL);
     }
 
   return 0;
@@ -169,7 +169,7 @@  __xstat64_conv (int vers, struct kernel_stat *kbuf, void *ubuf)
 	 _STAT_VER_KERNEL does not make sense.  */
     case _STAT_VER_KERNEL:
     default:
-      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+      return __syscall_error (-EINVAL);
     }
 
   return 0;
@@ -192,7 +192,7 @@  __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
 	buf->st_ino = kbuf->st_ino;
 	if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
 	    && buf->st_ino != kbuf->st_ino)
-	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	  return __syscall_error (-EOVERFLOW);
 	buf->st_mode = kbuf->st_mode;
 	buf->st_nlink = kbuf->st_nlink;
 	buf->st_uid = kbuf->st_uid;
@@ -205,13 +205,13 @@  __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
 	/* Check for overflow.  */
 	if (sizeof (buf->st_size) != sizeof (kbuf->st_size)
 	    && buf->st_size != kbuf->st_size)
-	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	  return __syscall_error (-EOVERFLOW);
 	buf->st_blksize = kbuf->st_blksize;
 	buf->st_blocks = kbuf->st_blocks;
 	/* Check for overflow.  */
 	if (sizeof (buf->st_blocks) != sizeof (kbuf->st_blocks)
 	    && buf->st_blocks != kbuf->st_blocks)
-	  return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
+	  return __syscall_error (-EOVERFLOW);
 #ifdef _HAVE_STAT_NSEC
 	buf->st_atim.tv_sec = kbuf->st_atim.tv_sec;
 	buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec;
@@ -247,7 +247,7 @@  __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
 	 _STAT_VER_KERNEL does not make sense.  */
     case _STAT_VER_KERNEL:
     default:
-      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+      return __syscall_error (-EINVAL);
     }
 
   return 0;