Просмотр исходного кода

libc: decide xstatconv by the headers, not by a kconfig flag

nds32 on the mainline asm-generic ABI, built against linux-3.4 headers,
does not link:

  undefined reference to `__xstat32_conv'

The stat wrappers choose their syscall path from the headers (#ifdef
__NR_fstat / __NR_statx / ...), but xstatconv.c -- which holds the
kernel-stat to user-stat conversion those wrappers call on the old
__NR_fstat path -- was compiled only where the kconfig flag
ARCH_HAS_DEPRECATED_SYSCALLS was set.  nds32 does not set it, while
linux-3.4 still has __NR_fstat, so the wrapper took the conversion path
and the converter was never built.

Compile the file unconditionally and let its contents decide, in the same
terms the wrappers use:

  #if defined(__ARCH_HAS_DEPRECATED_SYSCALLS__) \
      || (defined(__NR_fstat) \
          && !(__WORDSIZE == 64 && defined(__NR_newfstatat)))

The first term keeps the classic arches exactly as they were, the second
covers the case above.  The exclusion is needed because 64-bit
asm-generic does define __NR_fstat, but riscv64, aarch64, kvx and tile
take the direct newfstatat path, never call the converters, and have no
kernel_stat in their bits/kernel_stat.h -- compiling the body there
fails.  The prototypes in xstatconv.h carry the same guard.

What is left is an empty translation unit wherever the converters are
unreachable, and the linker drops it: the same set as before, plus the
nds32-on-3.4 case that needs it.

Most of the directory already works this way: compiled unconditionally,
gating itself on __NR_*, so the answer follows the same headers the
wrappers were built against.  xstatconv.c was the odd one out, selected
by a kconfig flag instead, and a flag is what can disagree with them.

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
ramin 3 дней назад
Родитель
Сommit
b5b5ecd1ee

+ 1 - 4
libc/sysdeps/linux/common/Makefile.in

@@ -92,10 +92,7 @@ endif
 # Cancellation points block in this multiplexer and must be unwindable.
 CFLAGS-__socketcall.c = -fasynchronous-unwind-tables
 
-ifneq ($(ARCH_HAS_DEPRECATED_SYSCALLS),y)
-# No conversion is needed for new architectures
-CSRC- += xstatconv.c
-endif
+# xstatconv.c always built (old kernels need it even without ARCH_HAS_DEPRECATED_SYSCALLS)
 # stubbed out in mman.h
 CSRC-$(ARCH_USE_MMU) += msync.c
 # we need these internally: getdomainname.c

+ 13 - 0
libc/sysdeps/linux/common/xstatconv.c

@@ -21,8 +21,19 @@
 
 #include <sys/stat.h>
 #include <string.h>
+#include <sys/syscall.h>
 #include "xstatconv.h"
 
+/* These conversions are only used when the kernel returns the legacy
+   kernel_stat/kernel_stat64 structs, i.e. on arches whose headers still have
+   the old stat syscalls: the classic ARCH_HAS_DEPRECATED_SYSCALLS arches, and
+   a no-deprecated arch built against an old kernel (e.g. nds32 on linux-3.4,
+   which still has __NR_fstat).  Modern asm-generic arches go through
+   statx/fstatat64, never reference these, and have no kernel_stat in their
+   bits/kernel_stat.h -- so compile to nothing there.  */
+#if defined(__ARCH_HAS_DEPRECATED_SYSCALLS__) \
+    || (defined(__NR_fstat) && !(__WORDSIZE == 64 && defined(__NR_newfstatat)))
+
 void __xstat_conv(struct kernel_stat *kbuf, struct stat *buf)
 {
 	/* Convert to current kernel version of `struct stat'. */
@@ -91,3 +102,5 @@ void __xstat64_conv(struct kernel_stat64 *kbuf, struct stat64 *buf)
 	buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec;
 	buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec;
 }
+
+#endif /* __ARCH_HAS_DEPRECATED_SYSCALLS__ || __NR_fstat */

+ 4 - 1
libc/sysdeps/linux/common/xstatconv.h

@@ -23,9 +23,12 @@
  * struct stat should look like.  It turns out that each arch has a different
  * opinion on the subject, and different kernel revs use different names... */
 #include <features.h>
+#include <bits/wordsize.h>
+#include <sys/syscall.h>
 #include <bits/kernel_stat.h>
 
-#ifdef __ARCH_HAS_DEPRECATED_SYSCALLS__
+#if defined(__ARCH_HAS_DEPRECATED_SYSCALLS__) \
+    || (defined(__NR_fstat) && !(__WORDSIZE == 64 && defined(__NR_newfstatat)))
 extern void __xstat_conv(struct kernel_stat *kbuf, struct stat *buf) attribute_hidden;
 extern void __xstat32_conv(struct kernel_stat64 *kbuf, struct stat *buf) attribute_hidden;
 extern void __xstat64_conv(struct kernel_stat64 *kbuf, struct stat64 *buf) attribute_hidden;