[v5,00/14] port C-SKY to glibc

Message ID 20181126132348.GA32593@vmh-VirtualBox
State New, archived
Headers

Commit Message

毛晗 Nov. 26, 2018, 1:23 p.m. UTC
  On Mon, Nov 19, 2018 at 04:45:09PM +0000, Joseph Myers wrote:
> As far as I can tell, in the current version of the gcc_AC_INITFINI_ARRAY
> test, the only part that's an execution test is the ia64 case.  That is,
> for every other target, the 'if test "x${build}" = "x${target}" && test
> "x${build}" = "x${host}"' condition is bogus as the rest of the tests
> would work just as well for cross compilation.  (In the ia64 case, the
> fourth argument to AC_RUN_IFELSE - the action if cross compiling - is
> already there.  So simply removing the requirement for build = host =
> target should allow things to work for cross compiling as well as for
> native except on ia64, and someone using ia64 could always fix that case
> later to have better cross compilation defaults based on the target OS.)
>

We'v tried to remove this condition, but seems doesn't meet our expectation.
The ia64 case seems only get a test need to run on the target, return -1 when
init_array is not support. I didn't found any AC_RUN_IFELSE in current gcc 9.0
gcc/configure. The *) case seems can return gcc_cv_initfini_array=yes
on C-SKY target, but it only check whether tools can generate init_array
section, not libc use init_array or not.

On Fri, Nov 23, 2018 at 05:11:35PM +0000, Joseph Myers wrote:
> Since the way in which those platforms avoid using the files in question 
> is through having their own sysdeps override files that either contain 
> just comments or reimplement the functions in question, my suggestion 
> would be to have statx_cp.c files in sysdeps/unix/sysv/linux/wordsize-64 
> and sysdeps/unix/sysv/linux/mips/mips64, containing just a comment.  Then 
> the conditional in the main statx_cp.c file would be

Thanks for suggestion.
I'v tried to add statx_cp.c under sysdeps/unix/sysv/linux/mips/mips64, and
something got wrong while glibc is configured for mips:

PASS: compilers-mips64-linux-gnu-soft glibc mips64-linux-gnu-n64-soft copy
*** Error in `/home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld': free(): invalid next size (fast): 0x000000000250c100 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f45a2d417e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f45a2d4a37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f45a2d4e53c]
/home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld[0x4440c0]
/home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld[0x4926bf]
/home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld[0x467c22]
...
PASS: compilers-mips64-linux-gnu-nan2008-soft glibc mips64-linux-gnu-n64-nan2008-soft configure

The final result is PASS. I haven't found the rootcause yet.

> It's probably a bad idea to duplicate the logic for such overflow checks - 
> rather, the existing stat_overflow code should be used.  Maybe eliminate 
> __cp_stat_statx, make the callers cast to (struct stat64 *) and call 
> __cp_stat64_statx and then use stat_overflow in the callers?  (As all the 
> cases needing this check are in generic/wordsize-32, we know that the stat 
> and stat64 layouts are the same, just differing in whether or not high 
> parts are counted as padding.  Because statx_cp.c is in a separate 
> translation unit and glibc uses C with ABI boundaries, doing the cast in a 
> caller like that is safe, whereas defining __cp_stat_statx to do such a 
> cast, call and then check with stat_overflow, in the same translation unit 
> as the __cp_stat64_statx definition, could run into aliasing issues.)

I used __cp_stat_statx in the last patch, the high part will cut off when
assign a 64bit variable to a 32bit one. The padding seems will never become
non-zero, so I didn't use stat_overflow in last patch. In order to return
whether st_ino, st_size, st_blocks are overflowed, the high part should
be keeped or some check is needed on statx result? So make the callers
cast to (struct stat64 *) and call __cp_stat64_statx will make the funcion
behavior exactly same as the old one?

Best Regards,
Mao Han
  

Comments

Joseph Myers Nov. 26, 2018, 4:49 p.m. UTC | #1
On Mon, 26 Nov 2018, Mao Han wrote:

> We'v tried to remove this condition, but seems doesn't meet our expectation.
> The ia64 case seems only get a test need to run on the target, return -1 when
> init_array is not support. I didn't found any AC_RUN_IFELSE in current gcc 9.0
> gcc/configure. The *) case seems can return gcc_cv_initfini_array=yes
> on C-SKY target, but it only check whether tools can generate init_array
> section, not libc use init_array or not.

Yes, that's right.  init_array is a standard feature of ELF and has been 
for a very long time.  So it's entirely correct that GCC should default to 
using it unless it knows there's a problem with support for that feature 
on some platform, and the present restriction to native builds is wrong.

It's true that removing the restriction to native builds might help show 
up places where libc is missing init_array support.  If it does, we can 
then consider whether some more selective disabling on those platforms 
would be appropriate - but enabling by default for ELF platforms, 
independent of whether native, is still the right thing to do.

> PASS: compilers-mips64-linux-gnu-soft glibc mips64-linux-gnu-n64-soft copy
> *** Error in `/home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld': free(): invalid next size (fast): 0x000000000250c100 ***
> ======= Backtrace: =========
> /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f45a2d417e5]
> /lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f45a2d4a37a]
> /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f45a2d4e53c]
> /home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld[0x4440c0]
> /home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld[0x4926bf]
> /home/vmh/disk2/buildmany/install/compilers/mips64-linux-gnu-soft/lib/gcc/mips64-glibc-linux-gnu/9.0.0/../../../../mips64-glibc-linux-gnu/bin/ld[0x467c22]
> ...
> PASS: compilers-mips64-linux-gnu-nan2008-soft glibc mips64-linux-gnu-n64-nan2008-soft configure
> 
> The final result is PASS. I haven't found the rootcause yet.

