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;