That's a known (i.e. observed for years) linker bug, though I've no idea 
where the underlying cause is in binutils.

> I used __cp_stat_statx in the last patch, the high part will cut off when
> assign a 64bit variable to a 32bit one. The padding seems will never become
> non-zero, so I didn't use stat_overflow in last patch. In order to return
> whether st_ino, st_size, st_blocks are overflowed, the high part should
> be keeped or some check is needed on statx result? So make the callers
> cast to (struct stat64 *) and call __cp_stat64_statx will make the funcion
> behavior exactly same as the old one?

Yes, that's my suggestion.  Silent truncation is not acceptable; if 
truncation occurs, it is required to produce an EOVERFLOW error, and it 
seems best to arrange things so that the existing overflow check code can 
be used for that.
  

Patch

From 9bb30a741a5665296997235ed89ced51a23e9048 Mon Sep 17 00:00:00 2001
Message-Id: <9bb30a741a5665296997235ed89ced51a23e9048.1543216869.git.han_mao@c-sky.com>
From: Mao Han <han_mao@c-sky.com>
Date: Mon, 26 Nov 2018 11:13:32 +0800
Subject: [PATCH v3 1/1] Add statx conditionals for wordsize-32 *xstat.c

Linux kernel have remove stat64 family from default syscall set, new
implementations with statx is needed when __ARCH_WANT_STAT64 is not
define. This patch add conditionals for relevant functions, using statx
system call to get information and then copy to the return buf, ref to
include/linux/fs.h from linux kernel.

	* sysdeps/unix/sysv/linux/Makefile: Add statx_cp.c.
	* sysdeps/unix/sysv/linux/fxstat64.c: Add conditionals for kernel
	without stat64 system call support.
	* sysdeps/unix/sysv/linux/fxstatat64.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c: New file.
	* sysdeps/unix/sysv/linux/statx_cp.c: Likewise.
	* sysdeps/unix/sysv/linux/statx_cp.h: Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/statx_cp.c: Likewise.
---
 sysdeps/unix/sysv/linux/Makefile                   |  3 +-
 sysdeps/unix/sysv/linux/fxstat64.c                 | 12 +++++-
 sysdeps/unix/sysv/linux/fxstatat64.c               | 11 +++++
 .../unix/sysv/linux/generic/wordsize-32/fxstat.c   | 11 +++++
 .../unix/sysv/linux/generic/wordsize-32/fxstatat.c | 11 +++++
 .../unix/sysv/linux/generic/wordsize-32/lxstat.c   | 11 +++++
 .../unix/sysv/linux/generic/wordsize-32/lxstat64.c | 19 ++++++++-
 .../unix/sysv/linux/generic/wordsize-32/xstat.c    | 10 +++++
 .../unix/sysv/linux/generic/wordsize-32/xstat64.c  | 14 ++++++-
 sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c     |  3 ++
 sysdeps/unix/sysv/linux/statx_cp.c                 | 49 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/statx_cp.h                 | 23 ++++++++++
 sysdeps/unix/sysv/linux/wordsize-64/statx_cp.c     |  3 ++
 13 files changed, 175 insertions(+), 5 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c
 create mode 100644 sysdeps/unix/sysv/linux/statx_cp.c
 create mode 100644 sysdeps/unix/sysv/linux/statx_cp.h
 create mode 100644 sysdeps/unix/sysv/linux/wordsize-64/statx_cp.c

diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 72b6b64..2943a10 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -177,7 +177,8 @@  sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \
 		   close_nocancel fcntl_nocancel nanosleep_nocancel \
 		   open_nocancel open64_nocancel \
 		   openat_nocancel openat64_nocancel \
-		   pause_nocancel read_nocancel waitpid_nocancel write_nocancel
+		   pause_nocancel read_nocancel waitpid_nocancel \
+		   write_nocancel statx_cp
 
 sysdep_headers += bits/fcntl-linux.h
 
diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
index 0d05389..b0c5271 100644
--- a/sysdeps/unix/sysv/linux/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/fxstat64.c
@@ -1,4 +1,4 @@ 
-/* fxstat64 using Linux fstat64 system call.
+/* fxstat64 using Linux fstat64/statx system call.
    Copyright (C) 1997-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -18,6 +18,7 @@ 
 
 #include <errno.h>
 #include <stddef.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <kernel_stat.h>
 
@@ -25,6 +26,7 @@ 
 #include <sys/syscall.h>
 
 #include <kernel-features.h>
+#include <statx_cp.h>
 
 /* Get information about the file FD in BUF.  */
 
@@ -32,7 +34,15 @@  int
 ___fxstat64 (int vers, int fd, struct stat64 *buf)
 {
   int result;
+#ifdef __NR_fstat64
   result = INLINE_SYSCALL (fstat64, 2, fd, buf);
+#else
+  struct statx tmp;
+  result = INLINE_SYSCALL (statx, 5, fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS,
+                           &tmp);
+  if (result == 0)
+    __cp_stat64_statx (buf, &tmp);
+#endif
 #if defined _HAVE_STAT64___ST_INO && !__ASSUME_ST_INO_64_BIT
   if (__builtin_expect (!result, 1) && buf->__st_ino != (__ino_t) buf->st_ino)
     buf->st_ino = buf->__st_ino;
diff --git a/sysdeps/unix/sysv/linux/fxstatat64.c b/sysdeps/unix/sysv/linux/fxstatat64.c
index baa9a60..767d55c 100644
--- a/sysdeps/unix/sysv/linux/fxstatat64.c
+++ b/sysdeps/unix/sysv/linux/fxstatat64.c
@@ -26,6 +26,8 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include <statx_cp.h>
+
 /* Get information about the file NAME in BUF.  */
 
 int
@@ -37,7 +39,16 @@  __fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
   int result;
   INTERNAL_SYSCALL_DECL (err);
 
+#ifdef __NR_fstatat64
   result = INTERNAL_SYSCALL (fstatat64, err, 4, fd, file, st, flag);
+#else
+  struct statx tmp;
+
+  result = INTERNAL_SYSCALL (statx, err, 5, fd, file, AT_NO_AUTOMOUNT | flag,
+                             STATX_BASIC_STATS, &tmp);
+  if (result == 0)
+    __cp_stat64_statx (st, &tmp);
+#endif
   if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
     return 0;
   else
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
index b5c766d..654c5e0 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
@@ -18,6 +18,7 @@ 
 
 #include <errno.h>
 #include <stddef.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <kernel_stat.h>
@@ -27,6 +28,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include <statx_cp.h>
 
 /* Get information about the file FD in BUF.  */
 int
@@ -34,8 +36,17 @@  __fxstat (int vers, int fd, struct stat *buf)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+# ifdef __NR_fstat64
       int rc = INLINE_SYSCALL (fstat64, 2, fd, buf);
       return rc ?: stat_overflow (buf);
+# else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, fd, "", AT_EMPTY_PATH,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx ((struct stat64 *)buf, &tmp);
+      return rc ?: stat_overflow (buf);
+# endif
     }
 
   errno = EINVAL;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
index 0bda8f7..1b385cc 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
@@ -28,6 +28,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include <statx_cp.h>
 
 /* Get information about the file NAME in BUF.  */
 int
@@ -35,8 +36,18 @@  __fxstatat (int vers, int fd, const char *file, struct stat *buf, int flag)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+# ifdef __NR_fstatat64
       int rc = INLINE_SYSCALL (fstatat64, 4, fd, file, buf, flag);
       return rc ?: stat_overflow (buf);
+# else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, fd, file,
+                               AT_NO_AUTOMOUNT | flag,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx ((struct stat64 *)buf, &tmp);
+      return rc ?: stat_overflow (buf);
+# endif
     }
 
   errno = EINVAL;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
index c278a4d..d6c8824 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
@@ -27,6 +27,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include <statx_cp.h>
 
 /* Get information about the file NAME in BUF.  */
 int
@@ -34,9 +35,19 @@  __lxstat (int vers, const char *name, struct stat *buf)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+#ifdef __NR_fstatat64
       int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
                                AT_SYMLINK_NOFOLLOW);
       return rc ?: stat_overflow (buf);
+#else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name,
+                               AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx ((struct stat64 *)buf, &tmp);
+      return rc ?: stat_overflow (buf);
+#endif
     }
   errno = EINVAL;
   return -1;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
index 761dd16..86b7a98 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
@@ -32,13 +32,28 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include <statx_cp.h>
+
 /* Get information about the file NAME in BUF.  */
 int
 __lxstat64 (int vers, const char *name, struct stat64 *buf)
 {
   if (vers == _STAT_VER_KERNEL)
-    return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
-                           AT_SYMLINK_NOFOLLOW);
+    {
+#ifdef __NR_fstatat64
+      return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
+                             AT_SYMLINK_NOFOLLOW);
+#else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name,
+                               AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx (buf, &tmp);
+      return rc;
+#endif
+    }
+
   errno = EINVAL;
   return -1;
 }
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
index 1fd57ff..753f91e 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
@@ -27,6 +27,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include <statx_cp.h>
 
 /* Get information about the file NAME in BUF.  */
 int
@@ -34,8 +35,17 @@  __xstat (int vers, const char *name, struct stat *buf)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+# ifdef __NR_fstatat64
       int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf, 0);
       return rc ?: stat_overflow (buf);
+# else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name, AT_NO_AUTOMOUNT,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx ((struct stat64 *)buf, &tmp);
+      return rc ?: stat_overflow (buf);
+# endif
     }
 
   errno = EINVAL;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
index ae70495..8b38926 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
@@ -32,13 +32,25 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include <statx_cp.h>
+
 /* Get information about the file NAME in BUF.  */
 int
 __xstat64 (int vers, const char *name, struct stat64 *buf)
 {
   if (vers == _STAT_VER_KERNEL)
+    {
+#ifdef __NR_fstatat64
     return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf, 0);
-
+#else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name, AT_NO_AUTOMOUNT,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx (buf, &tmp);
+      return rc;
+#endif
+    }
   errno = EINVAL;
   return -1;
 }
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c b/sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c
new file mode 100644
index 0000000..260cda9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/mips64/statx_cp.c
@@ -0,0 +1,3 @@ 
+/* Override the generic statx_cp.c which is only needed for new 32-bit arch
+   without stat64 family support.
+ */
diff --git a/sysdeps/unix/sysv/linux/statx_cp.c b/sysdeps/unix/sysv/linux/statx_cp.c
new file mode 100644
index 0000000..04a13fa
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/statx_cp.c
@@ -0,0 +1,49 @@ 
+/* Struct statx to stat/stat64 conversion for Linux.
+   Copyright (C) 2018 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 <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <statx_cp.h>
+
+#if !defined(__NR_fstat64) || !defined(__NR_fstatat64)
+void
+__cp_stat64_statx (struct stat64 *to, struct statx *from)
+{
+  memset (to, 0, sizeof (struct stat64));
+  to->st_dev = ((from->stx_dev_minor & 0xff) | (from->stx_dev_major << 8)
+		| ((from->stx_dev_minor & ~0xff) << 12));
+  to->st_rdev = ((from->stx_rdev_minor & 0xff) | (from->stx_rdev_major << 8)
+		 | ((from->stx_rdev_minor & ~0xff) << 12));
+  to->st_ino = from->stx_ino;
+  to->st_mode = from->stx_mode;
+  to->st_nlink = from->stx_nlink;
+  to->st_uid = from->stx_uid;
+  to->st_gid = from->stx_gid;
+  to->st_atime = from->stx_atime.tv_sec;
+  to->st_atim.tv_nsec = from->stx_atime.tv_nsec;
+  to->st_mtime = from->stx_mtime.tv_sec;
+  to->st_mtim.tv_nsec = from->stx_mtime.tv_nsec;
+  to->st_ctime = from->stx_ctime.tv_sec;
+  to->st_ctim.tv_nsec = from->stx_ctime.tv_nsec;
+  to->st_size = from->stx_size;
+  to->st_blocks = from->stx_blocks;
+  to->st_blksize = from->stx_blksize;
+}
+#endif
diff --git a/sysdeps/unix/sysv/linux/statx_cp.h b/sysdeps/unix/sysv/linux/statx_cp.h
new file mode 100644
index 0000000..7e411a7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/statx_cp.h
@@ -0,0 +1,23 @@ 
+/* Struct statx to stat/stat64 conversion for Linux.
+   Copyright (C) 2018 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/>.  */
+
+extern void __cp_stat_statx (struct stat *to, struct statx *from)
+  attribute_hidden;
+
+extern void __cp_stat64_statx (struct stat64 *to, struct statx *from)
+  attribute_hidden;
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/statx_cp.c b/sysdeps/unix/sysv/linux/wordsize-64/statx_cp.c
new file mode 100644
index 0000000..260cda9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/wordsize-64/statx_cp.c
@@ -0,0 +1,3 @@ 
+/* Override the generic statx_cp.c which is only needed for new 32-bit arch
+   without stat64 family support.
+ */
-- 
2.7.4