GIT update of https://sourceware.org/git/glibc.git/release/2.36/master from glibc-2.36

diff --git a/Makeconfig b/Makeconfig
index ba70321af1..151f542c27 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -43,6 +43,22 @@ else
 $(error objdir must be defined by the build-directory Makefile)
 endif
 
+# Did we request 'make -s' run? "yes" or "no".
+# Starting from make-4.4 MAKEFLAGS now contains long
+# options like '--shuffle'. To detect presence of 's'
+# we pick first word with short options. Long options
+# are guaranteed to come after whitespace. We use '-'
+# prefix to always have a word before long options
+# even if no short options were passed.
+# Typical MAKEFLAGS values to watch for:
+#   "rs --shuffle=42" (silent)
+#   " --shuffle" (not silent)
+ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),)
+silent-make := no
+else
+silent-make := yes
+endif
+
 # Root of the sysdeps tree.
 sysdep_dir := $(..)sysdeps
 export sysdep_dir := $(sysdep_dir)
@@ -569,10 +585,13 @@ link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
 # before the expansion of LDLIBS-* variables).
 
 # Tests use -Wl,-rpath instead of -Wl,-rpath-link for
-# build-hardcoded-path-in-tests.
+# build-hardcoded-path-in-tests.  Add -Wl,--disable-new-dtags to force
+# DT_RPATH instead of DT_RUNPATH which only applies to DT_NEEDED entries
+# in the executable and doesn't applies to DT_NEEDED entries in shared
+# libraries which are loaded via DT_NEEDED entries in the executable.
 ifeq (yes,$(build-hardcoded-path-in-tests))
-link-libc-tests-rpath-link = $(link-libc-rpath)
-link-test-modules-rpath-link = $(link-libc-rpath)
+link-libc-tests-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
+link-test-modules-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
 else
 link-libc-tests-rpath-link = $(link-libc-rpath-link)
 link-test-modules-rpath-link =
@@ -868,7 +887,7 @@ endif
 # Use 64 bit time_t support for installed programs
 installed-modules = nonlib nscd lddlibc4 ldconfig locale_programs \
 		    iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \
-		    libutil libpcprofile libSegFault
+		    libutil libpcprofile libSegFault libnsl
 +extra-time-flags = $(if $(filter $(installed-modules),\
                            $(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64)
 
@@ -917,7 +936,7 @@ endif
 # umpteen zillion filenames along with it (we use `...' instead)
 # but we don't want this echoing done when the user has said
 # he doesn't want to see commands echoed by using -s.
-ifneq	"$(findstring s,$(MAKEFLAGS))" ""	# if -s
+ifeq ($(silent-make),yes)			# if -s
 +cmdecho	:= echo >/dev/null
 else						# not -s
 +cmdecho	:= echo
diff --git a/Makerules b/Makerules
index d1e139d03c..09c0cf8357 100644
--- a/Makerules
+++ b/Makerules
@@ -794,7 +794,7 @@ endif
 # Maximize efficiency by minimizing the number of rules.
 .SUFFIXES:	# Clear the suffix list.  We don't use suffix rules.
 # Don't define any builtin rules.
-MAKEFLAGS := $(MAKEFLAGS)r
+MAKEFLAGS := $(MAKEFLAGS) -r
 
 # Generic rule for making directories.
 %/:
@@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r
 .PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
 
 # Use the verbose option of ar and tar when not running silently.
-ifeq	"$(findstring s,$(MAKEFLAGS))" ""	# if not -s
+ifeq ($(silent-make),no)			# if not -s
 verbose := v
 else	   					# -s
 verbose	:=
diff --git a/NEWS b/NEWS
index f61e521fc8..60ac79f4e6 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,117 @@ See the end for copying conditions.
 Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
 using `glibc' in the "product" field.
 
+Version 2.36.1
+
+Major new features:
+
+* The getent tool now supports the --no-addrconfig option. The output of
+  getent with --no-addrconfig may contain addresses of families not
+  configured on the current host i.e. as-if you had not passed
+  AI_ADDRCONFIG to getaddrinfo calls.
+
+Deprecated and removed features, and other changes affecting compatibility:
+
+* __rseq_size now denotes the size of the active rseq area (20 bytes
+  initially), not the size of struct rseq (32 bytes initially).
+
+Security related changes:
+
+  CVE-2022-39046: When the syslog function is passed a crafted input
+  string larger than 1024 bytes, it reads uninitialized memory from the
+  heap and prints it to the target log file, potentially revealing a
+  portion of the contents of the heap.
+
+  CVE-2023-4527: If the system is configured in no-aaaa mode via
+  /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address
+  family, and a DNS response is received over TCP that is larger than
+  2048 bytes, getaddrinfo may potentially disclose stack contents via
+  the returned address data, or crash.
+
+  CVE-2023-4806: When an NSS plugin only implements the
+  _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use
+  memory that was freed during buffer resizing, potentially causing a
+  crash or read or write to arbitrary memory.
+
+  CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when
+  an application calls getaddrinfo for AF_INET6 with AI_CANONNAME,
+  AI_ALL and AI_V4MAPPED flags set.
+
+  CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the
+  environment of a setuid program and NAME is valid, it may result in a
+  buffer overflow, which could be exploited to achieve escalated
+  privileges.  This flaw was introduced in glibc 2.34.
+
+  CVE-2025-0395: When the assert() function fails, it does not allocate
+  enough space for the assertion failure message string and size
+  information, which may lead to a buffer overflow if the message string
+  size aligns to page size.
+
+The following bugs are resolved with this release:
+
+  [12154] Do not fail DNS resolution for CNAMEs which are not host names
+  [20975] Deferred cancellation triggers in __check_pf and looses lock leading to deadlock
+  [24816] Fix tst-nss-files-hosts-long on single-stack hosts
+  [27576] gmon: improve mcount overflow handling
+  [27821] ungetc: Fix backup buffer leak on program exit
+  [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
+  [29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS
+  [29444] gmon: Fix allocated buffer overflow (bug 29444)
+  [29864] libc: __libc_start_main() should obtain program headers
+    address (_dl_phdr) from the auxv, not the ELF header.
+  [29305] Conserve NSS buffer space during DNS packet parsing
+  [29402] nscd: nscd: No such file or directory
+  [29415] nscd: Fix netlink cache invalidation if epoll is used
+  [28937] New DSO dependency sorter does not put new map first if in a cycle
+  [29446] _dlopen now ignores dl_caller argument in static mode
+  [29485] Linux: Terminate subprocess on late failure in tst-pidfd
+  [29490] alpha: New __brk_call implementation is broken
+  [29463] math/test-float128-y1 fails on x86_64
+  [29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2
+    or higher
+  [29528] elf: Call __libc_early_init for reused namespaces
+  [29537] libc: [2.34 regression]: Alignment issue on m68k when using
+  [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are
+  [29576] build: librtld.os: in function `_dl_start_profile':
+    (.text+0x9444): undefined reference to `strcpy'
+  [29583] Use 64-bit interfaces in gconv_parseconfdir
+  [29600] Do not completely clear reused namespace in dlmopen
+  [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is
+    enabled
+  [29638] libc: stdlib: arc4random fallback is never used
+  [29657] libc: Incorrect struct stat for 64-bit time on linux/generic
+    platforms
+  [29730] broken y2038 support in fstatat on MIPS N64
+  [29771] Restore IPC_64 support in sysvipc *ctl functions
+  [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10
+  [29951] time: Set daylight to 1 for matching DST/offset change
+  [30053] time: strftime %s returns -1 after 2038 on 32 bits systems
+  [30081] resolv: Do not wait for non-existing second DNS response after error
+  [30101] gmon: fix memory corruption issues
+  [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling
+  [30163] posix: Fix system blocks SIGCHLD erroneously
+  [30305] x86_64: Fix asm constraints in feraiseexcept
+  [30477] libc: [RISCV]: time64 does not work on riscv32
+  [30515] _dl_find_object incorrectly returns 1 during early startup
+  [30745] Slight bug in cache info codes for x86
+  [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with
+    -D_FILE_OFFSET_BITS=64
+  [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527)
+  [30843] potential use-after-free in getcanonname (CVE-2023-4806)
+  [31184] FAIL: elf/tst-tlsgap
+  [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic
+  [31476] resolv: Track single-request fallback via _res._flags
+  [31890] resolv: Allow short error responses to match any DNS query
+  [31965] rseq extension mechanism does not work as intended
+  [31968] mremap implementation in C does not handle arguments correctly
+  [32052] Name space violation in fortify wrappers
+  [32137] libio: Attempt wide backup free only for non-legacy code
+  [32231] elf: Change ldconfig auxcache magic number
+  [32470] x86: Avoid integer truncation with large cache sizes
+  [32582] Fix underallocation of abort_msg_s struct (CVE-2025-0395)
+  [32987] elf: Fix subprocess status handling for tst-dlopen-sgid
+  [33185] Fix double-free after allocation failure in regcomp
+
 Version 2.36
 
 Major new features:
diff --git a/assert/Makefile b/assert/Makefile
index f7cf8e9b77..df5a8e6f10 100644
--- a/assert/Makefile
+++ b/assert/Makefile
@@ -22,10 +22,23 @@ subdir	:= assert
 
 include ../Makeconfig
 
-headers	:= assert.h
-
-routines := assert assert-perr __assert
-tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++
+headers := \
+  assert.h
+  # headers
+
+routines := \
+  __assert \
+  assert \
+  assert-perr \
+  # routines
+
+tests := \
+  test-assert \
+  test-assert-perr \
+  tst-assert-c++ \
+  tst-assert-g++ \
+  tst-assert-sa-2025-0001 \
+  # tests
 
 ifeq ($(have-cxx-thread_local),yes)
 CFLAGS-tst-assert-c++.o = -std=c++11
@@ -33,7 +46,10 @@ LDLIBS-tst-assert-c++ = -lstdc++
 CFLAGS-tst-assert-g++.o = -std=gnu++11
 LDLIBS-tst-assert-g++ = -lstdc++
 else
-tests-unsupported += tst-assert-c++ tst-assert-g++
+tests-unsupported += \
+  tst-assert-c++ \
+  tst-assert-g++ \
+  # tests-unsupported
 endif
 
 include ../Rules
diff --git a/assert/assert.c b/assert/assert.c
index 133a183bc3..9e55eeb473 100644
--- a/assert/assert.c
+++ b/assert/assert.c
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <atomic.h>
 #include <ldsodefs.h>
+#include <libc-pointer-arith.h>
 #include <libintl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -64,7 +65,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
       (void) __fxprintf (NULL, "%s", str);
       (void) fflush (stderr);
 
-      total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+      total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+			GLRO(dl_pagesize));
       struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
 					MAP_ANON | MAP_PRIVATE, -1, 0);
       if (__glibc_likely (buf != MAP_FAILED))
diff --git a/assert/tst-assert-sa-2025-0001.c b/assert/tst-assert-sa-2025-0001.c
new file mode 100644
index 0000000000..102cb0078d
--- /dev/null
+++ b/assert/tst-assert-sa-2025-0001.c
@@ -0,0 +1,92 @@
+/* Test for CVE-2025-0395.
+   Copyright The GNU Toolchain Authors.
+   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/>.  */
+
+/* Test that a large enough __progname does not result in a buffer overflow
+   when printing an assertion failure.  This was CVE-2025-0395.  */
+#include <assert.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+extern const char *__progname;
+
+int
+do_test (int argc, char **argv)
+{
+
+  support_need_proc ("Reads /proc/self/maps to add guards to writable maps.");
+  ignore_stderr ();
+
+  /* XXX assumes that the assert is on a 2 digit line number.  */
+  const char *prompt = ": %s:99: do_test: Assertion `argc < 1' failed.\n";
+
+  int ret = fprintf (stderr, prompt, __FILE__);
+  if (ret < 0)
+    FAIL_EXIT1 ("fprintf failed: %m\n");
+
+  size_t pagesize = getpagesize ();
+  size_t namesize = pagesize - 1 - ret;
+
+  /* Alter the progname so that the assert message fills the entire page.  */
+  char progname[namesize];
+  memset (progname, 'A', namesize - 1);
+  progname[namesize - 1] = '\0';
+  __progname = progname;
+
+  FILE *f = xfopen ("/proc/self/maps", "r");
+  char *line = NULL;
+  size_t len = 0;
+  uintptr_t prev_to = 0;
+
+  /* Pad the beginning of every writable mapping with a PROT_NONE map.  This
+     ensures that the mmap in the assert_fail path never ends up below a
+     writable map and will terminate immediately in case of a buffer
+     overflow.  */
+  while (xgetline (&line, &len, f))
+    {
+      uintptr_t from, to;
+      char perm[4];
+
+      sscanf (line, "%" SCNxPTR "-%" SCNxPTR " %c%c%c%c ",
+	      &from, &to,
+	      &perm[0], &perm[1], &perm[2], &perm[3]);
+
+      bool writable = (memchr (perm, 'w', 4) != NULL);
+
+      if (prev_to != 0 && from - prev_to > pagesize && writable)
+	xmmap ((void *) from - pagesize, pagesize, PROT_NONE,
+	       MAP_ANONYMOUS | MAP_PRIVATE, 0);
+
+      prev_to = to;
+    }
+
+  xfclose (f);
+
+  assert (argc < 1);
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGABRT
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/bits/socket.h b/bits/socket.h
index 2b99dea33b..aac8c49b00 100644
--- a/bits/socket.h
+++ b/bits/socket.h
@@ -245,6 +245,12 @@ struct cmsghdr
 			 + CMSG_ALIGN (sizeof (struct cmsghdr)))
 #define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
 
+/* Given a length, return the additional padding necessary such that
+   len + __CMSG_PADDING(len) == CMSG_ALIGN (len).  */
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
+                              - ((len) & (sizeof (size_t) - 1))) \
+                             & (sizeof (size_t) - 1))
+
 extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
 				      struct cmsghdr *__cmsg) __THROW;
 #ifdef __USE_EXTERN_INLINES
@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
 _EXTERN_INLINE struct cmsghdr *
 __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
 {
+  /* We may safely assume that __cmsg lies between __mhdr->msg_control and
+     __mhdr->msg_controllen because the user is required to obtain the first
+     cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
+     via CMSG_NXTHDR, setting lengths along the way.  However, we don't yet
+     trust the value of __cmsg->cmsg_len and therefore do not use it in any
+     pointer arithmetic until we check its value.  */
+
+  unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
+  unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
+
+  size_t __size_needed = sizeof (struct cmsghdr)
+                         + __CMSG_PADDING (__cmsg->cmsg_len);
+
+  /* The current header is malformed, too small to be a full header.  */
   if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-    /* The kernel header does this so there may be a reason.  */
     return (struct cmsghdr *) 0;
 
+  /* There isn't enough space between __cmsg and the end of the buffer to
+  hold the current cmsg *and* the next one.  */
+  if (((size_t)
+         (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
+       < __size_needed)
+      || ((size_t)
+            (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
+             - __size_needed)
+          < __cmsg->cmsg_len))
+
+    return (struct cmsghdr *) 0;
+
+  /* Now, we trust cmsg_len and can use it to find the next header.  */
   __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
 			       + CMSG_ALIGN (__cmsg->cmsg_len));
-  if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-					+ __mhdr->msg_controllen)
-      || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-	  > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-    /* No more entries.  */
-    return (struct cmsghdr *) 0;
   return __cmsg;
 }
 #endif	/* Use `extern inline'.  */
diff --git a/bits/wordsize.h b/bits/wordsize.h
index 14edae3a11..53013a9275 100644
--- a/bits/wordsize.h
+++ b/bits/wordsize.h
@@ -21,7 +21,9 @@
 #define __WORDSIZE32_PTRDIFF_LONG
 
 /* Set to 1 in order to force time types to be 32 bits instead of 64 bits in
-   struct lastlog and struct utmp{,x} on 64-bit ports.  This may be done in
+   struct lastlog and struct utmp{,x}.  This may be done in
    order to make 64-bit ports compatible with 32-bit ports.  Set to 0 for
-   64-bit ports where the time types are 64-bits or for any 32-bit ports.  */
+   64-bit ports where the time types are 64-bits and new 32-bit ports
+   where time_t is 64 bits, and there is no companion architecture with
+   32-bit time_t.  */
 #define __WORDSIZE_TIME64_COMPAT32
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 543560f36c..bfeee6d851 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -262,28 +262,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
   }
 #  endif
   _dl_aux_init (auxvec);
-  if (GL(dl_phdr) == NULL)
 # endif
-    {
-      /* Starting from binutils-2.23, the linker will define the
-         magic symbol __ehdr_start to point to our own ELF header
-         if it is visible in a segment that also includes the phdrs.
-         So we can set up _dl_phdr and _dl_phnum even without any
-         information from auxv.  */
-
-      extern const ElfW(Ehdr) __ehdr_start
-# if BUILD_PIE_DEFAULT
-	__attribute__ ((visibility ("hidden")));
-# else
-	__attribute__ ((weak, visibility ("hidden")));
-      if (&__ehdr_start != NULL)
-# endif
-        {
-          assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr));
-          GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
-          GL(dl_phnum) = __ehdr_start.e_phnum;
-        }
-    }
 
   __tunables_init (__environ);
 
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
index 0a216c5502..7fdf7cd7a8 100644
--- a/csu/libc-tls.c
+++ b/csu/libc-tls.c
@@ -118,19 +118,18 @@ __libc_setup_tls (void)
   __tls_pre_init_tp ();
 
   /* Look through the TLS segment if there is any.  */
-  if (_dl_phdr != NULL)
-    for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
-      if (phdr->p_type == PT_TLS)
-	{
-	  /* Remember the values we need.  */
-	  memsz = phdr->p_memsz;
-	  filesz = phdr->p_filesz;
-	  initimage = (void *) phdr->p_vaddr + main_map->l_addr;
-	  align = phdr->p_align;
-	  if (phdr->p_align > max_align)
-	    max_align = phdr->p_align;
-	  break;
-	}
+  for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
+    if (phdr->p_type == PT_TLS)
+      {
+	/* Remember the values we need.  */
+	memsz = phdr->p_memsz;
+	filesz = phdr->p_filesz;
+	initimage = (void *) phdr->p_vaddr + main_map->l_addr;
+	align = phdr->p_align;
+	if (phdr->p_align > max_align)
+	  max_align = phdr->p_align;
+	break;
+      }
 
   /* Calculate the size of the static TLS surplus, with 0 auditors.  */
   _dl_tls_static_surplus_init (0);
diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
index 2696dde4b1..9b07b4e132 100644
--- a/dlfcn/dlopen.c
+++ b/dlfcn/dlopen.c
@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
 void *
 __dlopen (const char *file, int mode, void *dl_caller)
 {
-  return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
+  return dlopen_implementation (file, mode, dl_caller);
 }
 
 void *
diff --git a/elf/Makefile b/elf/Makefile
index fd77d0c7c8..3e08a8046d 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -53,6 +53,7 @@ routines = \
 # profiled libraries.
 dl-routines = \
   dl-call-libc-early-init \
+  dl-call_fini \
   dl-close \
   dl-debug \
   dl-debug-symbols \
@@ -176,6 +177,7 @@ CFLAGS-.op += $(call elide-stack-protector,.op,$(elide-routines.os))
 CFLAGS-.os += $(call elide-stack-protector,.os,$(all-rtld-routines))
 
 # Add the requested compiler flags to the early startup code.
+CFLAGS-dl-misc.os += $(rtld-early-cflags)
 CFLAGS-dl-printf.os += $(rtld-early-cflags)
 CFLAGS-dl-setup_hash.os += $(rtld-early-cflags)
 CFLAGS-dl-sysdep.os += $(rtld-early-cflags)
@@ -271,6 +273,7 @@ tests-static-normal := \
   tst-array1-static \
   tst-array5-static \
   tst-dl-iter-static \
+  tst-dlopen-sgid \
   tst-dst-static \
   tst-env-setuid \
   tst-env-setuid-tunables \
@@ -374,6 +377,8 @@ tests += \
   tst-align \
   tst-align2 \
   tst-align3 \
+  tst-audit-tlsdesc \
+  tst-audit-tlsdesc-dlopen \
   tst-audit1 \
   tst-audit2 \
   tst-audit8 \
@@ -408,6 +413,7 @@ tests += \
   tst-dlmopen4 \
   tst-dlmopen-dlerror \
   tst-dlmopen-gethostbyname \
+  tst-dlmopen-twice \
   tst-dlopenfail \
   tst-dlopenfail-2 \
   tst-dlopenrpath \
@@ -435,6 +441,7 @@ tests += \
   tst-p_align1 \
   tst-p_align2 \
   tst-p_align3 \
+  tst-recursive-tls \
   tst-relsort1 \
   tst-ro-dynamic \
   tst-rtld-run-static \
@@ -631,6 +638,7 @@ ifeq ($(run-built-tests),yes)
 tests-special += \
   $(objpfx)noload-mem.out \
   $(objpfx)tst-ldconfig-X.out \
+  $(objpfx)tst-ldconfig-p.out \
   $(objpfx)tst-leaks1-mem.out \
   $(objpfx)tst-rtld-help.out \
   # tests-special
@@ -765,6 +773,8 @@ modules-names += \
   tst-alignmod3 \
   tst-array2dep \
   tst-array5dep \
+  tst-audit-tlsdesc-mod1 \
+  tst-audit-tlsdesc-mod2 \
   tst-audit11mod1 \
   tst-audit11mod2 \
   tst-audit12mod1 \
@@ -798,6 +808,7 @@ modules-names += \
   tst-auditmanymod7 \
   tst-auditmanymod8 \
   tst-auditmanymod9 \
+  tst-auditmod-tlsdesc  \
   tst-auditmod1 \
   tst-auditmod9a \
   tst-auditmod9b \
@@ -834,6 +845,9 @@ modules-names += \
   tst-dlmopen1mod \
   tst-dlmopen-dlerror-mod \
   tst-dlmopen-gethostbyname-mod \
+  tst-dlmopen-twice-mod1 \
+  tst-dlmopen-twice-mod2 \
+  tst-dlopen-sgid-mod \
   tst-dlopenfaillinkmod \
   tst-dlopenfailmod1 \
   tst-dlopenfailmod2 \
@@ -866,6 +880,23 @@ modules-names += \
   tst-null-argv-lib \
   tst-p_alignmod-base \
   tst-p_alignmod3 \
+  tst-recursive-tlsmallocmod \
+  tst-recursive-tlsmod0 \
+  tst-recursive-tlsmod1 \
+  tst-recursive-tlsmod2 \
+  tst-recursive-tlsmod3 \
+  tst-recursive-tlsmod4 \
+  tst-recursive-tlsmod5 \
+  tst-recursive-tlsmod6 \
+  tst-recursive-tlsmod7 \
+  tst-recursive-tlsmod8 \
+  tst-recursive-tlsmod9 \
+  tst-recursive-tlsmod10 \
+  tst-recursive-tlsmod11 \
+  tst-recursive-tlsmod12 \
+  tst-recursive-tlsmod13 \
+  tst-recursive-tlsmod14 \
+  tst-recursive-tlsmod15 \
   tst-relsort1mod1 \
   tst-relsort1mod2 \
   tst-ro-dynamic-mod \
@@ -990,23 +1021,8 @@ modules-names += tst-gnu2-tls1mod
 $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
 tst-gnu2-tls1mod.so-no-z-defs = yes
 CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
+endif # $(have-mtls-dialect-gnu2)
 
-tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen
-modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc
-$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
-			    $(objpfx)tst-audit-tlsdesc-mod2.so \
-			    $(shared-thread-library)
-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
-$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
-				       $(objpfx)tst-audit-tlsdesc-mod2.so
-$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
-$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
-tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
-tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
-endif
 ifeq (yes,$(have-protected-data))
 modules-names += tst-protected1moda tst-protected1modb
 tests += tst-protected1a tst-protected1b
@@ -2410,6 +2426,11 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
 		 '$(run-program-env)' > $@; \
 	$(evaluate-test)
 
+$(objpfx)tst-ldconfig-p.out : tst-ldconfig-p.sh $(objpfx)ldconfig
+	$(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \
+		 '$(run-program-env)' > $@; \
+	$(evaluate-test)
+
 # Test static linking of all the libraries we can possibly link
 # together.  Note that in some configurations this may be less than the
 # complete list of libraries we build but we try to maxmimize this list.
@@ -2967,3 +2988,35 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \
 	grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \
 	  && grep -q '^status: 127$$' $@; \
 	  $(evaluate-test)
+
+$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
+			    $(objpfx)tst-audit-tlsdesc-mod2.so \
+			    $(shared-thread-library)
+ifeq (yes,$(have-mtls-dialect-gnu2))
+# The test is valid for all TLS types, but we want to exercise GNU2
+# TLS if possible.
+CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
+CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
+endif
+$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
+				       $(objpfx)tst-audit-tlsdesc-mod2.so
+$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
+$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
+tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
+tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
+
+$(objpfx)tst-dlmopen-twice.out: \
+  $(objpfx)tst-dlmopen-twice-mod1.so \
+  $(objpfx)tst-dlmopen-twice-mod2.so
+
+$(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so
+# More objects than DTV_SURPLUS, to trigger DTV reallocation.
+$(objpfx)tst-recursive-tls.out: \
+  $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
+    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
+$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
+	$(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
+
+$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
diff --git a/elf/cache.c b/elf/cache.c
index 3d7d3a67bf..528a8ba694 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -845,7 +845,7 @@ struct aux_cache_entry
   struct aux_cache_entry *next;
 };
 
-#define AUX_CACHEMAGIC		"glibc-ld.so.auxcache-1.0"
+#define AUX_CACHEMAGIC		"glibc-ld.so.auxcache-2.0"
 
 struct aux_cache_file_entry
 {
diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index 8bbf110d02..b97c17b3a9 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
      we are accessing. Therefore we must make the copy of the
      mapping data without using malloc.  */
   char *temp;
-  temp = alloca (strlen (best) + 1);
-  strcpy (temp, best);
+  size_t best_len = strlen (best) + 1;
+  temp = alloca (best_len);
+  memcpy (temp, best, best_len);
   return __strdup (temp);
 }
 
diff --git a/elf/dl-call_fini.c b/elf/dl-call_fini.c
new file mode 100644
index 0000000000..9e7ba10fa2
--- /dev/null
+++ b/elf/dl-call_fini.c
@@ -0,0 +1,50 @@
+/* Invoke DT_FINI and DT_FINI_ARRAY callbacks.
+   Copyright (C) 1996-2022 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 <ldsodefs.h>
+#include <sysdep.h>
+
+void
+_dl_call_fini (void *closure_map)
+{
+  struct link_map *map = closure_map;
+
+  /* When debugging print a message first.  */
+  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
+    _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", map->l_name, map->l_ns);
+
+  /* Make sure nothing happens if we are called twice.  */
+  map->l_init_called = 0;
+
+  ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
+  if (fini_array != NULL)
+    {
+      ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr
+                                          + fini_array->d_un.d_ptr);
+      size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+                   / sizeof (ElfW(Addr)));
+
+      while (sz-- > 0)
+        ((fini_t) array[sz]) ();
+    }
+
+  /* Next try the old-style destructor.  */
+  ElfW(Dyn) *fini = map->l_info[DT_FINI];
+  if (fini != NULL)
+    DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
+}
diff --git a/elf/dl-close.c b/elf/dl-close.c
index bcd6e206e9..ef909d8c66 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -36,11 +36,6 @@
 
 #include <dl-unmap-segments.h>
 
-
-/* Type of the constructor functions.  */
-typedef void (*fini_t) (void);
-
-
 /* Special l_idx value used to indicate which objects remain loaded.  */
 #define IDX_STILL_USED -1
 
@@ -110,31 +105,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
   return false;
 }
 
-/* Invoke dstructors for CLOSURE (a struct link_map *).  Called with
-   exception handling temporarily disabled, to make errors fatal.  */
-static void
-call_destructors (void *closure)
-{
-  struct link_map *map = closure;
-
-  if (map->l_info[DT_FINI_ARRAY] != NULL)
-    {
-      ElfW(Addr) *array =
-	(ElfW(Addr) *) (map->l_addr
-			+ map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
-      unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
-			 / sizeof (ElfW(Addr)));
-
-      while (sz-- > 0)
-	((fini_t) array[sz]) ();
-    }
-
-  /* Next try the old-style destructor.  */
-  if (map->l_info[DT_FINI] != NULL)
-    DL_CALL_DT_FINI (map, ((void *) map->l_addr
-			   + map->l_info[DT_FINI]->d_un.d_ptr));
-}
-
 void
 _dl_close_worker (struct link_map *map, bool force)
 {
@@ -280,17 +250,7 @@ _dl_close_worker (struct link_map *map, bool force)
 	     half-cooked objects.  Temporarily disable exception
 	     handling, so that errors are fatal.  */
 	  if (imap->l_init_called)
-	    {
-	      /* When debugging print a message first.  */
-	      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
-				    0))
-		_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
-				  imap->l_name, nsid);
-
-	      if (imap->l_info[DT_FINI_ARRAY] != NULL
-		  || imap->l_info[DT_FINI] != NULL)
-		_dl_catch_exception (NULL, call_destructors, imap);
-	    }
+	    _dl_catch_exception (NULL, _dl_call_fini, imap);
 
 #ifdef SHARED
 	  /* Auditing checkpoint: we remove an object.  */
@@ -743,7 +703,7 @@ _dl_close_worker (struct link_map *map, bool force)
       if (__glibc_unlikely (newgen == 0))
 	_dl_fatal_printf ("TLS generation counter wrapped!  Please report as described in "REPORT_BUGS_TO".\n");
       /* Can be read concurrently.  */
-      atomic_store_relaxed (&GL(dl_tls_generation), newgen);
+      atomic_store_release (&GL(dl_tls_generation), newgen);
 
       if (tls_free_end == GL(dl_tls_static_used))
 	GL(dl_tls_static_used) = tls_free_start;
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 4d5831b6f4..2e5b456c11 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result)
           struct dl_find_object_internal internal;
           _dl_find_object_from_map (l, &internal);
           _dl_find_object_to_external (&internal, result);
-          return 1;
+          return 0;
         }
 
   /* Object not found.  */
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 030b1fcbcd..50ff94db16 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -21,11 +21,6 @@
 #include <ldsodefs.h>
 #include <elf-initfini.h>
 
-
-/* Type of the constructor functions.  */
-typedef void (*fini_t) (void);
-
-
 void
 _dl_fini (void)
 {
@@ -116,38 +111,7 @@ _dl_fini (void)
 
 	      if (l->l_init_called)
 		{
-		  /* Make sure nothing happens if we are called twice.  */
-		  l->l_init_called = 0;
-
-		  /* Is there a destructor function?  */
-		  if (l->l_info[DT_FINI_ARRAY] != NULL
-		      || (ELF_INITFINI && l->l_info[DT_FINI] != NULL))
-		    {
-		      /* When debugging print a message first.  */
-		      if (__builtin_expect (GLRO(dl_debug_mask)
-					    & DL_DEBUG_IMPCALLS, 0))
-			_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
-					  DSO_FILENAME (l->l_name),
-					  ns);
-
-		      /* First see whether an array is given.  */
-		      if (l->l_info[DT_FINI_ARRAY] != NULL)
-			{
-			  ElfW(Addr) *array =
-			    (ElfW(Addr) *) (l->l_addr
-					    + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
-			  unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
-					    / sizeof (ElfW(Addr)));
-			  while (i-- > 0)
-			    ((fini_t) array[i]) ();
-			}
-
-		      /* Next try the old-style destructor.  */
-		      if (ELF_INITFINI && l->l_info[DT_FINI] != NULL)
-			DL_CALL_DT_FINI
-			  (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
-		    }
-
+		  _dl_call_fini (l);
 #ifdef SHARED
 		  /* Auditing checkpoint: another object closed.  */
 		  _dl_audit_objclose (l);
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index 6f161f6ad5..92eb53790e 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
   /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
      and a "/" suffix once stored in the result.  */
   hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
-  size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
+  size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
 		  + hwcaps_counts.total_length);
 
   /* Count the number of bits set in the masked value.  */
@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
   assert (m == cnt);
 
   /* Determine the total size of all strings together.  */
+  size_t total;
   if (cnt == 1)
-    total += temp[0].len + 1;
+    total = temp[0].len + 1;
   else
     {
-      total += temp[0].len + temp[cnt - 1].len + 2;
+      total = temp[0].len + temp[cnt - 1].len + 2;
       if (cnt > 2)
 	{
 	  total <<= 1;
@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
   /* This is the overall result, including both glibc-hwcaps
      subdirectories and the legacy hwcaps subdirectories using the
      power set construction.  */
+  total += hwcaps_sz;
   struct r_strlenpair *overall_result
     = malloc (*sz * sizeof (*result) + total);
   if (overall_result == NULL)
diff --git a/elf/dl-init.c b/elf/dl-init.c
index deefeb099a..fca8e3a05e 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -25,10 +25,14 @@
 static void
 call_init (struct link_map *l, int argc, char **argv, char **env)
 {
+  /* Do not run constructors for proxy objects.  */
+  if (l != l->l_real)
+    return;
+
   /* If the object has not been relocated, this is a bug.  The
      function pointers are invalid in this case.  (Executables do not
-     need relocation, and neither do proxy objects.)  */
-  assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
+     need relocation.)  */
+  assert (l->l_relocated || l->l_type == lt_executable);
 
   if (l->l_init_called)
     /* This object is all done.  */
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 4c86dc694e..67fb2e31e2 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
   if (__glibc_unlikely (current_value.m->l_used == 0))
     current_value.m->l_used = 1;
 
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS))
+   {
+      const char *reference_name = undef_map->l_name;
+
+      _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+			DSO_FILENAME (reference_name),
+			undef_map->l_ns,
+			DSO_FILENAME (current_value.m->l_name),
+			current_value.m->l_ns,
+			protected ? "protected" : "normal", undef_name);
+      if (version)
+	_dl_debug_printf_c (" [%s]\n", version->name);
+      else
+	_dl_debug_printf_c ("\n");
+   }
+
+
   *ref = current_value.s;
   return LOOKUP_VALUE (current_value.m);
 }
diff --git a/elf/dl-open.c b/elf/dl-open.c
index a23e65926b..734a0bee4e 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -405,7 +405,7 @@ update_tls_slotinfo (struct link_map *new)
     _dl_fatal_printf (N_("\
 TLS generation counter wrapped!  Please report this."));
   /* Can be read concurrently.  */
-  atomic_store_relaxed (&GL(dl_tls_generation), newgen);
+  atomic_store_release (&GL(dl_tls_generation), newgen);
 
   /* We need a second pass for static tls data, because
      _dl_update_slotinfo must not be run while calls to
@@ -422,8 +422,8 @@ TLS generation counter wrapped!  Please report this."));
 	     now, but we can delay updating the DTV.  */
 	  imap->l_need_tls_init = 0;
 #ifdef SHARED
-	  /* Update the slot information data for at least the
-	     generation of the DSO we are allocating data for.  */
+	  /* Update the slot information data for the current
+	     generation.  */
 
 	  /* FIXME: This can terminate the process on memory
 	     allocation failure.  It is not possible to raise
@@ -431,7 +431,7 @@ TLS generation counter wrapped!  Please report this."));
 	     _dl_update_slotinfo would have to be split into two
 	     operations, similar to resize_scopes and update_scopes
 	     above.  This is related to bug 16134.  */
-	  _dl_update_slotinfo (imap->l_tls_modid);
+	  _dl_update_slotinfo (imap->l_tls_modid, newgen);
 #endif
 
 	  dl_init_static_tls (imap);
@@ -850,6 +850,7 @@ no more namespaces available for dlmopen()"));
 	  ++GL(dl_nns);
 	}
 
+      GL(dl_ns)[nsid].libc_map = NULL;
       _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
     }
   /* Never allow loading a DSO in a namespace which is empty.  Such
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 756bf950f6..88816a715f 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -112,11 +112,11 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
   if (map->l_real->l_relocated)
     {
 #ifdef SHARED
+      /* Update the DTV of the current thread.  Note: GL(dl_load_tls_lock)
+	 is held here so normal load of the generation counter is valid.  */
       if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
 			    0))
-	/* Update the slot information data for at least the generation of
-	   the DSO we are allocating data for.  */
-	(void) _dl_update_slotinfo (map->l_tls_modid);
+	(void) _dl_update_slotinfo (map->l_tls_modid, GL(dl_tls_generation));
 #endif
 
       dl_init_static_tls (map);
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
index 96638d7ed1..3e2a6a584e 100644
--- a/elf/dl-sort-maps.c
+++ b/elf/dl-sort-maps.c
@@ -27,12 +27,12 @@
    If FOR_FINI is true, this is called for finishing an object.  */
 static void
 _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
-			unsigned int skip, bool for_fini)
+			bool force_first, bool for_fini)
 {
   /* Allows caller to do the common optimization of skipping the first map,
      usually the main binary.  */
-  maps += skip;
-  nmaps -= skip;
+  maps += force_first;
+  nmaps -= force_first;
 
   /* A list of one element need not be sorted.  */
   if (nmaps <= 1)
@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
 
 static void
 _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
-		   unsigned int skip __attribute__ ((unused)), bool for_fini)
+		   bool force_first, bool for_fini)
 {
+  struct link_map *first_map = maps[0];
   for (int i = nmaps - 1; i >= 0; i--)
     maps[i]->l_visited = 0;
 
@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
      Adjusting the order so that maps[0] is last traversed naturally avoids
      this problem.
 
-     Further, the old "optimization" of skipping the main object at maps[0]
-     from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
-     no longer valid, since traversing along object dependency-links
-     may "find" the main object even when it is not included in the initial
-     order (e.g. a dlopen()'ed shared object can have circular dependencies
-     linked back to itself). In such a case, traversing N-1 objects will
-     create a N-object result, and raise problems.
-
      To summarize, just passing in the full list, and iterating from back
      to front makes things much more straightforward.  */
 
@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
     }
 
   memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
+
+  /* Skipping the first object at maps[0] is not valid in general,
+     since traversing along object dependency-links may "find" that
+     first object even when it is not included in the initial order
+     (e.g., a dlopen'ed shared object can have circular dependencies
+     linked back to itself).  In such a case, traversing N-1 objects
+     will create a N-object result, and raise problems.  Instead,
+     force the object back into first place after sorting.  This naive
+     approach may introduce further dependency ordering violations
+     compared to rotating the cycle until the first map is again in
+     the first position, but as there is a cycle, at least one
+     violation is already present.  */
+  if (force_first && maps[0] != first_map)
+    {
+      int i;
+      for (i = 0; maps[i] != first_map; ++i)
+	;
+      assert (i < nmaps);
+      memmove (&maps[1], maps, i * sizeof (maps[0]));
+      maps[0] = first_map;
+    }
 }
 
 void
@@ -286,7 +300,7 @@ _dl_sort_maps_init (void)
 
 void
 _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
-	       unsigned int skip, bool for_fini)
+	       bool force_first, bool for_fini)
 {
   /* It can be tempting to use a static function pointer to store and call
      the current selected sorting algorithm routine, but experimentation
@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
      input cases. A simple if-case with direct function calls appears to
      be the fastest.  */
   if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
-    _dl_sort_maps_original (maps, nmaps, skip, for_fini);
+    _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
   else
-    _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
+    _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
 }
 
 #endif /* HAVE_TUNABLES.  */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 4af0b5b2ce..5c8d1e2428 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -255,6 +255,25 @@ _dl_aux_init (ElfW(auxv_t) *av)
   for (int i = 0; i < array_length (auxv_values); ++i)
     auxv_values[i] = 0;
   _dl_parse_auxv (av, auxv_values);
+
+  _dl_phdr = (void*) auxv_values[AT_PHDR];
+  _dl_phnum = auxv_values[AT_PHNUM];
+
+  if (_dl_phdr == NULL)
+    {
+      /* Starting from binutils-2.23, the linker will define the
+         magic symbol __ehdr_start to point to our own ELF header
+         if it is visible in a segment that also includes the phdrs.
+         So we can set up _dl_phdr and _dl_phnum even without any
+         information from auxv.  */
+
+      extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
+      assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr));
+      _dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
+      _dl_phnum = __ehdr_start.e_phnum;
+    }
+
+  assert (_dl_phdr != NULL);
 }
 #endif
 
@@ -266,8 +285,6 @@ _dl_non_dynamic_init (void)
   _dl_main_map.l_phdr = GL(dl_phdr);
   _dl_main_map.l_phnum = GL(dl_phnum);
 
-  _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
-
   /* Set up the data structures for the system-supplied DSO early,
      so they can influence _dl_init_paths.  */
   setup_vdso (NULL, NULL);
@@ -275,6 +292,22 @@ _dl_non_dynamic_init (void)
   /* With vDSO setup we can initialize the function pointers.  */
   setup_vdso_pointers ();
 
+  if (__libc_enable_secure)
+    {
+      static const char unsecure_envvars[] =
+	UNSECURE_ENVVARS
+	;
+      const char *cp = unsecure_envvars;
+
+      while (cp < unsecure_envvars + sizeof (unsecure_envvars))
+	{
+	  __unsetenv (cp);
+	  cp = strchr (cp, '\0') + 1;
+	}
+    }
+
+  _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
+
   /* Initialize the data structures for the search paths for shared
      objects.  */
   _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH",
@@ -296,25 +329,6 @@ _dl_non_dynamic_init (void)
     _dl_profile_output
       = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
 
-  if (__libc_enable_secure)
-    {
-      static const char unsecure_envvars[] =
-	UNSECURE_ENVVARS
-	;
-      const char *cp = unsecure_envvars;
-
-      while (cp < unsecure_envvars + sizeof (unsecure_envvars))
-	{
-	  __unsetenv (cp);
-	  cp = (const char *) __rawmemchr (cp, '\0') + 1;
-	}
-
-#if !HAVE_TUNABLES
-      if (__access ("/etc/suid-debug", F_OK) != 0)
-	__unsetenv ("MALLOC_CHECK_");
-#endif
-    }
-
 #ifdef DL_PLATFORM_INIT
   DL_PLATFORM_INIT;
 #endif
@@ -323,20 +337,19 @@ _dl_non_dynamic_init (void)
   if (_dl_platform != NULL)
     _dl_platformlen = strlen (_dl_platform);
 
-  if (_dl_phdr != NULL)
-    for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph)
-      switch (ph->p_type)
-	{
-	/* Check if the stack is nonexecutable.  */
-	case PT_GNU_STACK:
-	  _dl_stack_flags = ph->p_flags;
-	  break;
-
-	case PT_GNU_RELRO:
-	  _dl_main_map.l_relro_addr = ph->p_vaddr;
-	  _dl_main_map.l_relro_size = ph->p_memsz;
-	  break;
-	}
+  for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph)
+    switch (ph->p_type)
+      {
+      /* Check if the stack is nonexecutable.  */
+      case PT_GNU_STACK:
+	_dl_stack_flags = ph->p_flags;
+	break;
+
+      case PT_GNU_RELRO:
+	_dl_main_map.l_relro_addr = ph->p_vaddr;
+	_dl_main_map.l_relro_size = ph->p_memsz;
+	break;
+      }
 
   call_function_static_weak (_dl_find_object_init);
 
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 093cdddb7e..c6c2137092 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -75,6 +75,31 @@
 /* Default for dl_tls_static_optional.  */
 #define OPTIONAL_TLS 512
 
+/* Used to count the number of threads currently executing dynamic TLS
+   updates.  Used to avoid recursive malloc calls in __tls_get_addr
+   for an interposed malloc that uses global-dynamic TLS (which is not
+   recommended); see _dl_tls_allocate_active checks.  This could be a
+   per-thread flag, but would need TLS access in the dynamic linker.  */
+unsigned int _dl_tls_threads_in_update;
+
+static inline void
+_dl_tls_allocate_begin (void)
+{
+  atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, 1);
+}
+
+static inline void
+_dl_tls_allocate_end (void)
+{
+  atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, -1);
+}
+
+static inline bool
+_dl_tls_allocate_active (void)
+{
+  return atomic_load_relaxed (&_dl_tls_threads_in_update) > 0;
+}
+
 /* Compute the static TLS surplus based on the namespace count and the
    TLS space that can be used for optimizations.  */
 static inline int
@@ -160,6 +185,7 @@ _dl_assign_tls_modid (struct link_map *l)
 	      {
 		/* Mark the entry as used, so any dependency see it.  */
 		atomic_store_relaxed (&runp->slotinfo[result - disp].map, l);
+		atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0);
 		break;
 	      }
 
@@ -430,12 +456,18 @@ _dl_allocate_tls_storage (void)
   size += TLS_PRE_TCB_SIZE;
 #endif
 
-  /* Perform the allocation.  Reserve space for the required alignment
-     and the pointer to the original allocation.  */
+  /* Reserve space for the required alignment and the pointer to the
+     original allocation.  */
   size_t alignment = GLRO (dl_tls_static_align);
+
+  /* Perform the allocation.  */
+  _dl_tls_allocate_begin ();
   void *allocated = malloc (size + alignment + sizeof (void *));
   if (__glibc_unlikely (allocated == NULL))
-    return NULL;
+    {
+      _dl_tls_allocate_end ();
+      return NULL;
+    }
 
   /* Perform alignment and allocate the DTV.  */
 #if TLS_TCB_AT_TP
@@ -471,6 +503,8 @@ _dl_allocate_tls_storage (void)
   result = allocate_dtv (result);
   if (result == NULL)
     free (allocated);
+
+  _dl_tls_allocate_end ();
   return result;
 }
 
@@ -488,6 +522,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
   size_t newsize = max_modid + DTV_SURPLUS;
   size_t oldsize = dtv[-1].counter;
 
+  _dl_tls_allocate_begin ();
   if (dtv == GL(dl_initial_dtv))
     {
       /* This is the initial dtv that was either statically allocated in
@@ -507,6 +542,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
       if (newp == NULL)
 	oom ();
     }
+  _dl_tls_allocate_end ();
 
   newp[0].counter = newsize;
 
@@ -681,7 +717,9 @@ allocate_dtv_entry (size_t alignment, size_t size)
   if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
     {
       /* The alignment is supported by malloc.  */
+      _dl_tls_allocate_begin ();
       void *ptr = malloc (size);
+      _dl_tls_allocate_end ();
       return (struct dtv_pointer) { ptr, ptr };
     }
 
@@ -693,7 +731,10 @@ allocate_dtv_entry (size_t alignment, size_t size)
 
   /* Perform the allocation.  This is the pointer we need to free
      later.  */
+  _dl_tls_allocate_begin ();
   void *start = malloc (alloc_size);
+  _dl_tls_allocate_end ();
+
   if (start == NULL)
     return (struct dtv_pointer) {};
 
@@ -721,57 +762,57 @@ allocate_and_init (struct link_map *map)
 
 
 struct link_map *
-_dl_update_slotinfo (unsigned long int req_modid)
+_dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
 {
   struct link_map *the_map = NULL;
   dtv_t *dtv = THREAD_DTV ();
 
-  /* The global dl_tls_dtv_slotinfo array contains for each module
-     index the generation counter current when the entry was created.
+  /* CONCURRENCY NOTES:
+
+     The global dl_tls_dtv_slotinfo_list array contains for each module
+     index the generation counter current when that entry was updated.
      This array never shrinks so that all module indices which were
-     valid at some time can be used to access it.  Before the first
-     use of a new module index in this function the array was extended
-     appropriately.  Access also does not have to be guarded against
-     modifications of the array.  It is assumed that pointer-size
-     values can be read atomically even in SMP environments.  It is
-     possible that other threads at the same time dynamically load
-     code and therefore add to the slotinfo list.  This is a problem
-     since we must not pick up any information about incomplete work.
-     The solution to this is to ignore all dtv slots which were
-     created after the one we are currently interested.  We know that
-     dynamic loading for this module is completed and this is the last
-     load operation we know finished.  */
-  unsigned long int idx = req_modid;
+     valid at some time can be used to access it.  Concurrent loading
+     and unloading of modules can update slotinfo entries or extend
+     the array.  The updates happen under the GL(dl_load_tls_lock) and
+     finish with the release store of the generation counter to
+     GL(dl_tls_generation) which is synchronized with the load of
+     new_gen in the caller.  So updates up to new_gen are synchronized
+     but updates for later generations may not be.
+
+     Here we update the thread dtv from old_gen (== dtv[0].counter) to
+     new_gen generation.  For this, each dtv[i] entry is either set to
+     an unallocated state (set), or left unmodified (nop).  Where (set)
+     may resize the dtv first if modid i >= dtv[-1].counter. The rules
+     for the decision between (set) and (nop) are
+
+     (1) If slotinfo entry i is concurrently updated then either (set)
+         or (nop) is valid: TLS access cannot use dtv[i] unless it is
+         synchronized with a generation > new_gen.
+
+     Otherwise, if the generation of slotinfo entry i is gen and the
+     loaded module for this entry is map then
+
+     (2) If gen <= old_gen then do (nop).
+
+     (3) If old_gen < gen <= new_gen then
+         (3.1) if map != 0 then (set)
+         (3.2) if map == 0 then either (set) or (nop).
+
+     Note that (1) cannot be reliably detected, but since both actions
+     are valid it does not have to be.  Only (2) and (3.1) cases need
+     to be distinguished for which relaxed mo access of gen and map is
+     enough: their value is synchronized when it matters.
+
+     Note that a relaxed mo load may give an out-of-thin-air value since
+     it is used in decisions that can affect concurrent stores.  But this
+     should only happen if the OOTA value causes UB that justifies the
+     concurrent store of the value.  This is not expected to be an issue
+     in practice.  */
   struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
 
-  while (idx >= listp->len)
-    {
-      idx -= listp->len;
-      listp = listp->next;
-    }
-
-  if (dtv[0].counter < listp->slotinfo[idx].gen)
+  if (dtv[0].counter < new_gen)
     {
-      /* CONCURRENCY NOTES:
-
-	 Here the dtv needs to be updated to new_gen generation count.
-
-	 This code may be called during TLS access when GL(dl_load_tls_lock)
-	 is not held.  In that case the user code has to synchronize with
-	 dlopen and dlclose calls of relevant modules.  A module m is
-	 relevant if the generation of m <= new_gen and dlclose of m is
-	 synchronized: a memory access here happens after the dlopen and
-	 before the dlclose of relevant modules.  The dtv entries for
-	 relevant modules need to be updated, other entries can be
-	 arbitrary.
-
-	 This e.g. means that the first part of the slotinfo list can be
-	 accessed race free, but the tail may be concurrently extended.
-	 Similarly relevant slotinfo entries can be read race free, but
-	 other entries are racy.  However updating a non-relevant dtv
-	 entry does not affect correctness.  For a relevant module m,
-	 max_modid >= modid of m.  */
-      size_t new_gen = listp->slotinfo[idx].gen;
       size_t total = 0;
       size_t max_modid  = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
       assert (max_modid >= req_modid);
@@ -784,31 +825,33 @@ _dl_update_slotinfo (unsigned long int req_modid)
 	    {
 	      size_t modid = total + cnt;
 
-	      /* Later entries are not relevant.  */
+	      /* Case (1) for all later modids.  */
 	      if (modid > max_modid)
 		break;
 
 	      size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen);
 
+	      /* Case (1).  */
 	      if (gen > new_gen)
-		/* Not relevant.  */
 		continue;
 
-	      /* If the entry is older than the current dtv layout we
-		 know we don't have to handle it.  */
+	      /* Case (2) or (1).  */
 	      if (gen <= dtv[0].counter)
 		continue;
 
+	      /* Case (3) or (1).  */
+
 	      /* If there is no map this means the entry is empty.  */
 	      struct link_map *map
 		= atomic_load_relaxed (&listp->slotinfo[cnt].map);
 	      /* Check whether the current dtv array is large enough.  */
 	      if (dtv[-1].counter < modid)
 		{
+		  /* Case (3.2) or (1).  */
 		  if (map == NULL)
 		    continue;
 
-		  /* Resize the dtv.  */
+		  /* Resizing the dtv aborts on failure: bug 16134.  */
 		  dtv = _dl_resize_dtv (dtv, max_modid);
 
 		  assert (modid <= dtv[-1].counter);
@@ -819,10 +862,21 @@ _dl_update_slotinfo (unsigned long int req_modid)
 		}
 
 	      /* If there is currently memory allocate for this
-		 dtv entry free it.  */
+		 dtv entry free it.  Note: this is not AS-safe.  */
 	      /* XXX Ideally we will at some point create a memory
 		 pool.  */
-	      free (dtv[modid].pointer.to_free);
+	      /* Avoid calling free on a null pointer.  Some mallocs
+		 incorrectly use dynamic TLS, and depending on how the
+		 free function was compiled, it could call
+		 __tls_get_addr before the null pointer check in the
+		 free implementation.  Checking here papers over at
+		 least some dynamic TLS usage by interposed mallocs.  */
+	      if (dtv[modid].pointer.to_free != NULL)
+		{
+		  _dl_tls_allocate_begin ();
+		  free (dtv[modid].pointer.to_free);
+		  _dl_tls_allocate_end ();
+		}
 	      dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
 	      dtv[modid].pointer.to_free = NULL;
 
@@ -914,9 +968,9 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
 
 static struct link_map *
 __attribute_noinline__
-update_get_addr (GET_ADDR_ARGS)
+update_get_addr (GET_ADDR_ARGS, size_t gen)
 {
-  struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+  struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE, gen);
   dtv_t *dtv = THREAD_DTV ();
 
   void *p = dtv[GET_ADDR_MODULE].pointer.val;
@@ -946,12 +1000,29 @@ __tls_get_addr (GET_ADDR_ARGS)
   dtv_t *dtv = THREAD_DTV ();
 
   /* Update is needed if dtv[0].counter < the generation of the accessed
-     module.  The global generation counter is used here as it is easier
-     to check.  Synchronization for the relaxed MO access is guaranteed
-     by user code, see CONCURRENCY NOTES in _dl_update_slotinfo.  */
+     module, but the global generation counter is easier to check (which
+     must be synchronized up to the generation of the accessed module by
+     user code doing the TLS access so relaxed mo read is enough).  */
   size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
   if (__glibc_unlikely (dtv[0].counter != gen))
-    return update_get_addr (GET_ADDR_PARAM);
+    {
+      if (_dl_tls_allocate_active ()
+	  && GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
+	  /* This is a reentrant __tls_get_addr call, but we can
+	     satisfy it because it's an initially-loaded module ID.
+	     These TLS slotinfo slots do not change, so the
+	     out-of-date generation counter does not matter.  However,
+	     if not in a TLS update, still update_get_addr below, to
+	     get off the slow path eventually.  */
+	;
+      else
+	{
+	  /* Update DTV up to the global generation, see CONCURRENCY NOTES
+	     in _dl_update_slotinfo.  */
+	  gen = atomic_load_acquire (&GL(dl_tls_generation));
+	  return update_get_addr (GET_ADDR_PARAM, gen);
+	}
+    }
 
   void *p = dtv[GET_ADDR_MODULE].pointer.val;
 
@@ -960,7 +1031,7 @@ __tls_get_addr (GET_ADDR_ARGS)
 
   return (char *) p + GET_ADDR_OFFSET;
 }
-#endif
+#endif /* SHARED */
 
 
 /* Look up the module's TLS block as for __tls_get_addr,
@@ -1009,6 +1080,25 @@ _dl_tls_get_addr_soft (struct link_map *l)
   return data;
 }
 
+size_t _dl_tls_initial_modid_limit;
+
+void
+_dl_tls_initial_modid_limit_setup (void)
+{
+  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+  size_t idx;
+  for (idx = 0; idx < listp->len; ++idx)
+    {
+      struct link_map *l = listp->slotinfo[idx].map;
+      if (l == NULL
+	  /* The object can be unloaded, so its modid can be
+	     reassociated.  */
+	  || !(l->l_type == lt_executable || l->l_type == lt_library))
+	break;
+    }
+  _dl_tls_initial_modid_limit = idx;
+}
+
 
 void
 _dl_add_to_slotinfo (struct link_map *l, bool do_add)
@@ -1041,9 +1131,11 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
 	 the first slot.  */
       assert (idx == 0);
 
+      _dl_tls_allocate_begin ();
       listp = (struct dtv_slotinfo_list *)
 	malloc (sizeof (struct dtv_slotinfo_list)
 		+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+      _dl_tls_allocate_end ();
       if (listp == NULL)
 	{
 	  /* We ran out of memory while resizing the dtv slotinfo list.  */
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 8e7ee9df10..76cf8b9da3 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -187,11 +187,7 @@ parse_tunables (char *tunestr, char *valstring)
       /* If we reach the end of the string before getting a valid name-value
 	 pair, bail out.  */
       if (p[len] == '\0')
-	{
-	  if (__libc_enable_secure)
-	    tunestr[off] = '\0';
-	  return;
-	}
+	break;
 
       /* We did not find a valid name-value pair before encountering the
 	 colon.  */
@@ -251,9 +247,16 @@ parse_tunables (char *tunestr, char *valstring)
 	    }
 	}
 
-      if (p[len] != '\0')
-	p += len + 1;
+      /* We reached the end while processing the tunable string.  */
+      if (p[len] == '\0')
+	break;
+
+      p += len + 1;
     }
+
+  /* Terminate tunestr before we leave.  */
+  if (__libc_enable_secure)
+    tunestr[off] = '\0';
 }
 #endif
 
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index e6a56b3070..9fa3b484cf 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -169,4 +169,17 @@ glibc {
       default: 2
     }
   }
+
+  gmon {
+    minarcs {
+      type: INT_32
+      minval: 50
+      default: 50
+    }
+    maxarcs {
+      type: INT_32
+      minval: 50
+      default: 1048576
+    }
+  }
 }
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
index 5f7f18ef27..4bf9052db1 100644
--- a/elf/dso-sort-tests-1.def
+++ b/elf/dso-sort-tests-1.def
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
 tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
 output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
 output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
+
+# Test that even in the presence of dependency loops involving dlopen'ed
+# object, that object is initialized last (and not unloaded prematurely).
+# Final destructor order is indeterminate due to the cycle.
+tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
+output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
+output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
diff --git a/elf/elf.h b/elf/elf.h
index 02a1b3f52f..f34d4ef7f4 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1215,6 +1215,9 @@ typedef struct
 #define AT_HWCAP2	26		/* More machine-dependent hints about
 					   processor capabilities.  */
 
+#define AT_RSEQ_FEATURE_SIZE	27	/* rseq supported feature size.  */
+#define AT_RSEQ_ALIGN	28		/* rseq allocation alignment.  */
+
 #define AT_EXECFN	31		/* Filename of executable.  */
 
 /* Pointer to the global system page used for system calls and other
@@ -4085,8 +4088,11 @@ enum
 #define R_NDS32_TLS_DESC	119
 
 /* LoongArch ELF Flags */
-#define EF_LARCH_ABI    	0x07
-#define EF_LARCH_ABI_LP64D	0x03
+#define EF_LARCH_ABI_MODIFIER_MASK  0x07
+#define EF_LARCH_ABI_SOFT_FLOAT     0x01
+#define EF_LARCH_ABI_SINGLE_FLOAT   0x02
+#define EF_LARCH_ABI_DOUBLE_FLOAT   0x03
+#define EF_LARCH_OBJABI_V1          0x40
 
 /* LoongArch specific dynamic relocations */
 #define R_LARCH_NONE		0
diff --git a/elf/ifuncmain1.c b/elf/ifuncmain1.c
index 747fc02648..6effce3d77 100644
--- a/elf/ifuncmain1.c
+++ b/elf/ifuncmain1.c
@@ -19,7 +19,14 @@ typedef int (*foo_p) (void);
 #endif
 
 foo_p foo_ptr = foo;
+
+/* Address-significant access to protected symbols is not supported in
+   position-dependent mode on several architectures because GCC
+   generates relocations that assume that the address is local to the
+   main program.  */
+#ifdef __PIE__
 foo_p foo_procted_ptr = foo_protected;
+#endif
 
 extern foo_p get_foo_p (void);
 extern foo_p get_foo_hidden_p (void);
@@ -37,12 +44,16 @@ main (void)
   if ((*foo_ptr) () != -1)
     abort ();
 
+#ifdef __PIE__
   if (foo_procted_ptr != foo_protected)
     abort ();
+#endif
   if (foo_protected () != 0)
     abort ();
+#ifdef __PIE__
   if ((*foo_procted_ptr) () != 0)
     abort ();
+#endif
 
   p = get_foo_p ();
   if (p != foo)
@@ -55,8 +66,10 @@ main (void)
     abort ();
 
   p = get_foo_protected_p ();
+#ifdef __PIE__
   if (p != foo_protected)
     abort ();
+#endif
   if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
     abort ();
 
diff --git a/elf/ifuncmain5.c b/elf/ifuncmain5.c
index f398085cb4..6fda768fb6 100644
--- a/elf/ifuncmain5.c
+++ b/elf/ifuncmain5.c
@@ -14,12 +14,19 @@ get_foo (void)
   return foo;
 }
 
+
+/* Address-significant access to protected symbols is not supported in
+   position-dependent mode on several architectures because GCC
+   generates relocations that assume that the address is local to the
+   main program.  */
+#ifdef __PIE__
 foo_p
 __attribute__ ((noinline))
 get_foo_protected (void)
 {
   return foo_protected;
 }
+#endif
 
 int
 main (void)
@@ -30,9 +37,11 @@ main (void)
   if ((*p) () != -1)
     abort ();
 
+#ifdef __PIE__
   p = get_foo_protected ();
   if ((*p) () != 0)
     abort ();
+#endif
 
   return 0;
 }
diff --git a/elf/rtld-Rules b/elf/rtld-Rules
index ca00dd1fe2..3c5e273f2b 100644
--- a/elf/rtld-Rules
+++ b/elf/rtld-Rules
@@ -52,7 +52,7 @@ $(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\
 	mv -f $@T $@
 
 # Use the verbose option of ar and tar when not running silently.
-ifeq	"$(findstring s,$(MAKEFLAGS))" ""	# if not -s
+ifeq ($(silent-make),no)			# if not -s
 verbose := v
 else						# -s
 verbose	:=
diff --git a/elf/rtld.c b/elf/rtld.c
index cbbaf4a331..6e40893e52 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -791,6 +791,8 @@ init_tls (size_t naudit)
     _dl_fatal_printf ("\
 cannot allocate TLS data structures for initial thread\n");
 
+  _dl_tls_initial_modid_limit_setup ();
+
   /* Store for detection of the special case by __tls_get_addr
      so it knows not to pass this dtv to the normal realloc.  */
   GL(dl_initial_dtv) = GET_DTV (tcbp);
@@ -2122,6 +2124,12 @@ dl_main (const ElfW(Phdr) *phdr,
 	    if (l->l_faked)
 	      /* The library was not found.  */
 	      _dl_printf ("\t%s => not found\n",  l->l_libname->name);
+	    else if (strcmp (l->l_libname->name, l->l_name) == 0)
+	      /* Print vDSO like libraries without duplicate name.  Some
+		 consumers depend of this format.  */
+	      _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
+			  (int) sizeof l->l_map_start * 2,
+			  (size_t) l->l_map_start);
 	    else
 	      _dl_printf ("\t%s => %s (0x%0*Zx)\n",
 			  DSO_FILENAME (l->l_libname->name),
diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c
index db7ba95abe..9e0a122c38 100644
--- a/elf/tst-auditmod28.c
+++ b/elf/tst-auditmod28.c
@@ -71,6 +71,17 @@ la_version (unsigned int current)
   TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0);
   TEST_VERIFY (extra_info == handle);
 
+  /* Check _dl_find_object.  */
+  struct dl_find_object dlfo;
+  TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0);
+  /* "ld.so" is seen with --enable-hardcoded-path-in-tests.  */
+  if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0)
+    TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO);
+  TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0);
+  TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO);
+  TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1);
+  TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1);
+
   /* Verify that dlmopen creates a new namespace.  */
   void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
   TEST_VERIFY (dlmopen_handle != handle);
diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
new file mode 100644
index 0000000000..0eaf04948c
--- /dev/null
+++ b/elf/tst-dlmopen-twice-mod1.c
@@ -0,0 +1,37 @@
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528).  Module 1.
+   Copyright (C) 2022 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 <stdio.h>
+
+static void __attribute__ ((constructor))
+init (void)
+{
+  puts ("info: tst-dlmopen-twice-mod1.so loaded");
+  fflush (stdout);
+}
+
+static void __attribute__ ((destructor))
+fini (void)
+{
+  puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
+  fflush (stdout);
+}
+
+/* Large allocation.  The second module does not have this, so it
+   should load libc at a different address.  */
+char large_allocate[16 * 1024 * 1024];
diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
new file mode 100644
index 0000000000..40c6c01f96
--- /dev/null
+++ b/elf/tst-dlmopen-twice-mod2.c
@@ -0,0 +1,50 @@
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528).  Module 2.
+   Copyright (C) 2022 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 <ctype.h>
+#include <stdio.h>
+
+static void __attribute__ ((constructor))
+init (void)
+{
+  puts ("info: tst-dlmopen-twice-mod2.so loaded");
+  fflush (stdout);
+}
+
+static void __attribute__ ((destructor))
+fini (void)
+{
+  puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
+  fflush (stdout);
+}
+
+int
+run_check (void)
+{
+  puts ("info: about to call isalpha");
+  fflush (stdout);
+
+  volatile char ch = 'a';
+  if (!isalpha (ch))
+    {
+      puts ("error: isalpha ('a') is not true");
+      fflush (stdout);
+      return 1;
+    }
+  return 0;
+}
diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
new file mode 100644
index 0000000000..70c71fe19c
--- /dev/null
+++ b/elf/tst-dlmopen-twice.c
@@ -0,0 +1,54 @@
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528).  Main.
+   Copyright (C) 2022 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 <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* Run the test multiple times, to check finding a new namespace while
+   another namespace is already in use.  This used to trigger bug 29600.  */
+static void
+recurse (int depth)
+{
+  if (depth == 0)
+    return;
+
+  printf ("info: running at depth %d\n", depth);
+  void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so",
+                           RTLD_NOW);
+  xdlclose (handle);
+  handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
+  int (*run_check) (void) = xdlsym (handle, "run_check");
+  TEST_COMPARE (run_check (), 0);
+  recurse (depth - 1);
+  xdlclose (handle);
+}
+
+static int
+do_test (void)
+{
+  /* First run the test without nesting.  */
+  recurse (1);
+
+  /* Then with nesting.  The constant needs to be less than the
+     internal DL_NNS namespace constant.  */
+  recurse (10);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopen-sgid-mod.c b/elf/tst-dlopen-sgid-mod.c
new file mode 100644
index 0000000000..5eb79eef48
--- /dev/null
+++ b/elf/tst-dlopen-sgid-mod.c
@@ -0,0 +1 @@
+/* Opening this object should not succeed.  */
diff --git a/elf/tst-dlopen-sgid.c b/elf/tst-dlopen-sgid.c
new file mode 100644
index 0000000000..8aec52e19f
--- /dev/null
+++ b/elf/tst-dlopen-sgid.c
@@ -0,0 +1,106 @@
+/* Test case for ignored LD_LIBRARY_PATH in static startug (bug 32976).
+   Copyright (C) 2025 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 <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* This is the name of our test object.  Use a custom module for
+   testing, so that this object does not get picked up from the system
+   path.  */
+static const char dso_name[] = "tst-dlopen-sgid-mod.so";
+
+/* Used to mark the recursive invocation.  */
+static const char magic_argument[] = "run-actual-test";
+
+static int
+do_test (void)
+{
+/* Pathname of the directory that receives the shared objects this
+   test attempts to load.  */
+  char *libdir = support_create_temp_directory ("tst-dlopen-sgid-");
+
+  /* This is supposed to be ignored and stripped.  */
+  TEST_COMPARE (setenv ("LD_LIBRARY_PATH", libdir, 1), 0);
+
+  /* Copy of libc.so.6.  */
+  {
+    char *from = xasprintf ("%s/%s", support_objdir_root, LIBC_SO);
+    char *to = xasprintf ("%s/%s", libdir, LIBC_SO);
+    add_temp_file (to);
+    support_copy_file (from, to);
+    free (to);
+    free (from);
+  }
+
+  /* Copy of the test object.   */
+  {
+    char *from = xasprintf ("%s/elf/%s", support_objdir_root, dso_name);
+    char *to = xasprintf ("%s/%s", libdir, dso_name);
+    add_temp_file (to);
+    support_copy_file (from, to);
+    free (to);
+    free (from);
+  }
+
+  free (libdir);
+
+  support_capture_subprogram_self_sgid (magic_argument);
+
+  return 0;
+}
+
+static void
+alternative_main (int argc, char **argv)
+{
+  if (argc == 2 && strcmp (argv[1], magic_argument) == 0)
+    {
+      if (getgid () == getegid ())
+        /* This can happen if the file system is mounted nosuid.  */
+        FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+                          (intmax_t) getgid ());
+
+      /* Should be removed due to SGID.  */
+      TEST_COMPARE_STRING (getenv ("LD_LIBRARY_PATH"), NULL);
+
+      TEST_VERIFY (dlopen (dso_name, RTLD_NOW) == NULL);
+      {
+        const char *message = dlerror ();
+        TEST_COMPARE_STRING (message,
+                             "tst-dlopen-sgid-mod.so:"
+                             " cannot open shared object file:"
+                             " No such file or directory");
+      }
+
+      support_record_failure_barrier ();
+      exit (EXIT_SUCCESS);
+    }
+}
+
+#define PREPARE alternative_main
+#include <support/test-driver.c>
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index 88182b7b25..bca299bb34 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -52,6 +52,8 @@ const char *teststrings[] =
   "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
   "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
   "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.check=2",
   "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
   "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
   ":glibc.malloc.garbage=2:glibc.malloc.check=1",
@@ -70,6 +72,8 @@ const char *resultstrings[] =
   "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
   "glibc.malloc.mmap_threshold=4096",
   "glibc.malloc.mmap_threshold=4096",
+  "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+  "",
   "",
   "",
   "",
@@ -84,11 +88,18 @@ test_child (int off)
   const char *val = getenv ("GLIBC_TUNABLES");
 
 #if HAVE_TUNABLES
+  printf ("    [%d] GLIBC_TUNABLES is %s\n", off, val);
+  fflush (stdout);
   if (val != NULL && strcmp (val, resultstrings[off]) == 0)
     return 0;
 
   if (val != NULL)
-    printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
+    printf ("    [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n",
+	    off, val, resultstrings[off]);
+  else
+    printf ("    [%d] GLIBC_TUNABLES environment variable absent\n", off);
+
+  fflush (stdout);
 
   return 1;
 #else
@@ -116,32 +127,28 @@ do_test (int argc, char **argv)
 
       if (ret != 0)
 	exit (1);
-
-      exit (EXIT_SUCCESS);
+      return 0;
     }
   else
     {
-      int ret = 0;
-
       /* Spawn tests.  */
       for (int i = 0; i < array_length (teststrings); i++)
 	{
 	  char buf[INT_BUFSIZE_BOUND (int)];
 
-	  printf ("Spawned test for %s (%d)\n", teststrings[i], i);
+	  printf ("[%d] Spawned test for %s\n", i, teststrings[i]);
 	  snprintf (buf, sizeof (buf), "%d\n", i);
+	  fflush (stdout);
 	  if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
-	    exit (1);
-
-	  int status = support_capture_subprogram_self_sgid (buf);
-
-	  /* Bail out early if unsupported.  */
-	  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
-	    return EXIT_UNSUPPORTED;
+	    {
+	      printf ("    [%d] Failed to set GLIBC_TUNABLES: %m", i);
+	      support_record_failure ();
+	      continue;
+	    }
 
-	  ret |= status;
+	  support_capture_subprogram_self_sgid (buf);
 	}
-      return ret;
+      return 0;
     }
 }
 
diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
index 53fc52787d..8ed4d48c26 100644
--- a/elf/tst-env-setuid.c
+++ b/elf/tst-env-setuid.c
@@ -104,20 +104,14 @@ do_test (int argc, char **argv)
       if (ret != 0)
 	exit (1);
 
-      exit (EXIT_SUCCESS);
+      return 0;
     }
   else
     {
       if (test_parent () != 0)
 	exit (1);
 
-      int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
-
-      if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
-	return EXIT_UNSUPPORTED;
-
-      if (!WIFEXITED (status))
-	FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+      support_capture_subprogram_self_sgid (SETGID_CHILD);
 
       return 0;
     }
diff --git a/elf/tst-ldconfig-p.sh b/elf/tst-ldconfig-p.sh
new file mode 100644
index 0000000000..ec937bf4ec
--- /dev/null
+++ b/elf/tst-ldconfig-p.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Test that ldconfig -p prints something useful.
+# Copyright (C) 2023 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/>.
+
+# Check that the newly built ldconfig -p can dump the system
+# /etc/ld.so.cache file.  This should always work even if the ABIs are
+# not compatible, except in a cross-endian build (that presumably
+# involves emulation when running ldconfig).
+
+common_objpfx=$1
+test_wrapper_env=$2
+run_program_env=$3
+
+if ! test -r /etc/ld.so.cache; then
+    echo "warning: /etc/ld.so.cache does not exist, test skipped"
+    exit 77
+fi
+
+testout="${common_objpfx}elf/tst-ldconfig-p.out"
+# Truncate file.
+: > "$testout"
+
+${test_wrapper_env} \
+${run_program_env} \
+${common_objpfx}elf/ldconfig -p \
+  $testroot/lib >>"$testout" 2>>"$testout"
+status=$?
+echo "info: ldconfig exit status: $status" >>"$testout"
+
+errors=0
+case $status in
+    (0)
+	if head -n 1 "$testout" | \
+		grep -q "libs found in cache \`/etc/ld.so.cache'\$" ; then
+	    echo "info: initial string found" >>"$testout"
+	else
+	    echo "error: initial string not found" >>"$testout"
+	    errors=1
+	fi
+	if grep -q "^	libc\.so\..* => " "$testout"; then
+	    echo "info: libc.so.* string found" >>"$testout"
+	else
+	    echo "error: libc.so.* string not found" >>"$testout"
+	    errors=1
+	fi
+	;;
+    (1)
+	if head -n 1 "$testout" | \
+		grep -q ": Cache file has wrong endianness\.$" ; then
+	    echo "info: cache file has wrong endianess" >> "$testout"
+	else
+	    echo "error: unexpected ldconfig error message" >> "$testout"
+	    errors=1
+	fi
+	;;
+    (*)
+	echo "error: unexpected exit status" >> "$testout"
+	errors=1
+	;;
+esac
+
+exit $errors
diff --git a/elf/tst-recursive-tls.c b/elf/tst-recursive-tls.c
new file mode 100644
index 0000000000..716d1f783a
--- /dev/null
+++ b/elf/tst-recursive-tls.c
@@ -0,0 +1,60 @@
+/* Test with interposed malloc with dynamic TLS.
+   Copyright (C) 2024 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 <array_length.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* Defined in tst-recursive-tlsmallocmod.so.  */
+extern __thread unsigned int malloc_subsytem_counter;
+
+static int
+do_test (void)
+{
+  /* 16 is large enough to exercise the DTV resizing case.  */
+  void *handles[16];
+
+  for (unsigned int i = 0; i < array_length (handles); ++i)
+    {
+      /* Re-use the TLS slot for module 0.  */
+      if (i > 0)
+        xdlclose (handles[0]);
+
+      char soname[30];
+      snprintf (soname, sizeof (soname), "tst-recursive-tlsmod%u.so", i);
+      handles[i] = xdlopen (soname, RTLD_NOW);
+
+      if (i > 0)
+        {
+          handles[0] = xdlopen ("tst-recursive-tlsmod0.so", RTLD_NOW);
+          int (*fptr) (void) = xdlsym (handles[0], "get_threadvar_0");
+          /* May trigger TLS storage allocation using malloc.  */
+          TEST_COMPARE (fptr (), 0);
+        }
+    }
+
+  for (unsigned int i = 0; i < array_length (handles); ++i)
+    xdlclose (handles[i]);
+
+  printf ("info: malloc subsystem calls: %u\n", malloc_subsytem_counter);
+  TEST_VERIFY (malloc_subsytem_counter > 0);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-recursive-tlsmallocmod.c b/elf/tst-recursive-tlsmallocmod.c
new file mode 100644
index 0000000000..c24e9945d1
--- /dev/null
+++ b/elf/tst-recursive-tlsmallocmod.c
@@ -0,0 +1,64 @@
+/* Interposed malloc with dynamic TLS.
+   Copyright (C) 2024 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 <stdlib.h>
+#include <dlfcn.h>
+
+__thread unsigned int malloc_subsytem_counter;
+
+static __typeof (malloc) *malloc_fptr;
+static __typeof (free) *free_fptr;
+static __typeof (calloc) *calloc_fptr;
+static __typeof (realloc) *realloc_fptr;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+  malloc_fptr = dlsym (RTLD_NEXT, "malloc");
+  free_fptr = dlsym (RTLD_NEXT, "free");
+  calloc_fptr = dlsym (RTLD_NEXT, "calloc");
+  realloc_fptr = dlsym (RTLD_NEXT, "realloc");
+}
+
+void *
+malloc (size_t size)
+{
+  ++malloc_subsytem_counter;
+  return malloc_fptr (size);
+}
+
+void
+free (void *ptr)
+{
+  ++malloc_subsytem_counter;
+  return free_fptr (ptr);
+}
+
+void *
+calloc (size_t a, size_t b)
+{
+  ++malloc_subsytem_counter;
+  return calloc_fptr (a, b);
+}
+
+void *
+realloc (void *ptr, size_t size)
+{
+  ++malloc_subsytem_counter;
+  return realloc_fptr (ptr, size);
+}
diff --git a/elf/tst-recursive-tlsmodN.c b/elf/tst-recursive-tlsmodN.c
new file mode 100644
index 0000000000..bb7592aee6
--- /dev/null
+++ b/elf/tst-recursive-tlsmodN.c
@@ -0,0 +1,28 @@
+/* Test module with global-dynamic TLS.  Used to trigger DTV reallocation.
+   Copyright (C) 2024 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/>.  */
+
+/* Compiled with VAR and FUNC set via -D.  FUNC requires some
+   relocation against TLS variable VAR.  */
+
+__thread int VAR;
+
+int
+FUNC (void)
+{
+  return VAR;
+}
diff --git a/elf/tst-stackguard1.c b/elf/tst-stackguard1.c
index 050784319a..98625632dc 100644
--- a/elf/tst-stackguard1.c
+++ b/elf/tst-stackguard1.c
@@ -26,6 +26,8 @@
 #include <tls.h>
 #include <unistd.h>
 
+#include <support/xstdlib.h>
+
 static const char *command;
 static bool child;
 static uintptr_t stack_chk_guard_copy;
@@ -108,7 +110,8 @@ do_test (void)
 	  dup2 (fds[1], 2);
 	  close (fds[1]);
 
-	  system (command);
+	  xsystem (command);
+
 	  exit (0);
 	}
 
diff --git a/gmon/Makefile b/gmon/Makefile
index 552b7d7751..fbe2b0ba5c 100644
--- a/gmon/Makefile
+++ b/gmon/Makefile
@@ -1,4 +1,5 @@
-# Copyright (C) 1995-2022 Free Software Foundation, Inc.
+# Copyright (C) 1995-2023 Free Software Foundation, Inc.
+# Copyright The GNU Toolchain Authors.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -25,7 +26,7 @@ include ../Makeconfig
 headers	:= sys/gmon.h sys/gmon_out.h sys/profil.h
 routines := gmon mcount profil sprofil prof-freq
 
-tests	= tst-sprofil tst-gmon
+tests	= tst-sprofil tst-gmon tst-mcleanup
 ifeq ($(build-profile),yes)
 tests	+= tst-profile-static
 tests-static	+= tst-profile-static
@@ -56,6 +57,14 @@ ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-gmon-gprof.out
 endif
 
+CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg
+tst-mcleanup-no-pie = yes
+CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name)
+tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-mcleanup.out
+endif
+
 CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg
 CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name)
 tst-gmon-static-no-pie = yes
@@ -103,6 +112,18 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data
 clean-tst-gmon-data:
 	rm -f $(objpfx)tst-gmon.data.*
 
+$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data
+clean-tst-mcount-overflow-data:
+	rm -f $(objpfx)tst-mcount-overflow.data.*
+
+$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out
+	$(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \
+	$(evaluate-test)
+
+$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data
+clean-tst-mcleanup-data:
+	rm -f $(objpfx)tst-mcleanup.data.*
+
 $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out
 	$(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \
 	$(evaluate-test)
diff --git a/gmon/gmon.c b/gmon/gmon.c
index dee64803ad..97be1f72ca 100644
--- a/gmon/gmon.c
+++ b/gmon/gmon.c
@@ -97,11 +97,8 @@ __moncontrol (int mode)
 {
   struct gmonparam *p = &_gmonparam;
 
-  /* Don't change the state if we ran into an error.  */
-  if (p->state == GMON_PROF_ERROR)
-    return;
-
-  if (mode)
+  /* Treat start request as stop if error or gmon not initialized. */
+  if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL)
     {
       /* start */
       __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
@@ -111,7 +108,9 @@ __moncontrol (int mode)
     {
       /* stop */
       __profil(NULL, 0, 0, 0);
-      p->state = GMON_PROF_OFF;
+      /* Don't change the state if we ran into an error. */
+      if (p->state != GMON_PROF_ERROR)
+        p->state = GMON_PROF_OFF;
     }
 }
 libc_hidden_def (__moncontrol)
@@ -124,6 +123,19 @@ __monstartup (u_long lowpc, u_long highpc)
   int o;
   char *cp;
   struct gmonparam *p = &_gmonparam;
+  long int minarcs, maxarcs;
+
+  /* No tunables, we use hardcoded defaults */
+  minarcs = MINARCS;
+  maxarcs = MAXARCS;
+
+  /*
+   * If we are incorrectly called twice in a row (without an
+   * intervening call to _mcleanup), ignore the second call to
+   * prevent leaking memory.
+   */
+  if (p->tos != NULL)
+      return;
 
   /*
    * round lowpc and highpc to multiples of the density we're using
@@ -132,6 +144,8 @@ __monstartup (u_long lowpc, u_long highpc)
   p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
   p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
   p->textsize = p->highpc - p->lowpc;
+  /* This looks like a typo, but it's here to align the p->froms
+     section.  */
   p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
   p->hashfraction = HASHFRACTION;
   p->log_hashfraction = -1;
@@ -142,12 +156,12 @@ __monstartup (u_long lowpc, u_long highpc)
 	 instead of integer division.  Precompute shift amount. */
       p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
   }
-  p->fromssize = p->textsize / HASHFRACTION;
+  p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms));
   p->tolimit = p->textsize * ARCDENSITY / 100;
-  if (p->tolimit < MINARCS)
-    p->tolimit = MINARCS;
-  else if (p->tolimit > MAXARCS)
-    p->tolimit = MAXARCS;
+  if (p->tolimit < minarcs)
+    p->tolimit = minarcs;
+  else if (p->tolimit > maxarcs)
+    p->tolimit = maxarcs;
   p->tossize = p->tolimit * sizeof(struct tostruct);
 
   cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
@@ -440,9 +454,14 @@ _mcleanup (void)
 {
   __moncontrol (0);
 
-  if (_gmonparam.state != GMON_PROF_ERROR)
+  if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL)
     write_gmon ();
 
   /* free the memory. */
   free (_gmonparam.tos);
+
+  /* reset buffer to initial state for safety */
+  memset(&_gmonparam, 0, sizeof _gmonparam);
+  /* somewhat confusingly, ON=0, OFF=3 */
+  _gmonparam.state = GMON_PROF_OFF;
 }
diff --git a/gmon/mcount.c b/gmon/mcount.c
index 9d4a1a50fa..f7180fdb83 100644
--- a/gmon/mcount.c
+++ b/gmon/mcount.c
@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c	8.1 (Berkeley) 6/4/93";
 
 #include <atomic.h>
 
+#include <not-cancel.h>
+#include <unistd.h>
+#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1)
+
 /*
  * mcount is called on entry to each function compiled with the profiling
  * switch set.  _mcount(), which is declared in a machine-dependent way
@@ -170,6 +174,7 @@ done:
 	return;
 overflow:
 	p->state = GMON_PROF_ERROR;
+	ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n");
 	return;
 }
 
diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h
index b4cc3b043a..af0582a371 100644
--- a/gmon/sys/gmon.h
+++ b/gmon/sys/gmon.h
@@ -111,6 +111,8 @@ extern struct __bb *__bb_head;
  * Always allocate at least this many tostructs.  This
  * hides the inadequacy of the ARCDENSITY heuristic, at least
  * for small programs.
+ *
+ * Value can be overridden at runtime by glibc.gmon.minarcs tunable.
  */
 #define MINARCS		50
 
@@ -124,8 +126,8 @@ extern struct __bb *__bb_head;
  * Used to be max representable value of ARCINDEX minus 2, but now
  * that ARCINDEX is a long, that's too large; we don't really want
  * to allow a 48 gigabyte table.
- * The old value of 1<<16 wasn't high enough in practice for large C++
- * programs; will 1<<20 be adequate for long?  FIXME
+ *
+ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable.
  */
 #define MAXARCS		(1 << 20)
 
diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c
new file mode 100644
index 0000000000..b259653ec8
--- /dev/null
+++ b/gmon/tst-mcleanup.c
@@ -0,0 +1,31 @@
+/* Test program for repeated invocation of _mcleanup
+   Copyright The GNU Toolchain Authors.
+   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/>.  */
+
+/* Intentionally calls _mcleanup() twice: once manually, it will be
+   called again as an atexit handler. This is incorrect use of the API,
+   but the point of the test is to make sure we don't crash when the
+   API is misused in this way. */
+
+#include <sys/gmon.h>
+
+int
+main (void)
+{
+  _mcleanup();
+  return 0;
+}
diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh
new file mode 100644
index 0000000000..27eb5538fd
--- /dev/null
+++ b/gmon/tst-mcount-overflow-check.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Test expected messages generated when mcount overflows
+# Copyright (C) 2017-2023 Free Software Foundation, Inc.
+# Copyright The GNU Toolchain Authors.
+# 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/>.
+
+LC_ALL=C
+export LC_ALL
+set -e
+exec 2>&1
+
+program="$1"
+
+check_msg() {
+    if ! grep -q "$1" "$program.out"; then
+       echo "FAIL: expected message not in output: $1"
+       exit 1
+    fi
+}
+
+check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs'
+check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated'
+
+for data_file in $1.data.*; do
+  if [ -f "$data_file" ]; then
+    echo "FAIL: expected no data files, but found $data_file"
+    exit 1
+  fi
+done
+
+echo PASS
diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c
new file mode 100644
index 0000000000..06cc93ef87
--- /dev/null
+++ b/gmon/tst-mcount-overflow.c
@@ -0,0 +1,72 @@
+/* Test program to trigger mcount overflow in profiling collection.
+   Copyright (C) 2017-2023 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/>.  */
+
+/* Program with sufficiently complex, yet pointless, call graph
+   that it will trigger an mcount overflow, when you set the
+   minarcs/maxarcs tunables to very low values. */
+
+#define PREVENT_TAIL_CALL asm volatile ("")
+
+/* Calls REP(n) macro 16 times, for n=0..15.
+ * You need to define REP(n) before using this.
+ */
+#define REPS \
+  REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \
+  REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15)
+
+/* Defines 16 leaf functions named f1_0 to f1_15 */
+#define REP(n) \
+  __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {};
+REPS
+#undef REP
+
+/* Calls all 16 leaf functions f1_* in succession */
+__attribute__ ((noinline, noclone, weak)) void
+f2 (void)
+{
+# define REP(n) f1_##n();
+  REPS
+# undef REP
+  PREVENT_TAIL_CALL;
+}
+
+/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */
+#define REP(n) \
+  __attribute__ ((noinline, noclone, weak)) void \
+  f2_##n (void) { f2(); PREVENT_TAIL_CALL; };
+REPS
+#undef REP
+
+__attribute__ ((noinline, noclone, weak)) void
+f3 (int count)
+{
+  for (int i = 0; i < count; ++i)
+    {
+      /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */
+#     define REP(n) f1_##n(); f2_##n();
+      REPS
+#     undef REP
+    }
+}
+
+int
+main (void)
+{
+  f3 (1000);
+  return 0;
+}
diff --git a/gshadow/Makefile b/gshadow/Makefile
index eff303f538..5b3fa7e387 100644
--- a/gshadow/Makefile
+++ b/gshadow/Makefile
@@ -26,7 +26,7 @@ headers		= gshadow.h
 routines	= getsgent getsgnam sgetsgent fgetsgent putsgent \
 		  getsgent_r getsgnam_r sgetsgent_r fgetsgent_r
 
-tests = tst-gshadow tst-putsgent tst-fgetsgent_r
+tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent
 
 CFLAGS-getsgent_r.c += -fexceptions
 CFLAGS-getsgent.c += -fexceptions
diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c
index 28c826c9b5..a767a643d4 100644
--- a/gshadow/sgetsgent_r.c
+++ b/gshadow/sgetsgent_r.c
@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer,
       buffer[buflen - 1] = '\0';
       sp = strncpy (buffer, string, buflen);
       if (buffer[buflen - 1] != '\0')
-	return ERANGE;
+	{
+	  __set_errno (ERANGE);
+	  return ERANGE;
+	}
     }
   else
     sp = (char *) string;
diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c
new file mode 100644
index 0000000000..0370c10fd0
--- /dev/null
+++ b/gshadow/tst-sgetsgent.c
@@ -0,0 +1,69 @@
+/* Test large input for sgetsgent (bug 30151).
+   Copyright (C) 2023 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 <gshadow.h>
+#include <stddef.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  /* Create a shadow group with 1000 members.  */
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+  const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ";
+  fprintf (mem.out, "group-name:%s::m0", passwd);
+  for (int i = 1; i < 1000; ++i)
+    fprintf (mem.out, ",m%d", i);
+  xfclose_memstream (&mem);
+
+  /* Call sgetsgent.  */
+  char *input = mem.buffer;
+  struct sgrp *e = sgetsgent (input);
+  TEST_VERIFY_EXIT (e != NULL);
+  TEST_COMPARE_STRING (e->sg_namp, "group-name");
+  TEST_COMPARE_STRING (e->sg_passwd, passwd);
+  /* No administrators.  */
+  TEST_COMPARE_STRING (e->sg_adm[0], NULL);
+  /* Check the members list.  */
+  for (int i = 0; i < 1000; ++i)
+    {
+      char *member = xasprintf ("m%d", i);
+      TEST_COMPARE_STRING (e->sg_mem[i], member);
+      free (member);
+    }
+  TEST_COMPARE_STRING (e->sg_mem[1000], NULL);
+
+  /* Check that putsgent brings back the input string.  */
+  xopen_memstream (&mem);
+  TEST_COMPARE (putsgent (e, mem.out), 0);
+  xfclose_memstream (&mem);
+  /* Compare without the trailing '\n' that putsgent added.  */
+  TEST_COMPARE (mem.buffer[mem.length - 1], '\n');
+  mem.buffer[mem.length - 1] = '\0';
+  TEST_COMPARE_STRING (mem.buffer, input);
+
+  free (mem.buffer);
+  free (input);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
index debb96b322..b72933b526 100644
--- a/iconv/gconv_parseconfdir.h
+++ b/iconv/gconv_parseconfdir.h
@@ -29,14 +29,14 @@
 # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
 # define asprintf __asprintf
 # define opendir __opendir
-# define readdir __readdir
+# define readdir64 __readdir64
 # define closedir __closedir
 # define mempcpy __mempcpy
-# define struct_stat struct __stat64_t64
-# define lstat __lstat64_time64
+# define struct_stat64 struct __stat64_t64
+# define lstat64 __lstat64_time64
 # define feof_unlocked __feof_unlocked
 #else
-# define struct_stat struct stat
+# define struct_stat64 struct stat64
 #endif
 
 /* Name of the file containing the module information in the directories
@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
   DIR *confdir = opendir (buf);
   if (confdir != NULL)
     {
-      struct dirent *ent;
-      while ((ent = readdir (confdir)) != NULL)
+      struct dirent64 *ent;
+      while ((ent = readdir64 (confdir)) != NULL)
 	{
 	  if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
 	    continue;
@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
 	      && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
 	    {
 	      char *conf;
-	      struct_stat st;
+	      struct_stat64 st;
 	      if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
 		continue;
 
 	      if (ent->d_type != DT_UNKNOWN
-		  || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode)))
+		  || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
 		found |= read_conf_file (conf, dir, dir_len);
 
 	      free (conf);
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index f4c089ed5d..d01b3fcab6 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -75,7 +75,8 @@ ifeq (yes,$(build-shared))
 tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
 	tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
 	bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
-	bug-iconv13 bug-iconv14 bug-iconv15
+	bug-iconv13 bug-iconv14 bug-iconv15 \
+	tst-iconv-iso-2022-cn-ext
 ifeq ($(have-thread-library),yes)
 tests += bug-iconv3
 endif
@@ -330,6 +331,8 @@ $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
 			  $(addprefix $(objpfx),$(modules.so))
 $(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
 			  $(addprefix $(objpfx),$(modules.so))
+$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \
+					$(addprefix $(objpfx),$(modules.so))
 
 $(objpfx)iconv-test.out: run-iconv-test.sh \
 			 $(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c
index e09f358cad..2cc478a8c6 100644
--- a/iconvdata/iso-2022-cn-ext.c
+++ b/iconvdata/iso-2022-cn-ext.c
@@ -574,6 +574,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
 	      {								      \
 		const char *escseq;					      \
 									      \
+		if (outptr + 4 > outend)				      \
+		  {							      \
+		    result = __GCONV_FULL_OUTPUT;			      \
+		    break;						      \
+		  }							      \
+									      \
 		assert (used == CNS11643_2_set); /* XXX */		      \
 		escseq = "*H";						      \
 		*outptr++ = ESC;					      \
@@ -587,6 +593,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
 	      {								      \
 		const char *escseq;					      \
 									      \
+		if (outptr + 4 > outend)				      \
+		  {							      \
+		    result = __GCONV_FULL_OUTPUT;			      \
+		    break;						      \
+		  }							      \
+									      \
 		assert ((used >> 5) >= 3 && (used >> 5) <= 7);		      \
 		escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2;		      \
 		*outptr++ = ESC;					      \
diff --git a/iconvdata/tst-iconv-iso-2022-cn-ext.c b/iconvdata/tst-iconv-iso-2022-cn-ext.c
new file mode 100644
index 0000000000..96a8765fd5
--- /dev/null
+++ b/iconvdata/tst-iconv-iso-2022-cn-ext.c
@@ -0,0 +1,128 @@
+/* Verify ISO-2022-CN-EXT does not write out of the bounds.
+   Copyright (C) 2024 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 <stdio.h>
+#include <string.h>
+
+#include <errno.h>
+#include <iconv.h>
+#include <sys/mman.h>
+
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* The test sets up a two memory page buffer with the second page marked
+   PROT_NONE to trigger a fault if the conversion writes beyond the exact
+   expected amount.  Then we carry out various conversions and precisely
+   place the start of the output buffer in order to trigger a SIGSEGV if the
+   process writes anywhere between 1 and page sized bytes more (only one
+   PROT_NONE page is setup as a canary) than expected.  These tests exercise
+   all three of the cases in ISO-2022-CN-EXT where the converter must switch
+   character sets and may run out of buffer space while doing the
+   operation.  */
+
+static int
+do_test (void)
+{
+  iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8");
+  TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+  char *ntf;
+  size_t ntfsize;
+  char *outbufbase;
+  {
+    int pgz = getpagesize ();
+    TEST_VERIFY_EXIT (pgz > 0);
+    ntfsize = 2 * pgz;
+
+    ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE
+		 | MAP_ANONYMOUS, -1);
+    xmprotect (ntf + pgz, pgz, PROT_NONE);
+
+    outbufbase = ntf + pgz;
+  }
+
+  /* Check if SOdesignation escape sequence does not trigger an OOB write.  */
+  {
+    char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2";
+
+    for (int i = 0; i < 9; i++)
+      {
+	char *inp = inbuf;
+	size_t inleft = sizeof (inbuf) - 1;
+
+	char *outp = outbufbase - i;
+	size_t outleft = i;
+
+	TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
+			  == (size_t) -1);
+	TEST_COMPARE (errno, E2BIG);
+
+	TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
+      }
+  }
+
+  /* Same as before for SS2designation.  */
+  {
+    char inbuf[] = "㴽 \xe3\xb4\xbd";
+
+    for (int i = 0; i < 14; i++)
+      {
+	char *inp = inbuf;
+	size_t inleft = sizeof (inbuf) - 1;
+
+	char *outp = outbufbase - i;
+	size_t outleft = i;
+
+	TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
+			  == (size_t) -1);
+	TEST_COMPARE (errno, E2BIG);
+
+	TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
+      }
+  }
+
+  /* Same as before for SS3designation.  */
+  {
+    char inbuf[] = "劄 \xe5\x8a\x84";
+
+    for (int i = 0; i < 14; i++)
+      {
+	char *inp = inbuf;
+	size_t inleft = sizeof (inbuf) - 1;
+
+	char *outp = outbufbase - i;
+	size_t outleft = i;
+
+	TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
+			  == (size_t) -1);
+	TEST_COMPARE (errno, E2BIG);
+
+	TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
+      }
+  }
+
+  TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+  xmunmap (ntf, ntfsize);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index 53f1dbc7c3..c27e7886b7 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
 int __ns_name_unpack (const unsigned char *, const unsigned char *,
 		      const unsigned char *, unsigned char *, size_t) __THROW;
 
+/* Like ns_samename, but for uncompressed binary names.  Return true
+   if the two arguments compare are equal as case-insensitive domain
+   names.  */
+_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *)
+  attribute_hidden;
+
 #define ns_msg_getflag(handle, flag) \
   (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
 
@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack)
 extern __typeof (ns_samename) __libc_ns_samename;
 libc_hidden_proto (__libc_ns_samename)
 
+/* Packet parser helper functions.  */
+
+/* Verify that P points to an uncompressed domain name in wire format.
+   On success, return the length of the encoded name, including the
+   terminating null byte.  On failure, return -1 and set errno.  EOM
+   must point one past the last byte in the packet.  */
+int __ns_name_length_uncompressed (const unsigned char *p,
+				   const unsigned char *eom) attribute_hidden;
+
+/* Iterator over the resource records in a DNS packet.  */
+struct ns_rr_cursor
+{
+  /* These members are not changed after initialization.  */
+  const unsigned char *begin;	/* First byte of packet.  */
+  const unsigned char *end;	/* One past the last byte of the packet.  */
+  const unsigned char *first_rr; /* First resource record (or packet end).  */
+
+  /* Advanced towards the end while reading the packet.  */
+  const unsigned char *current;
+};
+
+/* Returns the RCODE field from the DNS header.  */
+static inline int
+ns_rr_cursor_rcode (const struct ns_rr_cursor *c)
+{
+  return c->begin[3] & 0x0f;	/* Lower 4 bits at offset 3.  */
+}
+
+/* Returns the length of the answer section according to the DNS header.  */
+static inline int
+ns_rr_cursor_ancount (const struct ns_rr_cursor *c)
+{
+  return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6.  */
+}
+
+/* Returns the length of the authority (name server) section according
+   to the DNS header.  */
+static inline int
+ns_rr_cursor_nscount (const struct ns_rr_cursor *c)
+{
+  return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8.  */
+}
+
+/* Returns the length of the additional data section according to the
+   DNS header.  */
+static inline int
+ns_rr_cursor_adcount (const struct ns_rr_cursor *c)
+{
+  return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10.  */
+}
+
+/* Returns a pointer to the uncompressed question name in wire
+   format.  */
+static inline const unsigned char *
+ns_rr_cursor_qname (const struct ns_rr_cursor *c)
+{
+  return c->begin + 12;		/* QNAME starts right after the header.  */
+}
+
+/* Returns the question type of the first and only question.  */
+static inline const int
+ns_rr_cursor_qtype (const struct ns_rr_cursor *c)
+{
+  /* 16 bits 4 bytes back from the first RR header start.  */
+  return c->first_rr[-4] * 256 + c->first_rr[-3];
+}
+
+/* Returns the clss of the first and only question (usally C_IN).  */
+static inline const int
+ns_rr_cursor_qclass (const struct ns_rr_cursor *c)
+{
+  /* 16 bits 2 bytes back from the first RR header start.  */
+  return c->first_rr[-2] * 256 + c->first_rr[-1];
+}
+
+/* Initializes *C to cover the packet [BUF, BUF+LEN).  Returns false
+   if LEN is less than sizeof (*HD), if the packet does not contain a
+   full (uncompressed) question, or if the question count is not 1.  */
+_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c,
+			   const unsigned char *buf, size_t len)
+  attribute_hidden;
+
+/* Like ns_rr, but the record owner name is not decoded into text format.  */
+struct ns_rr_wire
+{
+  unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record.  */
+  uint16_t rtype;		/* Resource record type (T_*).  */
+  uint16_t rclass;		/* Resource record class (C_*).  */
+  uint32_t ttl;			/* Time-to-live field.  */
+  const unsigned char *rdata;	/* Start of resource record data.  */
+  uint16_t rdlength;		/* Length of the data at rdata, in bytes.  */
+};
+
+/* Attempts to parse the record at C into *RR.  On success, return
+   true, and C is advanced past the record, and RR->rdata points to
+   the record data.  On failure, errno is set to EMSGSIZE, and false
+   is returned.  */
+_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
+  attribute_hidden;
+
 # endif /* !_ISOMAC */
 #endif
diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h
new file mode 100644
index 0000000000..00b1b93342
--- /dev/null
+++ b/include/bits/wchar2-decl.h
@@ -0,0 +1 @@
+#include <wcsmbs/bits/wchar2-decl.h>
diff --git a/include/link.h b/include/link.h
index 0ac82d7c77..87966e8397 100644
--- a/include/link.h
+++ b/include/link.h
@@ -278,6 +278,10 @@ struct link_map
     /* List of object in order of the init and fini calls.  */
     struct link_map **l_initfini;
 
+    /* Linked list of objects in reverse ELF constructor execution
+       order.  Head of list is stored in _dl_init_called_list.  */
+    struct link_map *l_init_called_next;
+
     /* List of the dependencies introduced through symbol binding.  */
     struct link_map_reldeps
       {
diff --git a/include/resolv.h b/include/resolv.h
index 3590b6f496..4dbbac3800 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery)
 extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
 libc_hidden_proto (__libc_res_queriesmatch)
 
+/* Variant of res_hnok which operates on binary (but uncompressed) names.  */
+bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
+
 # endif /* _RESOLV_H_ && !_ISOMAC */
 #endif
diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h
index c490561581..65742b1036 100644
--- a/include/sys/sysinfo.h
+++ b/include/sys/sysinfo.h
@@ -14,10 +14,6 @@ libc_hidden_proto (__get_nprocs_conf)
 extern int __get_nprocs (void);
 libc_hidden_proto (__get_nprocs)
 
-/* Return the number of available processors which the process can
-   be scheduled.  */
-extern int __get_nprocs_sched (void) attribute_hidden;
-
 /* Return number of physical pages of memory in the system.  */
 extern long int __get_phys_pages (void);
 libc_hidden_proto (__get_phys_pages)
diff --git a/io/Makefile b/io/Makefile
index b1710407d0..b896484320 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -59,6 +59,7 @@ routines :=								\
 	ftw64-time64							\
 	closefrom close_range
 
+
 others		:= pwd
 test-srcs	:= ftwtest ftwtest-time64
 tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
@@ -80,7 +81,9 @@ tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 		   tst-utimensat \
 		   tst-closefrom \
 		   tst-close_range \
-		   tst-ftw-bz28126
+		   tst-ftw-bz28126 \
+		   tst-fcntl-lock \
+		   tst-fcntl-lock-lfs
 
 tests-time64 := \
   tst-fcntl-time64 \
diff --git a/io/tst-fcntl-lock-lfs.c b/io/tst-fcntl-lock-lfs.c
new file mode 100644
index 0000000000..f2a909fb02
--- /dev/null
+++ b/io/tst-fcntl-lock-lfs.c
@@ -0,0 +1,2 @@
+#define _FILE_OFFSET_BITS 64
+#include <io/tst-fcntl-lock.c>
diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c
new file mode 100644
index 0000000000..357c4b7b56
--- /dev/null
+++ b/io/tst-fcntl-lock.c
@@ -0,0 +1,97 @@
+/* Test for advisory record locking.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.
+*/
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* This is essentially the POSIX lockf.  */
+
+static int
+fcntl_lockf (int fd, int cmd, off_t len)
+{
+  struct flock fl = {
+    .l_type = F_WRLCK,
+    .l_whence = SEEK_CUR,
+    .l_len = len
+  };
+
+  switch (cmd)
+    {
+    case F_TEST:
+      fl.l_type = F_RDLCK;
+      if (fcntl (fd, F_GETLK, &fl) < 0)
+	return -1;
+      if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
+	return 0;
+      errno = EACCES;
+      return -1;
+
+    case F_ULOCK:
+      fl.l_type = F_UNLCK;
+      return fcntl (fd, F_SETLK, &fl);
+
+    case F_LOCK:
+      return fcntl (fd, F_SETLKW, &fl);
+
+    case F_TLOCK:
+      return fcntl (fd, F_SETLK, &fl);
+    }
+
+  errno = EINVAL;
+  return -1;
+}
+
+static int
+fcntl64_lockf (int fd, int cmd, off64_t len64)
+  {
+  struct flock64 fl64 = {
+    .l_type = F_WRLCK,
+    .l_whence = SEEK_CUR,
+    .l_len = len64
+  };
+
+  switch (cmd)
+    {
+    case F_TEST:
+      fl64.l_type = F_RDLCK;
+      if (fcntl64 (fd, F_GETLK64, &fl64) < 0)
+	return -1;
+      if (fl64.l_type == F_UNLCK || fl64.l_pid == getpid ())
+	return 0;
+      errno = EACCES;
+      return -1;
+
+    case F_ULOCK:
+      fl64.l_type = F_UNLCK;
+      return fcntl64 (fd, F_SETLK64, &fl64);
+
+    case F_LOCK:
+      return fcntl64 (fd, F_SETLKW64, &fl64);
+
+    case F_TLOCK:
+      return fcntl64 (fd, F_SETLK64, &fl64);
+    }
+
+  errno = EINVAL;
+  return -1;
+}
+
+#define TST_LOCKFD  "tst-fcntl-lock."
+#define LOCKF       fcntl_lockf
+#define LOCKF64     fcntl64_lockf
+#include "tst-lockf.c"
diff --git a/io/tst-lockf.c b/io/tst-lockf.c
index be92f33fd1..5e41dc19df 100644
--- a/io/tst-lockf.c
+++ b/io/tst-lockf.c
@@ -24,13 +24,23 @@
 #include <support/capture_subprocess.h>
 #include <support/check.h>
 
+#ifndef TST_LOCKFD
+# define TST_LOCKFD "tst-lockfd."
+#endif
+#ifndef LOCKF
+# define LOCKF lockf
+#endif
+#ifndef LOCKF64
+# define LOCKF64 lockf64
+#endif
+
 static char *temp_filename;
 static int temp_fd;
 
 static void
 do_prepare (int argc, char **argv)
 {
-  temp_fd = create_temp_file ("tst-lockfd.", &temp_filename);
+  temp_fd = create_temp_file (TST_LOCKFD, &temp_filename);
   TEST_VERIFY_EXIT (temp_fd != -1);
 }
 #define PREPARE do_prepare
@@ -40,22 +50,22 @@ do_test_child_lockf (void *closure)
 {
   /* Check if parent has [0, 1024) locked.  */
   TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0);
-  TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), -1);
+  TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1);
   TEST_COMPARE (errno, EAGAIN);
-  TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1);
+  TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1);
   TEST_COMPARE (errno, EACCES);
   /* Also Check if parent has last 1024 bytes locked.  */
   TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024);
-  TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1);
+  TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1);
 
   /* And try to lock [1024, 2048).  */
   TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024);
-  TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0);
+  TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0);
 
   /* Check if non-LFS interface cap access to 32-bif off_t.  */
   TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET),
 		(off64_t)INT32_MAX);
-  TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0);
+  TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0);
 }
 
 static void
@@ -63,32 +73,32 @@ do_test_child_lockf64 (void *closure)
 {
   /* Check if parent has [0, 1024) locked.  */
   TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0);
-  TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1);
+  TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1);
   TEST_COMPARE (errno, EAGAIN);
-  TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1);
+  TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1);
   TEST_COMPARE (errno, EACCES);
   /* Also Check if parent has last 1024 bytes locked.  */
   TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024);
-  TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1);
+  TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1);
 
   /* And try to lock [1024, 2048).  */
   TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024);
-  TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
+  TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
 
   /* And also [INT32_MAX, INT32_MAX+1024).  */
   {
     off64_t off = (off64_t)INT32_MAX;
     TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off);
-    TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
+    TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
   }
 
   /* Check if [INT32_MAX+1024, INT64_MAX) is locked.  */
   {
     off64_t off = (off64_t)INT32_MAX+1024;
     TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off);
-    TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1);
+    TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1);
     TEST_COMPARE (errno, EAGAIN);
-    TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1);
+    TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1);
     TEST_COMPARE (errno, EACCES);
   }
 }
@@ -97,38 +107,38 @@ static int
 do_test (void)
 {
   /* Basic tests to check if a lock can be obtained and checked.  */
-  TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0);
-  TEST_COMPARE (lockf (temp_fd, F_LOCK, INT32_MAX), 0);
-  TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), 0);
-  TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), 0);
+  TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0);
+  TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0);
+  TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0);
+  TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0);
   TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024);
-  TEST_COMPARE (lockf (temp_fd, F_ULOCK, 1024), 0);
+  TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0);
   /* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked.  */
 
   {
     struct support_capture_subprocess result;
     result = support_capture_subprocess (do_test_child_lockf, NULL);
-    support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none);
+    support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none);
   }
 
   if (sizeof (off_t) != sizeof (off64_t))
     {
       /* Check if previously locked regions with LFS symbol.  */
       TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0);
-      TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
-      TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), 0);
-      TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0);
+      TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
+      TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0);
+      TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0);
       /* Lock region [INT32_MAX+1024, INT64_MAX).  */
       off64_t off = (off64_t)INT32_MAX + 1024;
       TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off);
-      TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0);
+      TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0);
       /* Parent process should have ([0, 1024), [2048, INT32_MAX),
 	 [INT32_MAX+1024, INT64_MAX)) ranges locked.  */
 
       {
 	struct support_capture_subprocess result;
 	result = support_capture_subprocess (do_test_child_lockf64, NULL);
-	support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none);
+	support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none);
       }
     }
 
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index b1e200e716..0fa261257c 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -208,12 +208,12 @@ extern char *__REDIRECT (__fgets_chk_warn,
 __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
 fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __fgets_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __fgets_chk_warn (__s, sz, __n, __stream);
-  return __fgets_chk (__s, sz, __n, __stream);
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __fgets_chk_warn (__s, __sz, __n, __stream);
+  return __fgets_chk (__s, __sz, __n, __stream);
 }
 
 extern size_t __REDIRECT (__fread_alias,
@@ -232,12 +232,12 @@ __fortify_function __wur size_t
 fread (void *__restrict __ptr, size_t __size, size_t __n,
        FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize0 (__ptr);
-  if (__glibc_safe_or_unknown_len (__n, __size, sz))
+  size_t __sz = __glibc_objsize0 (__ptr);
+  if (__glibc_safe_or_unknown_len (__n, __size, __sz))
     return __fread_alias (__ptr, __size, __n, __stream);
-  if (__glibc_unsafe_len (__n, __size, sz))
-    return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
-  return __fread_chk (__ptr, sz, __size, __n, __stream);
+  if (__glibc_unsafe_len (__n, __size, __sz))
+    return __fread_chk_warn (__ptr, __sz, __size, __n, __stream);
+  return __fread_chk (__ptr, __sz, __size, __n, __stream);
 }
 
 #ifdef __USE_GNU
@@ -254,12 +254,12 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn,
 __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
 fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __fgets_unlocked_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
-  return __fgets_unlocked_chk (__s, sz, __n, __stream);
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __fgets_unlocked_chk_warn (__s, __sz, __n, __stream);
+  return __fgets_unlocked_chk (__s, __sz, __n, __stream);
 }
 #endif
 
@@ -281,8 +281,8 @@ __fortify_function __wur size_t
 fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
 		FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize0 (__ptr);
-  if (__glibc_safe_or_unknown_len (__n, __size, sz))
+  size_t __sz = __glibc_objsize0 (__ptr);
+  if (__glibc_safe_or_unknown_len (__n, __size, __sz))
     {
 # ifdef __USE_EXTERN_INLINES
       if (__builtin_constant_p (__size)
@@ -307,9 +307,9 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
 # endif
       return __fread_unlocked_alias (__ptr, __size, __n, __stream);
     }
-  if (__glibc_unsafe_len (__n, __size, sz))
-    return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
-  return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
+  if (__glibc_unsafe_len (__n, __size, __sz))
+    return __fread_unlocked_chk_warn (__ptr, __sz, __size, __n, __stream);
+  return __fread_unlocked_chk (__ptr, __sz, __size, __n, __stream);
 
 }
 #endif
diff --git a/libio/bug-mmap-fflush.c b/libio/bug-mmap-fflush.c
index d8aa58985a..3f99222eef 100644
--- a/libio/bug-mmap-fflush.c
+++ b/libio/bug-mmap-fflush.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <support/xstdlib.h>
 
 static char *fname;
 
@@ -35,14 +36,16 @@ do_test (void)
   char buffer[1024];
 
   snprintf (buffer, sizeof (buffer), "echo 'From foo@bar.com' > %s", fname);
-  system (buffer);
+  xsystem (buffer);
+
   f = fopen (fname, "r");
   fseek (f, 0, SEEK_END);
   o = ftello (f);
   fseek (f, 0, SEEK_SET);
   fflush (f);
   snprintf (buffer, sizeof (buffer), "echo 'From bar@baz.edu' >> %s", fname);
-  system (buffer);
+  xsystem (buffer);
+
   fseek (f, o, SEEK_SET);
   if (fgets (buffer, 1024, f) == NULL)
     exit (1);
diff --git a/libio/genops.c b/libio/genops.c
index 1b629eb695..1be964ef77 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -635,7 +635,7 @@ _IO_sputbackc (FILE *fp, int c)
 {
   int result;
 
-  if (fp->_IO_read_ptr > fp->_IO_read_base
+  if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
       && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
     {
       fp->_IO_read_ptr--;
@@ -796,6 +796,12 @@ _IO_unbuffer_all (void)
 	legacy = 1;
 #endif
 
+      /* Free up the backup area if it was ever allocated.  */
+      if (_IO_have_backup (fp))
+	_IO_free_backup_area (fp);
+      if (!legacy && fp->_mode > 0 && _IO_have_wbackup (fp))
+	_IO_free_wbackup_area (fp);
+
       if (! (fp->_flags & _IO_UNBUFFERED)
 	  /* Iff stream is un-orientated, it wasn't used. */
 	  && (legacy || fp->_mode != 0))
diff --git a/libio/libioP.h b/libio/libioP.h
index ba4fdbd200..bef3324ffb 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -529,8 +529,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW;
        ((__fp)->_wide_data->_IO_write_base \
 	= (__fp)->_wide_data->_IO_write_ptr = __p, \
 	(__fp)->_wide_data->_IO_write_end = (__ep))
-#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL)
-#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL)
+#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL)
+#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL)
 #define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP)
 #define _IO_have_markers(fp) ((fp)->_markers != NULL)
 #define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
diff --git a/locale/weight.h b/locale/weight.h
index 8be2d220f8..4a4d5aa6b2 100644
--- a/locale/weight.h
+++ b/locale/weight.h
@@ -27,7 +27,14 @@ findidx (const int32_t *table,
 	 const unsigned char *extra,
 	 const unsigned char **cpp, size_t len)
 {
+  /* With GCC 8 when compiling with -Os the compiler warns that
+     seq1.back_us and seq2.back_us might be used uninitialized.
+     This uninitialized use is impossible for the same reason
+     as described in comments in locale/weightwc.h.  */
+  DIAG_PUSH_NEEDS_COMMENT;
+  DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized");
   int32_t i = table[*(*cpp)++];
+  DIAG_POP_NEEDS_COMMENT;
   const unsigned char *cp;
   const unsigned char *usrc;
 
diff --git a/localedata/tst-ctype.c b/localedata/tst-ctype.c
index d77a684b41..ae7426eadb 100644
--- a/localedata/tst-ctype.c
+++ b/localedata/tst-ctype.c
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <support/check.h>
+
 
 static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
 static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -53,19 +55,11 @@ static struct classes
 #define nclasses (sizeof (classes) / sizeof (classes[0]))
 
 
-#define FAIL(str, args...) \
-  {									      \
-    printf ("      " str "\n", ##args);					      \
-    ++errors;								      \
-  }
-
-
 static int
 do_test (void)
 {
   const char *cp;
   const char *cp2;
-  int errors = 0;
   char *inpline = NULL;
   size_t inplinelen = 0;
   char *resline = NULL;
@@ -394,11 +388,8 @@ punct = %04x  alnum = %04x\n",
 	    {
 	      if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
 		  != (*resp != '0'))
-		{
-		  printf ("    is%s('%c' = '\\x%02x') %s true\n", inpline,
-			  *inp, *inp, *resp == '1' ? "not" : "is");
-		  ++errors;
-		}
+		FAIL ("    is%s('%c' = '\\x%02x') %s true\n", inpline,
+		      *inp, *inp, *resp == '1' ? "not" : "is");
 	      ++inp;
 	      ++resp;
 	    }
@@ -408,11 +399,8 @@ punct = %04x  alnum = %04x\n",
 	  while (*inp != '\0')
 	    {
 	      if (tolower (*inp) != *resp)
-		{
-		  printf ("    tolower('%c' = '\\x%02x') != '%c'\n",
-			  *inp, *inp, *resp);
-		  ++errors;
-		}
+		FAIL ("    tolower('%c' = '\\x%02x') != '%c'\n",
+		      *inp, *inp, *resp);
 	      ++inp;
 	      ++resp;
 	    }
@@ -422,11 +410,8 @@ punct = %04x  alnum = %04x\n",
 	  while (*inp != '\0')
 	    {
 	      if (toupper (*inp) != *resp)
-		{
-		  printf ("    toupper('%c' = '\\x%02x') != '%c'\n",
-			  *inp, *inp, *resp);
-		  ++errors;
-		}
+		FAIL ("    toupper('%c' = '\\x%02x') != '%c'\n",
+		      *inp, *inp, *resp);
 	      ++inp;
 	      ++resp;
 	    }
@@ -436,14 +421,7 @@ punct = %04x  alnum = %04x\n",
     }
 
 
-  if (errors != 0)
-    {
-      printf ("  %d error%s for `%s' locale\n\n\n", errors,
-	      errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
-      return 1;
-    }
-
-  printf ("  No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
+  printf ("Completed testing for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
   return 0;
 }
 
diff --git a/login/Makefile b/login/Makefile
index 62440499bc..0b6b962c06 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -44,7 +44,9 @@ subdir-dirs = programs
 vpath %.c programs
 
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
-  tst-pututxline-lockfail tst-pututxline-cache
+  tst-pututxline-lockfail tst-pututxline-cache tst-utmp-size tst-utmp-size-64
+
+CFLAGS-tst-utmp-size-64.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
 
 # Empty compatibility library for old binaries.
 extra-libs      := libutil
diff --git a/login/tst-utmp-size-64.c b/login/tst-utmp-size-64.c
new file mode 100644
index 0000000000..7a581a4c12
--- /dev/null
+++ b/login/tst-utmp-size-64.c
@@ -0,0 +1,2 @@
+/* The on-disk layout must not change in time64 mode.  */
+#include "tst-utmp-size.c"
diff --git a/login/tst-utmp-size.c b/login/tst-utmp-size.c
new file mode 100644
index 0000000000..1b7f7ff042
--- /dev/null
+++ b/login/tst-utmp-size.c
@@ -0,0 +1,33 @@
+/* Check expected sizes of struct utmp, struct utmpx, struct lastlog.
+   Copyright (C) 2024 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 <utmp.h>
+#include <utmpx.h>
+#include <utmp-size.h>
+
+static int
+do_test (void)
+{
+  _Static_assert (sizeof (struct utmp) == UTMP_SIZE, "struct utmp size");
+  _Static_assert (sizeof (struct utmpx) == UTMP_SIZE, "struct utmpx size");
+  _Static_assert (sizeof (struct lastlog) == LASTLOG_SIZE,
+                  "struct lastlog size");
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/malloc/arena.c b/malloc/arena.c
index 0a684a720d..a1ee7928d3 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -937,7 +937,7 @@ arena_get2 (size_t size, mstate avoid_arena)
             narenas_limit = mp_.arena_max;
           else if (narenas > mp_.arena_test)
             {
-              int n = __get_nprocs_sched ();
+              int n = __get_nprocs ();
 
               if (n >= 1)
                 narenas_limit = NARENAS_FROM_NCORES (n);
diff --git a/math/test-tgmath2.c b/math/test-tgmath2.c
index d758231a89..95897948fb 100644
--- a/math/test-tgmath2.c
+++ b/math/test-tgmath2.c
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <tgmath.h>
 
+#include <support/check.h>
+
 //#define DEBUG
 
 typedef complex float cfloat;
@@ -87,13 +89,6 @@ enum
 int count;
 int counts[Tlast][C_last];
 
-#define FAIL(str) \
-  do								\
-    {								\
-      printf ("%s failure on line %d\n", (str), __LINE__);	\
-      result = 1;						\
-    }								\
-  while (0)
 #define TEST_TYPE_ONLY(expr, rettype) \
   do								\
     {								\
@@ -133,8 +128,6 @@ int counts[Tlast][C_last];
 int
 test_cos (const int Vint4, const long long int Vllong4)
 {
-  int result = 0;
-
   TEST (cos (vfloat1), float, cos);
   TEST (cos (vdouble1), double, cos);
   TEST (cos (vldouble1), ldouble, cos);
@@ -152,7 +145,7 @@ test_cos (const int Vint4, const long long int Vllong4)
   TEST (cos (Vcdouble1), cdouble, cos);
   TEST (cos (Vcldouble1), cldouble, cos);
 
-  return result;
+  return 0;
 }
 
 int
diff --git a/misc/Makefile b/misc/Makefile
index ba8232a0e9..e77cdd8c1b 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -90,7 +90,7 @@ tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
 	 tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
 	 tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
 	 tst-mntent-autofs tst-syscalls tst-mntent-escape tst-select \
-	 tst-ioctl
+	 tst-ioctl tst-mremap1 tst-mremap2
 
 tests-time64 := \
   tst-select-time64 \
@@ -115,7 +115,10 @@ tests-special += $(objpfx)tst-error1-mem.out \
   $(objpfx)tst-allocate_once-mem.out
 endif
 
-tests-container := tst-syslog
+tests-container := \
+  tst-syslog \
+  tst-syslog-long-progname \
+  # tests-container
 
 CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-tsearch.c += $(uses-callbacks)
@@ -175,6 +178,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
 	$(evaluate-test)
 
+tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
+			       LD_PRELOAD=libc_malloc_debug.so.0
+
 $(objpfx)tst-select: $(librt)
 $(objpfx)tst-select-time64: $(librt)
 $(objpfx)tst-pselect: $(librt)
diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h
index fd30dd3114..916d2b6f12 100644
--- a/misc/bits/syslog.h
+++ b/misc/bits/syslog.h
@@ -24,6 +24,20 @@
 extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...)
      __attribute__ ((__format__ (__printf__, 3, 4)));
 
+#ifdef __USE_MISC
+extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
+			   __gnuc_va_list __ap)
+     __attribute__ ((__format__ (__printf__, 3, 0)));
+#endif
+
+#include <bits/floatn.h>
+#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+# include <bits/syslog-ldbl.h>
+#endif
+
+/* The following functions must be used only after applying all asm
+   redirections, e.g. long double asm redirections.  */
+
 #ifdef __va_arg_pack
 __fortify_function void
 syslog (int __pri, const char *__fmt, ...)
@@ -37,10 +51,6 @@ syslog (int __pri, const char *__fmt, ...)
 
 
 #ifdef __USE_MISC
-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
-			   __gnuc_va_list __ap)
-     __attribute__ ((__format__ (__printf__, 3, 0)));
-
 __fortify_function void
 vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
 {
diff --git a/misc/getsysstats.c b/misc/getsysstats.c
index e56aff0f37..660f64eb80 100644
--- a/misc/getsysstats.c
+++ b/misc/getsysstats.c
@@ -44,12 +44,6 @@ weak_alias (__get_nprocs, get_nprocs)
 link_warning (get_nprocs, "warning: get_nprocs will always return 1")
 
 
-int
-__get_nprocs_sched (void)
-{
-  return 1;
-}
-
 long int
 __get_phys_pages (void)
 {
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index f525f67547..294e633335 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -152,6 +152,7 @@
 # define __glibc_objsize(__o) __bos (__o)
 #endif
 
+#if __USE_FORTIFY_LEVEL > 0
 /* Compile time conditions to choose between the regular, _chk and _chk_warn
    variants.  These conditions should get evaluated to constant and optimized
    away.  */
@@ -187,7 +188,7 @@
    ? __ ## f ## _alias (__VA_ARGS__)					      \
    : (__glibc_unsafe_len (__l, __s, __osz)				      \
       ? __ ## f ## _chk_warn (__VA_ARGS__, __osz)			      \
-      : __ ## f ## _chk (__VA_ARGS__, __osz)))			      \
+      : __ ## f ## _chk (__VA_ARGS__, __osz)))
 
 /* Fortify function f, where object size argument passed to f is the number of
    elements and not total size.  */
@@ -197,7 +198,8 @@
    ? __ ## f ## _alias (__VA_ARGS__)					      \
    : (__glibc_unsafe_len (__l, __s, __osz)				      \
       ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s))		      \
-      : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))))		      \
+      : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))))
+#endif
 
 #if __GNUC_PREREQ (4,3)
 # define __warnattr(msg) __attribute__((__warning__ (msg)))
diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h
index d933fea104..3888153ed2 100644
--- a/misc/sys/syslog.h
+++ b/misc/sys/syslog.h
@@ -205,11 +205,11 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
 /* Define some macros helping to catch buffer overflows.  */
 #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
 # include <bits/syslog.h>
-#endif
-
-#include <bits/floatn.h>
-#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
-# include <bits/syslog-ldbl.h>
+#else
+# include <bits/floatn.h>
+# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+#  include <bits/syslog-ldbl.h>
+# endif
 #endif
 
 __END_DECLS
diff --git a/misc/syslog.c b/misc/syslog.c
index 554089bfc4..9336036666 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)syslog.c	8.4 (Berkeley) 3/18/94";
 #include <sys/uio.h>
 #include <sys/un.h>
 #include <syslog.h>
+#include <limits.h>
 
 static int LogType = SOCK_DGRAM;	/* type of socket connection */
 static int LogFile = -1;		/* fd for log */
@@ -122,8 +123,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
 {
   /* Try to use a static buffer as an optimization.  */
   char bufs[1024];
-  char *buf = NULL;
-  size_t bufsize = 0;
+  char *buf = bufs;
+  size_t bufsize;
+
   int msgoff;
   int saved_errno = errno;
 
@@ -167,7 +169,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
 		  _nl_C_locobj_ptr);
 
 #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
-  "<%d>%s %n%s%s%.0d%s: ",                               \
+  "<%d>%s%n%s%s%.0d%s: ",                                \
   __pri, __timestamp, __msgoff,                          \
   LogTag == NULL ? __progname : LogTag,                  \
   "[" + (pid == 0), pid, "]" + (pid == 0)
@@ -175,53 +177,95 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
 #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff)        \
   "<%d>: %n", __pri, __msgoff
 
-  int l;
+  int l, vl;
   if (has_ts)
     l = __snprintf (bufs, sizeof bufs,
 		    SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
   else
     l = __snprintf (bufs, sizeof bufs,
 		    SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
-  if (0 <= l && l < sizeof bufs)
+  if (l < 0)
+    goto out;
+
+  char *pos;
+  size_t len;
+
+  if (l < sizeof bufs)
     {
-      va_list apc;
-      va_copy (apc, ap);
+      /* At this point, there is still a chance that we can print the
+         remaining part of the log into bufs and use that.  */
+      pos = bufs + l;
+      len = sizeof (bufs) - l;
+    }
+  else
+    {
+      buf = NULL;
+      /* We already know that bufs is too small to use for this log message.
+         The next vsnprintf into bufs is used only to calculate the total
+         required buffer length.  We will discard bufs contents and allocate
+         an appropriately sized buffer later instead.  */
+      pos = bufs;
+      len = sizeof (bufs);
+    }
 
-      /* Restore errno for %m format.  */
-      __set_errno (saved_errno);
+  {
+    va_list apc;
+    va_copy (apc, ap);
 
-      int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
-                                     mode_flags);
-      if (0 <= vl && vl < sizeof bufs - l)
-        {
-          buf = bufs;
-          bufsize = l + vl;
-        }
+    /* Restore errno for %m format.  */
+    __set_errno (saved_errno);
 
-      va_end (apc);
-    }
+    vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
+    va_end (apc);
+
+    if (vl < 0 || vl >= INT_MAX - l)
+      goto out;
+
+    if (vl >= len)
+      buf = NULL;
+
+    bufsize = l + vl;
+  }
 
   if (buf == NULL)
     {
-      buf = malloc (l * sizeof (char));
+      buf = malloc ((bufsize + 1) * sizeof (char));
       if (buf != NULL)
 	{
 	  /* Tell the cancellation handler to free this buffer.  */
 	  clarg.buf = buf;
 
+	  int cl;
 	  if (has_ts)
-	    __snprintf (bufs, sizeof bufs,
-			SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
+	    cl = __snprintf (buf, l + 1,
+			     SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
 	  else
-	    __snprintf (bufs, sizeof bufs,
-			SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
+	    cl = __snprintf (buf, l + 1,
+			     SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
+	  if (cl != l)
+	    goto out;
+
+	  va_list apc;
+	  va_copy (apc, ap);
+	  cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
+				     mode_flags);
+	  va_end (apc);
+
+	  if (cl != vl)
+	    goto out;
 	}
       else
         {
+          int bl;
 	  /* Nothing much to do but emit an error message.  */
-          bufsize = __snprintf (bufs, sizeof bufs,
-                                "out of memory[%d]", __getpid ());
+          bl = __snprintf (bufs, sizeof bufs,
+                           "out of memory[%d]", __getpid ());
+          if (bl < 0 || bl >= sizeof bufs)
+            goto out;
+
+          bufsize = bl;
           buf = bufs;
+          msgoff = 0;
         }
     }
 
diff --git a/misc/tst-mremap1.c b/misc/tst-mremap1.c
new file mode 100644
index 0000000000..0469991a6c
--- /dev/null
+++ b/misc/tst-mremap1.c
@@ -0,0 +1,46 @@
+/* Test mremap with MREMAP_MAYMOVE.
+   Copyright (C) 2024 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 <errno.h>
+#include <sys/mman.h>
+#include <support/xstdlib.h>
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+static int
+do_test (void)
+{
+  size_t old_size = getpagesize ();
+  char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  old_addr[0] = 1;
+  old_addr[old_size - 1] = 2;
+
+  /* Test MREMAP_MAYMOVE.  */
+  size_t new_size = old_size + old_size;
+  char *new_addr = mremap (old_addr, old_size, new_size, MREMAP_MAYMOVE);
+  TEST_VERIFY_EXIT (new_addr != MAP_FAILED);
+  new_addr[0] = 1;
+  new_addr[new_size - 1] = 2;
+  xmunmap (new_addr, new_size);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-mremap2.c b/misc/tst-mremap2.c
new file mode 100644
index 0000000000..45be7f0369
--- /dev/null
+++ b/misc/tst-mremap2.c
@@ -0,0 +1,54 @@
+/* Test mremap with MREMAP_FIXED.
+   Copyright (C) 2024 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 <errno.h>
+#include <sys/mman.h>
+#include <support/xstdlib.h>
+#include <support/xunistd.h>
+#include <support/test-driver.h>
+#include <mremap-failure.h>
+
+static int
+do_test (void)
+{
+  size_t old_size = getpagesize ();
+  size_t new_size = old_size + old_size;
+  char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  old_addr[0] = 1;
+  old_addr[old_size - 1] = 2;
+
+  char *fixed_addr = xmmap (NULL, new_size, PROT_READ | PROT_WRITE,
+			    MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  fixed_addr[0] = 1;
+  fixed_addr[new_size - 1] = 2;
+
+  /* Test MREMAP_FIXED.  */
+  char *new_addr = mremap (old_addr, old_size, new_size,
+			   MREMAP_FIXED | MREMAP_MAYMOVE,
+			   fixed_addr);
+  if (new_addr == MAP_FAILED)
+    return mremap_failure_exit (errno);
+  new_addr[0] = 1;
+  new_addr[new_size - 1] = 2;
+  xmunmap (new_addr, new_size);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c
index 40b527bdcb..ed3dc04eeb 100644
--- a/misc/tst-preadvwritev2-common.c
+++ b/misc/tst-preadvwritev2-common.c
@@ -34,8 +34,11 @@
 #ifndef RWF_APPEND
 # define RWF_APPEND 0
 #endif
+#ifndef RWF_NOAPPEND
+# define RWF_NOAPPEND 0
+#endif
 #define RWF_SUPPORTED	(RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
-			 | RWF_APPEND)
+			 | RWF_APPEND | RWF_NOAPPEND)
 
 /* Generic uio_lim.h does not define IOV_MAX.  */
 #ifndef IOV_MAX
diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c
new file mode 100644
index 0000000000..88f37a8a00
--- /dev/null
+++ b/misc/tst-syslog-long-progname.c
@@ -0,0 +1,39 @@
+/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246)
+   Copyright (C) 2023 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 <syslog.h>
+#include <string.h>
+
+extern char * __progname;
+
+static int
+do_test (void)
+{
+  char long_progname[2048];
+
+  memset (long_progname, 'X', sizeof (long_progname) - 1);
+  long_progname[sizeof (long_progname) - 1] = '\0';
+
+  __progname = long_progname;
+
+  syslog (LOG_INFO, "Hello, World!");
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-syslog-long-progname.root/postclean.req b/misc/tst-syslog-long-progname.root/postclean.req
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c
index e550d15796..3560b518a2 100644
--- a/misc/tst-syslog.c
+++ b/misc/tst-syslog.c
@@ -68,21 +68,19 @@ static const int priorities[] =
     LOG_DEBUG
   };
 
-enum
-  {
-    ident_length = 64,
-    msg_length = 64
-  };
+#define IDENT_LENGTH 64
+#define MSG_LENGTH   1024
 
 #define SYSLOG_MSG_BASE "syslog_message"
 #define OPENLOG_IDENT   "openlog_ident"
+static char large_message[MSG_LENGTH];
 
 struct msg_t
   {
     int priority;
     int facility;
-    char ident[ident_length];
-    char msg[msg_length];
+    char ident[IDENT_LENGTH];
+    char msg[MSG_LENGTH];
     pid_t pid;
   };
 
@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options,
   return true;
 }
 
+static void
+send_syslog_large (int options)
+{
+  int facility = LOG_USER;
+  int priority = LOG_INFO;
+
+  syslog (facility | priority, "%s %d %d", large_message, facility,
+	  priority);
+}
+
+static void
+send_vsyslog_large (int options)
+{
+  int facility = LOG_USER;
+  int priority = LOG_INFO;
+
+  call_vsyslog (facility | priority, "%s %d %d", large_message, facility,
+		priority);
+}
+
+static bool
+check_syslog_message_large (const struct msg_t *msg, int msgnum, int options,
+			    pid_t pid)
+{
+  TEST_COMPARE (msg->facility, LOG_USER);
+  TEST_COMPARE (msg->priority, LOG_INFO);
+  TEST_COMPARE_STRING (msg->msg, large_message);
+
+  return false;
+}
+
 static void
 send_openlog (int options)
 {
@@ -179,6 +208,17 @@ send_openlog (int options)
   closelog ();
 }
 
+static void
+send_openlog_large (int options)
+{
+  /* Define a non-default IDENT and a not default facility.  */
+  openlog (OPENLOG_IDENT, options, LOG_LOCAL0);
+
+  syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO);
+
+  closelog ();
+}
+
 static bool
 check_openlog_message (const struct msg_t *msg, int msgnum,
                        int options, pid_t pid)
@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
   int expected_priority = priorities[msgnum % array_length (priorities)];
   TEST_COMPARE (msg->priority, expected_priority);
 
-  char expected_ident[ident_length];
+  char expected_ident[IDENT_LENGTH];
   snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
             OPENLOG_IDENT,
             options & LOG_PID ? "[" : "",
@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
   return true;
 }
 
+static bool
+check_openlog_message_large (const struct msg_t *msg, int msgnum,
+			     int options, pid_t pid)
+{
+  char expected_ident[IDENT_LENGTH];
+  snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
+            OPENLOG_IDENT,
+            options & LOG_PID ? "[" : "",
+            options & LOG_PID ? pid : 0,
+            options & LOG_PID ? "]" : "");
+
+  TEST_COMPARE_STRING (msg->ident, expected_ident);
+  TEST_COMPARE_STRING (msg->msg, large_message);
+  TEST_COMPARE (msg->priority, LOG_INFO);
+  TEST_COMPARE (msg->facility, LOG_LOCAL0);
+
+  return false;
+}
+
 static struct msg_t
 parse_syslog_msg (const char *msg)
 {
   struct msg_t r = { .pid = -1 };
   int number;
+  int wsb, wsa;
+
+#define STRINPUT(size)  XSTRINPUT(size)
+#define XSTRINPUT(size) "%" # size "s"
 
   /* The message in the form:
-     <179>Apr  8 14:51:19 tst-syslog: syslog message 176 3  */
-  int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d",
-                  &number, r.ident, r.msg);
+     <179>Apr  8 14:51:19 tst-syslog: message 176 3  */
+  int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH)
+		       " " STRINPUT(MSG_LENGTH) " %*d %*d",
+                  &number, &wsb, &wsa, r.ident, r.msg);
   TEST_COMPARE (n, 3);
+  /* It should only one space between timestamp and message.  */
+  TEST_COMPARE (wsa - wsb, 1);
 
   r.facility = number & LOG_FACMASK;
   r.priority = number & LOG_PRIMASK;
@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg)
 
   /* The message in the form:
      openlog_ident: syslog_message 128 0  */
-  int n = sscanf (msg, "%32s %64s %d %d",
+  int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d",
       r.ident, r.msg, &facility, &priority);
   TEST_COMPARE (n, 4);
 
@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options,
   int msgnum = 0;
   while (1)
     {
-      char buf[512];
+      char buf[2048];
       size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0,
                             (struct sockaddr *) &addr, &addrlen);
       buf[l] = '\0';
@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options,
 
   int client_tcp = xaccept (server_tcp, NULL, NULL);
 
-  char buf[512], *rb = buf;
+  char buf[2048], *rb = buf;
   size_t rbl = sizeof (buf);
   size_t prl = 0;  /* Track the size of the partial record.  */
   int msgnum = 0;
@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp)
 }
 
 static void
-check_syslog_console (void)
+check_syslog_console_read_large (FILE *fp)
+{
+  char buf[2048];
+  TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL);
+  struct msg_t msg = parse_syslog_console (buf);
+
+  TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":");
+  TEST_COMPARE_STRING (msg.msg, large_message);
+  TEST_COMPARE (msg.priority, LOG_INFO);
+  TEST_COMPARE (msg.facility, LOG_LOCAL0);
+}
+
+static void
+check_syslog_console (void (*syslog_send)(int),
+		      void (*syslog_check)(FILE *fp))
 {
   xmkfifo (_PATH_CONSOLE, 0666);
 
   pid_t sender_pid = xfork ();
   if (sender_pid == 0)
     {
-      send_openlog (LOG_CONS);
+      syslog_send (LOG_CONS);
       _exit (0);
     }
 
   {
     FILE *fp = xfopen (_PATH_CONSOLE, "r+");
-    check_syslog_console_read (fp);
+    syslog_check (fp);
     xfclose (fp);
   }
 
@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure)
 }
 
 static void
-check_syslog_perror (void)
+send_openlog_callback_large (void *clousure)
+{
+  int options = *(int *) clousure;
+  send_openlog_large (options);
+}
+
+static void
+check_syslog_perror (bool large)
 {
   struct support_capture_subprocess result;
-  result = support_capture_subprocess (send_openlog_callback,
+  result = support_capture_subprocess (large
+				       ? send_openlog_callback_large
+				       : send_openlog_callback,
                                        &(int){LOG_PERROR});
 
   FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r");
   if (mfp == NULL)
     FAIL_EXIT1 ("fmemopen: %m");
-  check_syslog_console_read (mfp);
+  if (large)
+    check_syslog_console_read_large (mfp);
+  else
+    check_syslog_console_read (mfp);
   xfclose (mfp);
 
   support_capture_subprocess_check (&result, "tst-openlog-child", 0,
@@ -462,10 +554,31 @@ do_test (void)
   check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message);
 
   /* Check the LOG_CONS option.  */
-  check_syslog_console ();
+  check_syslog_console (send_openlog, check_syslog_console_read);
 
   /* Check the LOG_PERROR option.  */
-  check_syslog_perror ();
+  check_syslog_perror (false);
+
+  /* Similar tests as before, but with a large message to trigger the
+     syslog path that uses dynamically allocated memory.  */
+  memset (large_message, 'a', sizeof large_message - 1);
+  large_message[sizeof large_message - 1] = '\0';
+
+  check_syslog_udp (send_syslog_large, 0, check_syslog_message_large);
+  check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large);
+
+  check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large);
+  check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large);
+
+  check_syslog_udp (send_openlog_large, 0, check_openlog_message_large);
+  check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large);
+
+  check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large);
+  check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large);
+
+  check_syslog_console (send_openlog_large, check_syslog_console_read_large);
+
+  check_syslog_perror (true);
 
   return 0;
 }
diff --git a/nis/nis_call.c b/nis/nis_call.c
index 90187e30b1..5b9dd50151 100644
--- a/nis/nis_call.c
+++ b/nis/nis_call.c
@@ -574,7 +574,7 @@ static struct nis_server_cache
   unsigned int size;
   unsigned int server_used;
   unsigned int current_ep;
-  __time64_t expires;
+  time_t expires;
   char name[];
 } *nis_server_cache[16];
 static time_t nis_cold_start_mtime;
@@ -583,7 +583,7 @@ __libc_lock_define_initialized (static, nis_server_cache_lock)
 static directory_obj *
 nis_server_cache_search (const_nis_name name, int search_parent,
 			 unsigned int *server_used, unsigned int *current_ep,
-			 struct __timespec64 *now)
+			 struct timespec *now)
 {
   directory_obj *ret = NULL;
   int i;
@@ -641,7 +641,7 @@ nis_server_cache_search (const_nis_name name, int search_parent,
 static void
 nis_server_cache_add (const_nis_name name, int search_parent,
 		      directory_obj *dir, unsigned int server_used,
-		      unsigned int current_ep, struct __timespec64 *now)
+		      unsigned int current_ep, struct timespec *now)
 {
   struct nis_server_cache **loc;
   struct nis_server_cache *new;
@@ -707,7 +707,7 @@ __nisfind_server (const_nis_name name, int search_parent,
   nis_error result = NIS_SUCCESS;
   nis_error status;
   directory_obj *obj;
-  struct __timespec64 ts;
+  struct timespec ts;
   unsigned int server_used = ~0;
   unsigned int current_ep = ~0;
 
@@ -717,7 +717,7 @@ __nisfind_server (const_nis_name name, int search_parent,
   if (*dir != NULL)
     return NIS_SUCCESS;
 
-  __clock_gettime64 (CLOCK_REALTIME, &ts);
+  clock_gettime (CLOCK_REALTIME, &ts);
 
   if ((flags & NO_CACHE) == 0)
     *dir = nis_server_cache_search (name, search_parent, &server_used,
diff --git a/nptl/descr.h b/nptl/descr.h
index 5cacb286f3..bbb26607ef 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -34,7 +34,6 @@
 #include <bits/types/res_state.h>
 #include <kernel-features.h>
 #include <tls-internal-struct.h>
-#include <sys/rseq.h>
 #include <internal-sigset.h>
 
 #ifndef TCB_ALIGNMENT
@@ -402,14 +401,27 @@ struct pthread
   /* Used on strsignal.  */
   struct tls_internal_t tls_state;
 
-  /* rseq area registered with the kernel.  */
-  struct rseq rseq_area;
-
-  /* This member must be last.  */
-  char end_padding[];
-
+  /* rseq area registered with the kernel.  Use a custom definition
+     here to isolate from kernel struct rseq changes.  The
+     implementation of sched_getcpu needs acccess to the cpu_id field;
+     the other fields are unused and not included here.  */
+  union
+  {
+    struct
+    {
+      uint32_t cpu_id_start;
+      uint32_t cpu_id;
+      uint64_t rseq_cs;
+      uint32_t flags;
+    };
+    char pad[32];		/* Original rseq area size.  */
+  } rseq_area __attribute__ ((aligned (32)));
+
+  /* Amount of end padding, if any, in this structure.
+     This definition relies on rseq_area being last.  */
 #define PTHREAD_STRUCT_END_PADDING \
-  (sizeof (struct pthread) - offsetof (struct pthread, end_padding))
+  (sizeof (struct pthread) - offsetof (struct pthread, rseq_area) \
+   + sizeof ((struct pthread) {}.rseq_area))
 } __attribute ((aligned (TCB_ALIGNMENT)));
 
 static inline bool
diff --git a/nptl/tst-cancel7.c b/nptl/tst-cancel7.c
index 903457db76..1c80457553 100644
--- a/nptl/tst-cancel7.c
+++ b/nptl/tst-cancel7.c
@@ -43,7 +43,8 @@ tf (void *arg)
 {
   char *cmd = xasprintf ("%s --direct --sem %s --pidfile %s",
 			 command, semfilename, pidfilename);
-  system (cmd);
+  if (system (cmd))
+    FAIL_EXIT1("system call unexpectedly returned");
   /* This call should never return.  */
   return NULL;
 }
diff --git a/nptl/tst-setuid2.c b/nptl/tst-setuid2.c
index aff3b1a97d..9b7799991c 100644
--- a/nptl/tst-setuid2.c
+++ b/nptl/tst-setuid2.c
@@ -20,6 +20,7 @@
 #include <signal.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <support/xthread.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 
@@ -36,30 +37,21 @@ static pthread_cond_t cond_recv;
 static void *
 thread_func (void *ctx __attribute__ ((unused)))
 {
-  int ret = pthread_mutex_lock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (thread): %d", ret);
-
+  xpthread_mutex_lock (&mutex);
   while (true)
     {
       if (func_sent != NULL)
 	{
 	  void (*func) (void) = func_sent;
-	  ret = pthread_mutex_unlock (&mutex);
-	  if (ret != 0)
-	    FAIL ("pthread_mutex_unlock (thread): %d", ret);
+	  xpthread_mutex_unlock (&mutex);
+
 	  func ();
-	  ret = pthread_mutex_lock (&mutex);
-	  if (ret != 0)
-	    FAIL ("pthread_mutex_lock (thread): %d", ret);
+
+	  xpthread_mutex_lock (&mutex);
 	  func_sent = NULL;
-	  ret = pthread_cond_signal (&cond_recv);
-	  if (ret != 0)
-	    FAIL ("pthread_cond_signal (recv): %d", ret);
+	  xpthread_cond_signal (&cond_recv);
 	}
-      ret = pthread_cond_wait (&cond_send, &mutex);
-      if (ret != 0)
-	FAIL ("pthread_cond_wait (send): %d", ret);
+      xpthread_cond_wait (&cond_send, &mutex);
     }
   return NULL;
 }
@@ -67,31 +59,18 @@ thread_func (void *ctx __attribute__ ((unused)))
 static void
 run_on_thread (void (*func) (void))
 {
-  int ret = pthread_mutex_lock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
+  xpthread_mutex_lock (&mutex);
   func_sent = func;
-  ret = pthread_mutex_unlock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret);
+  xpthread_mutex_unlock (&mutex);
 
-  ret = pthread_cond_signal (&cond_send);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
-
-  ret = pthread_mutex_lock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
+  xpthread_cond_signal (&cond_send);
 
+  xpthread_mutex_lock (&mutex);
   while (func_sent != NULL)
     {
-      ret = pthread_cond_wait (&cond_recv, &mutex);
-      if (ret != 0)
-	FAIL ("pthread_mutex_wait (%s): %d", __func__, ret);
+      xpthread_cond_wait (&cond_recv, &mutex);
     }
-  ret = pthread_mutex_unlock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret);
+  xpthread_mutex_unlock (&mutex);
 }
 
 static void
@@ -141,5 +120,4 @@ do_test (void)
   return 0;
 }
 
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/nptl/tst-stackguard1.c b/nptl/tst-stackguard1.c
index 3460c01819..bc8900ce22 100644
--- a/nptl/tst-stackguard1.c
+++ b/nptl/tst-stackguard1.c
@@ -27,6 +27,8 @@
 #include <tls.h>
 #include <unistd.h>
 
+#include <support/xstdlib.h>
+
 static const char *command;
 static bool child;
 static uintptr_t stack_chk_guard_copy;
@@ -138,7 +140,8 @@ do_test (void)
 	  dup2 (fds[1], 2);
 	  close (fds[1]);
 
-	  system (command);
+	  xsystem (command);
+
 	  exit (0);
 	}
 
diff --git a/nscd/aicache.c b/nscd/aicache.c
index 51e793199f..e0baed170b 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 							  "gethostbyname4_r");
       if (fct4 != NULL)
 	{
-	  struct gaih_addrtuple atmem;
 	  struct gaih_addrtuple *at;
 	  while (1)
 	    {
-	      at = &atmem;
+	      at = NULL;
 	      rc6 = 0;
 	      herrno = 0;
 	      status[1] = DL_CALL_FCT (fct4, (key, &at,
@@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	    goto next_nip;
 
 	  /* We found the data.  Count the addresses and the size.  */
-	  for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL;
+	  for (const struct gaih_addrtuple *at2 = at; at2 != NULL;
 	       at2 = at2->next)
 	    {
 	      ++naddrs;
diff --git a/nscd/connections.c b/nscd/connections.c
index 61d1674eb4..531d2e83df 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd)
 					     sizeof (buf))) != -1)
 	      ;
 
-	    __bump_nl_timestamp ();
+	    dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
+	      = __bump_nl_timestamp ();
 	  }
 # endif
 	else
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index 85977521a6..adc34ba6b4 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <scratch_buffer.h>
 
 #include "../inet/netgroup.h"
 #include "nscd.h"
@@ -65,6 +66,16 @@ struct dataset
   char strdata[0];
 };
 
+/* Send a notfound response to FD.  Always returns -1 to indicate an
+   ephemeral error.  */
+static time_t
+send_notfound (int fd)
+{
+  if (fd != -1)
+    TEMP_FAILURE_RETRY (send (fd, &notfound, sizeof (notfound), MSG_NOSIGNAL));
+  return -1;
+}
+
 /* Sends a notfound message and prepares a notfound dataset to write to the
    cache.  Returns true if there was enough memory to allocate the dataset and
    returns the dataset in DATASETP, total bytes to write in TOTALP and the
@@ -83,8 +94,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
   total = sizeof (notfound);
   timeout = time (NULL) + db->negtimeout;
 
-  if (fd != -1)
-    TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
+  send_notfound (fd);
 
   dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
   /* If we cannot permanently store the result, so be it.  */
@@ -109,11 +119,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
   return cacheable;
 }
 
+struct addgetnetgrentX_scratch
+{
+  /* This is the result that the caller should use.  It can be NULL,
+     point into buffer, or it can be in the cache.  */
+  struct dataset *dataset;
+
+  struct scratch_buffer buffer;
+
+  /* Used internally in addgetnetgrentX as a staging area.  */
+  struct scratch_buffer tmp;
+
+  /* Number of bytes in buffer that are actually used.  */
+  size_t buffer_used;
+};
+
+static void
+addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch)
+{
+  scratch->dataset = NULL;
+  scratch_buffer_init (&scratch->buffer);
+  scratch_buffer_init (&scratch->tmp);
+
+  /* Reserve space for the header.  */
+  scratch->buffer_used = sizeof (struct dataset);
+  static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space),
+		 "initial buffer space");
+  memset (scratch->tmp.data, 0, sizeof (struct dataset));
+}
+
+static void
+addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch)
+{
+  scratch_buffer_free (&scratch->buffer);
+  scratch_buffer_free (&scratch->tmp);
+}
+
+/* Copy LENGTH bytes from S into SCRATCH.  Returns NULL if SCRATCH
+   could not be resized, otherwise a pointer to the copy.  */
+static char *
+addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch,
+			  const char *s, size_t length)
+{
+  while (true)
+    {
+      size_t remaining = scratch->buffer.length - scratch->buffer_used;
+      if (remaining >= length)
+	break;
+      if (!scratch_buffer_grow_preserve (&scratch->buffer))
+	return NULL;
+    }
+  char *copy = scratch->buffer.data + scratch->buffer_used;
+  memcpy (copy, s, length);
+  scratch->buffer_used += length;
+  return copy;
+}
+
+/* Copy S into SCRATCH, including its null terminator.  Returns false
+   if SCRATCH could not be resized.  */
+static bool
+addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s)
+{
+  if (s == NULL)
+    s = "";
+  return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL;
+}
+
+/* Caller must initialize and free *SCRATCH.  If the return value is
+   negative, this function has sent a notfound response.  */
 static time_t
 addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		 const char *key, uid_t uid, struct hashentry *he,
-		 struct datahead *dh, struct dataset **resultp,
-		 void **tofreep)
+		 struct datahead *dh, struct addgetnetgrentX_scratch *scratch)
 {
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -132,14 +209,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 
   char *key_copy = NULL;
   struct __netgrent data;
-  size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
-  size_t buffilled = sizeof (*dataset);
-  char *buffer = NULL;
   size_t nentries = 0;
   size_t group_len = strlen (key) + 1;
   struct name_list *first_needed
     = alloca (sizeof (struct name_list) + group_len);
-  *tofreep = NULL;
 
   if (netgroup_database == NULL
       && !__nss_database_get (nss_database_netgroup, &netgroup_database))
@@ -147,12 +220,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
       /* No such service.  */
       cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
 			       &key_copy);
-      goto writeout;
+      goto maybe_cache_add;
     }
 
   memset (&data, '\0', sizeof (data));
-  buffer = xmalloc (buflen);
-  *tofreep = buffer;
   first_needed->next = first_needed;
   memcpy (first_needed->name, key, group_len);
   data.needed_groups = first_needed;
@@ -195,8 +266,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		while (1)
 		  {
 		    int e;
-		    status = getfct.f (&data, buffer + buffilled,
-				       buflen - buffilled - req->key_len, &e);
+		    status = getfct.f (&data, scratch->tmp.data,
+				       scratch->tmp.length, &e);
 		    if (status == NSS_STATUS_SUCCESS)
 		      {
 			if (data.type == triple_val)
@@ -204,68 +275,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 			    const char *nhost = data.val.triple.host;
 			    const char *nuser = data.val.triple.user;
 			    const char *ndomain = data.val.triple.domain;
-
-			    size_t hostlen = strlen (nhost ?: "") + 1;
-			    size_t userlen = strlen (nuser ?: "") + 1;
-			    size_t domainlen = strlen (ndomain ?: "") + 1;
-
-			    if (nhost == NULL || nuser == NULL || ndomain == NULL
-				|| nhost > nuser || nuser > ndomain)
-			      {
-				const char *last = nhost;
-				if (last == NULL
-				    || (nuser != NULL && nuser > last))
-				  last = nuser;
-				if (last == NULL
-				    || (ndomain != NULL && ndomain > last))
-				  last = ndomain;
-
-				size_t bufused
-				  = (last == NULL
-				     ? buffilled
-				     : last + strlen (last) + 1 - buffer);
-
-				/* We have to make temporary copies.  */
-				size_t needed = hostlen + userlen + domainlen;
-
-				if (buflen - req->key_len - bufused < needed)
-				  {
-				    buflen += MAX (buflen, 2 * needed);
-				    /* Save offset in the old buffer.  We don't
-				       bother with the NULL check here since
-				       we'll do that later anyway.  */
-				    size_t nhostdiff = nhost - buffer;
-				    size_t nuserdiff = nuser - buffer;
-				    size_t ndomaindiff = ndomain - buffer;
-
-				    char *newbuf = xrealloc (buffer, buflen);
-				    /* Fix up the triplet pointers into the new
-				       buffer.  */
-				    nhost = (nhost ? newbuf + nhostdiff
-					     : NULL);
-				    nuser = (nuser ? newbuf + nuserdiff
-					     : NULL);
-				    ndomain = (ndomain ? newbuf + ndomaindiff
-					       : NULL);
-				    *tofreep = buffer = newbuf;
-				  }
-
-				nhost = memcpy (buffer + bufused,
-						nhost ?: "", hostlen);
-				nuser = memcpy ((char *) nhost + hostlen,
-						nuser ?: "", userlen);
-				ndomain = memcpy ((char *) nuser + userlen,
-						  ndomain ?: "", domainlen);
-			      }
-
-			    char *wp = buffer + buffilled;
-			    wp = memmove (wp, nhost ?: "", hostlen);
-			    wp += hostlen;
-			    wp = memmove (wp, nuser ?: "", userlen);
-			    wp += userlen;
-			    wp = memmove (wp, ndomain ?: "", domainlen);
-			    wp += domainlen;
-			    buffilled = wp - buffer;
+			    if (!(addgetnetgrentX_append (scratch, nhost)
+				  && addgetnetgrentX_append (scratch, nuser)
+				  && addgetnetgrentX_append (scratch, ndomain)))
+			      return send_notfound (fd);
 			    ++nentries;
 			  }
 			else
@@ -317,8 +330,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		      }
 		    else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
 		      {
-			buflen *= 2;
-			*tofreep = buffer = xrealloc (buffer, buflen);
+			if (!scratch_buffer_grow (&scratch->tmp))
+			  return send_notfound (fd);
 		      }
 		    else if (status == NSS_STATUS_RETURN
 			     || status == NSS_STATUS_NOTFOUND
@@ -348,13 +361,20 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     {
       cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
 			       &key_copy);
-      goto writeout;
+      goto maybe_cache_add;
     }
 
-  total = buffilled;
+  /* Capture the result size without the key appended.   */
+  total = scratch->buffer_used;
+
+  /* Make a copy of the key.  The scratch buffer must not move after
+     this point.  */
+  key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len);
+  if (key_copy == NULL)
+    return send_notfound (fd);
 
   /* Fill in the dataset.  */
-  dataset = (struct dataset *) buffer;
+  dataset = scratch->buffer.data;
   timeout = datahead_init_pos (&dataset->head, total + req->key_len,
 			       total - offsetof (struct dataset, resp),
 			       he == NULL ? 0 : dh->nreloads + 1,
@@ -363,11 +383,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
   dataset->resp.version = NSCD_VERSION;
   dataset->resp.found = 1;
   dataset->resp.nresults = nentries;
-  dataset->resp.result_len = buffilled - sizeof (*dataset);
-
-  assert (buflen - buffilled >= req->key_len);
-  key_copy = memcpy (buffer + buffilled, key, req->key_len);
-  buffilled += req->key_len;
+  dataset->resp.result_len = total - sizeof (*dataset);
 
   /* Now we can determine whether on refill we have to create a new
      record or not.  */
@@ -398,7 +414,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     if (__glibc_likely (newp != NULL))
       {
 	/* Adjust pointer into the memory block.  */
-	key_copy = (char *) newp + (key_copy - buffer);
+	key_copy = (char *) newp + (key_copy - (char *) dataset);
 
 	dataset = memcpy (newp, dataset, total + req->key_len);
 	cacheable = true;
@@ -410,14 +426,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
   }
 
   if (he == NULL && fd != -1)
-    {
-      /* We write the dataset before inserting it to the database
-	 since while inserting this thread might block and so would
-	 unnecessarily let the receiver wait.  */
-    writeout:
+    /* We write the dataset before inserting it to the database since
+       while inserting this thread might block and so would
+       unnecessarily let the receiver wait.  */
       writeall (fd, &dataset->resp, dataset->head.recsize);
-    }
 
+ maybe_cache_add:
   if (cacheable)
     {
       /* If necessary, we also propagate the data to disk.  */
@@ -441,7 +455,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     }
 
  out:
-  *resultp = dataset;
+  scratch->dataset = dataset;
 
   return timeout;
 }
@@ -462,6 +476,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
   if (user != NULL)
     key = (char *) rawmemchr (key, '\0') + 1;
   const char *domain = *key++ ? key : NULL;
+  struct addgetnetgrentX_scratch scratch;
+
+  addgetnetgrentX_scratch_init (&scratch);
 
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -477,12 +494,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
 							    group, group_len,
 							    db, uid);
   time_t timeout;
-  void *tofree;
   if (result != NULL)
-    {
-      timeout = result->head.timeout;
-      tofree = NULL;
-    }
+    timeout = result->head.timeout;
   else
     {
       request_header req_get =
@@ -491,7 +504,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
 	  .key_len = group_len
 	};
       timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
-				 &result, &tofree);
+				 &scratch);
+      result = scratch.dataset;
+      if (timeout < 0)
+	goto out;
     }
 
   struct indataset
@@ -502,24 +518,26 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
       = (struct indataset *) mempool_alloc (db,
 					    sizeof (*dataset) + req->key_len,
 					    1);
-  struct indataset dataset_mem;
   bool cacheable = true;
   if (__glibc_unlikely (dataset == NULL))
     {
       cacheable = false;
-      dataset = &dataset_mem;
+      /* The alloca is safe because nscd_run_worker verfies that
+	 key_len is not larger than MAXKEYLEN.  */
+      dataset = alloca (sizeof (*dataset) + req->key_len);
     }
 
   datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
 		     sizeof (innetgroup_response_header),
-		     he == NULL ? 0 : dh->nreloads + 1, result->head.ttl);
+		     he == NULL ? 0 : dh->nreloads + 1,
+		     result == NULL ? db->negtimeout : result->head.ttl);
   /* Set the notfound status and timeout based on the result from
      getnetgrent.  */
-  dataset->head.notfound = result->head.notfound;
+  dataset->head.notfound = result == NULL || result->head.notfound;
   dataset->head.timeout = timeout;
 
   dataset->resp.version = NSCD_VERSION;
-  dataset->resp.found = result->resp.found;
+  dataset->resp.found = result != NULL && result->resp.found;
   /* Until we find a matching entry the result is 0.  */
   dataset->resp.result = 0;
 
@@ -567,7 +585,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
       goto out;
     }
 
-  if (he == NULL)
+  /* addgetnetgrentX may have already sent a notfound response.  Do
+     not send another one.  */
+  if (he == NULL && dataset->resp.found)
     {
       /* We write the dataset before inserting it to the database
 	 since while inserting this thread might block and so would
@@ -601,7 +621,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
     }
 
  out:
-  free (tofree);
+  addgetnetgrentX_scratch_free (&scratch);
   return timeout;
 }
 
@@ -611,11 +631,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
 			const char *key, uid_t uid, struct hashentry *he,
 			struct datahead *dh)
 {
-  struct dataset *ignore;
-  void *tofree;
-  time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
-				    &ignore, &tofree);
-  free (tofree);
+  struct addgetnetgrentX_scratch scratch;
+  addgetnetgrentX_scratch_init (&scratch);
+  time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch);
+  addgetnetgrentX_scratch_free (&scratch);
+  if (timeout < 0)
+    timeout = 0;
   return timeout;
 }
 
@@ -659,5 +680,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he,
       .key_len = he->len
     };
 
-  return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
+  time_t timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner,
+				he, dh);
+  if (timeout < 0)
+    timeout = 0;
+  return timeout;
 }
diff --git a/nscd/nscd.h b/nscd/nscd.h
index 368091aef8..f15321585b 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -65,7 +65,7 @@ typedef enum
 struct traced_file
 {
   /* Tracks the last modified time of the traced file.  */
-  time_t mtime;
+  __time64_t mtime;
   /* Support multiple registered files per database.  */
   struct traced_file *next;
   int call_res_init;
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
index 9becb62033..31c64275f0 100644
--- a/nscd/nscd_gethst_r.c
+++ b/nscd/nscd_gethst_r.c
@@ -112,7 +112,7 @@ __nscd_get_nl_timestamp (void)
   if (map == NULL
       || (map != NO_MAPPING
 	  && map->head->nscd_certainly_running == 0
-	  && map->head->timestamp + MAPPING_TIMEOUT < time_now ()))
+	  && map->head->timestamp + MAPPING_TIMEOUT < time64_now ()))
     map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped);
 
   if (map == NO_MAPPING)
diff --git a/nss/Makefile b/nss/Makefile
index a978e3927a..7a52c68791 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -81,6 +81,7 @@ tests-container := \
   tst-nss-test3 \
   tst-reload1 \
   tst-reload2 \
+  tst-nss-gai-hv2-canonname \
 # tests-container
 
 # Tests which need libdl
@@ -144,7 +145,17 @@ libnss_compat-inhibit-o	= $(filter-out .os,$(object-suffixes))
 ifeq ($(build-static-nss),yes)
 tests-static		+= tst-nss-static
 endif
-extra-test-objs		+= nss_test1.os nss_test2.os nss_test_errno.os
+extra-test-objs		+= nss_test1.os nss_test2.os nss_test_errno.os \
+			   nss_test_gai_hv2_canonname.os
+
+ifeq ($(run-built-tests),yes)
+ifneq (no,$(PERL))
+tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out
+endif
+endif
+
+generated += mtrace-tst-nss-gai-hv2-canonname.out \
+		tst-nss-gai-hv2-canonname.mtrace
 
 include ../Rules
 
@@ -179,12 +190,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
 libof-nss_test1 = extramodules
 libof-nss_test2 = extramodules
 libof-nss_test_errno = extramodules
+libof-nss_test_gai_hv2_canonname = extramodules
 $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
 	$(build-module)
 $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
 	$(build-module)
 $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
 	$(build-module)
+$(objpfx)/libnss_test_gai_hv2_canonname.so: \
+  $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps)
+	$(build-module)
 $(objpfx)nss_test2.os : nss_test1.c
 # Use the nss_files suffix for these objects as well.
 $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so
@@ -194,10 +209,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so
 $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
   $(objpfx)/libnss_test_errno.so
 	$(make-link)
+$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \
+  $(objpfx)/libnss_test_gai_hv2_canonname.so
+	$(make-link)
 $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \
 	$(objpfx)/libnss_test1.so$(libnss_files.so-version) \
 	$(objpfx)/libnss_test2.so$(libnss_files.so-version) \
-	$(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
+	$(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \
+	$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version)
 
 ifeq (yes,$(have-thread-library))
 $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
@@ -206,6 +225,17 @@ endif
 $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
 $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so
 
+tst-nss-gai-hv2-canonname-ENV = \
+		MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \
+		LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \
+  $(objpfx)tst-nss-gai-hv2-canonname.out
+	{ test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \
+	|| ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \
+	&& $(common-objpfx)malloc/mtrace \
+	$(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \
+	$(evaluate-test)
+
 # Disable DT_RUNPATH on NSS tests so that the glibc internal NSS
 # functions can load testing NSS modules via DT_RPATH.
 LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags
@@ -214,3 +244,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags
 LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags
 LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags
 LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags
+LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags
diff --git a/nss/getent.c b/nss/getent.c
index 8178b4b470..d2d2524b0c 100644
--- a/nss/getent.c
+++ b/nss/getent.c
@@ -58,6 +58,8 @@ static const struct argp_option args_options[] =
   {
     { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") },
     { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
+    { "no-addrconfig", 'A', NULL, 0,
+      N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") },
     { NULL, 0, NULL, 0, NULL },
   };
 
@@ -79,6 +81,9 @@ static struct argp argp =
 /* Additional getaddrinfo flags for IDN encoding.  */
 static int idn_flags = AI_IDN | AI_CANONIDN;
 
+/* Set to 0 by --no-addrconfig.  */
+static int addrconfig_flags = AI_ADDRCONFIG;
+
 /* Print the version information.  */
 static void
 print_version (FILE *stream, struct argp_state *state)
@@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[])
 
   struct addrinfo hint;
   memset (&hint, '\0', sizeof (hint));
-  hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME
+  hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME
 		   | idn_flags | xflags);
   hint.ai_family = af;
 
@@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state)
       idn_flags = 0;
       break;
 
+    case 'A':
+      addrconfig_flags = 0;
+      break;
+
     default:
       return ARGP_ERR_UNKNOWN;
     }
diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c
new file mode 100644
index 0000000000..4439c83c9f
--- /dev/null
+++ b/nss/nss_test_gai_hv2_canonname.c
@@ -0,0 +1,56 @@
+/* NSS service provider that only provides gethostbyname2_r.
+   Copyright The GNU Toolchain Authors.
+   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 <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+/* Catch misnamed and functions.  */
+#pragma GCC diagnostic error "-Wmissing-prototypes"
+NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname)
+
+extern enum nss_status _nss_files_gethostbyname2_r (const char *, int,
+						    struct hostent *, char *,
+						    size_t, int *, int *);
+
+enum nss_status
+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af,
+					      struct hostent *result,
+					      char *buffer, size_t buflen,
+					      int *errnop, int *herrnop)
+{
+  return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop,
+				      herrnop);
+}
+
+enum nss_status
+_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer,
+					    size_t buflen, char **result,
+					    int *errnop, int *h_errnop)
+{
+  /* We expect QUERYNAME, which is a small enough string that it shouldn't fail
+     the test.  */
+  if (memcmp (QUERYNAME, name, sizeof (QUERYNAME))
+      || buflen < sizeof (QUERYNAME))
+    abort ();
+
+  strncpy (buffer, name, buflen);
+  *result = buffer;
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/nss/tst-nss-db-endpwent.c b/nss/tst-nss-db-endpwent.c
index da4ab643e7..c2417b2505 100644
--- a/nss/tst-nss-db-endpwent.c
+++ b/nss/tst-nss-db-endpwent.c
@@ -23,6 +23,7 @@
 
 #include <support/support.h>
 #include <support/check.h>
+#include <support/xstdlib.h>
 
 /* It is entirely allowed to start with a getpwent call without
    resetting the state of the service via a call to setpwent.
@@ -55,7 +56,7 @@ do_test (void)
 
   cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in",
 		   support_bindir_prefix);
-  system (cmd);
+  xsystem (cmd);
   free (cmd);
 
   try_it ();
diff --git a/nss/tst-nss-files-hosts-long.c b/nss/tst-nss-files-hosts-long.c
index 3942cf5fca..a7697e3143 100644
--- a/nss/tst-nss-files-hosts-long.c
+++ b/nss/tst-nss-files-hosts-long.c
@@ -28,14 +28,15 @@ do_test (void)
 {
   int ret;
 
-  /* Run getent to fetch the IPv4 address for host test4.
-     This forces /etc/hosts to be parsed.  */
-  ret = system("getent ahostsv4 test4");
+  /* Run getent to fetch the IPv4 address for host test4.  This forces
+     /etc/hosts to be parsed.  Use --no-addrconfig to return addresses
+     even in an IPv6-only environment.  */
+  ret = system("getent --no-addrconfig ahostsv4 test4");
   if (ret != 0)
     FAIL_EXIT1("ahostsv4 failed");
 
   /* Likewise for IPv6.  */
-  ret = system("getent ahostsv6 test6");
+  ret = system("getent --no-addrconfig  ahostsv6 test6");
   if (ret != 0)
     FAIL_EXIT1("ahostsv6 failed");
 
diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
new file mode 100644
index 0000000000..7db53cf09d
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.c
@@ -0,0 +1,66 @@
+/* Test NSS query path for plugins that only implement gethostbyname2
+   (#30843).
+   Copyright The GNU Toolchain Authors.
+   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 <nss.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mcheck.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+#define PREPARE do_prepare
+
+static void do_prepare (int a, char **av)
+{
+  FILE *hosts = xfopen ("/etc/hosts", "w");
+  for (unsigned i = 2; i < 255; i++)
+    {
+      fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i);
+      fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i);
+    }
+  xfclose (hosts);
+}
+
+static int
+do_test (void)
+{
+  mtrace ();
+
+  __nss_configure_lookup ("hosts", "test_gai_hv2_canonname");
+
+  struct addrinfo hints = {};
+  struct addrinfo *result = NULL;
+
+  hints.ai_family = AF_INET6;
+  hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME;
+
+  int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result);
+
+  if (ret != 0)
+    FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret));
+
+  TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME);
+
+  freeaddrinfo(result);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
new file mode 100644
index 0000000000..14f2a9cb08
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.h
@@ -0,0 +1 @@
+#define QUERYNAME "test.example.com"
diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
new file mode 100644
index 0000000000..31848b4a28
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
@@ -0,0 +1,2 @@
+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
+su
diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c
index fdc5bdd65b..bc32bb132a 100644
--- a/nss/tst-reload1.c
+++ b/nss/tst-reload1.c
@@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = {
 
 static const char *hostaddr_5[] =
   {
-   "ABCD", "abcd", "1234", NULL
+   "ABCd", "ABCD", "ABC4", NULL
   };
 
 static const char *hostaddr_15[] =
   {
-   "4321", "ghij", NULL
+   "4321", "4322", NULL
   };
 
 static const char *hostaddr_25[] =
@@ -86,12 +86,12 @@ static const char *hostaddr_6[] =
 
 static const char *hostaddr_16[] =
   {
-   "7890", "a1b2", NULL
+   "7890", "7891", NULL
   };
 
 static const char *hostaddr_26[] =
   {
-   "qwer", "tyui", NULL
+   "qwer", "qweR", NULL
   };
 
 static struct hostent host_table_2[] = {
diff --git a/posix/Makefile b/posix/Makefile
index d1df7c27cb..336bee4a4a 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -109,7 +109,7 @@ tests		:= test-errno tstgetopt testfnm runtests runptests \
 		   tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
 		   bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
 		   tst-wordexp-nocmd tst-execveat tst-spawn5 \
-		   tst-sched_getaffinity tst-spawn6
+		   tst-sched_getaffinity tst-spawn6 tst-regcomp-bracket-free
 
 # Test for the glob symbol version that was replaced in glibc 2.27.
 ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
diff --git a/posix/regcomp.c b/posix/regcomp.c
index 84fc1cc82b..7bd0beeafe 100644
--- a/posix/regcomp.c
+++ b/posix/regcomp.c
@@ -3383,6 +3383,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
     {
 #ifdef RE_ENABLE_I18N
       free_charset (mbcset);
+      mbcset = NULL;
 #endif
       /* Build a tree for simple bracket.  */
       br_token.type = SIMPLE_BRACKET;
@@ -3398,7 +3399,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
  parse_bracket_exp_free_return:
   re_free (sbcset);
 #ifdef RE_ENABLE_I18N
-  free_charset (mbcset);
+  if (__glibc_likely (mbcset != NULL))
+    free_charset (mbcset);
 #endif /* RE_ENABLE_I18N */
   return NULL;
 }
diff --git a/posix/tst-regcomp-bracket-free.c b/posix/tst-regcomp-bracket-free.c
new file mode 100644
index 0000000000..3c091d8c44
--- /dev/null
+++ b/posix/tst-regcomp-bracket-free.c
@@ -0,0 +1,176 @@
+/* Test regcomp bracket parsing with injected allocation failures (bug 33185).
+   Copyright (C) 2025 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/>.  */
+
+/* This test invokes regcomp multiple times, failing one memory
+   allocation in each call.  The function call should fail with
+   REG_ESPACE (or succeed if it can recover from the allocation
+   failure).  Previously, there was double-free bug.  */
+
+#include <errno.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+
+/* Data structure allocated via MAP_SHARED, so that writes from the
+   subprocess are visible.  */
+struct shared_data
+{
+  /* Number of tracked allocations performed so far.  */
+  volatile unsigned int allocation_count;
+
+  /* If this number is reached, one allocation fails.  */
+  volatile unsigned int failing_allocation;
+
+  /* The subprocess stores the expected name here.  */
+  char name[100];
+};
+
+/* Allocation count in shared mapping.  */
+static struct shared_data *shared;
+
+/* Returns true if a failure should be injected for this allocation.  */
+static bool
+fail_this_allocation (void)
+{
+  if (shared != NULL)
+    {
+      unsigned int count = shared->allocation_count;
+      shared->allocation_count = count + 1;
+      return count == shared->failing_allocation;
+    }
+  else
+    return false;
+}
+
+/* Failure-injecting wrappers for allocation functions used by glibc.  */
+
+void *
+malloc (size_t size)
+{
+  if (fail_this_allocation ())
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+  extern __typeof (malloc) __libc_malloc;
+  return __libc_malloc (size);
+}
+
+void *
+calloc (size_t a, size_t b)
+{
+  if (fail_this_allocation ())
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+  extern __typeof (calloc) __libc_calloc;
+  return __libc_calloc (a, b);
+}
+
+void *
+realloc (void *ptr, size_t size)
+{
+  if (fail_this_allocation ())
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+  extern __typeof (realloc) __libc_realloc;
+  return __libc_realloc (ptr, size);
+}
+
+/* No-op subprocess to verify that support_isolate_in_subprocess does
+   not perform any heap allocations.  */
+static void
+no_op (void *ignored)
+{
+}
+
+/* Perform a regcomp call in a subprocess.  Used to count its
+   allocations.  */
+static void
+initialize (void *regexp1)
+{
+  const char *regexp = regexp1;
+
+  shared->allocation_count = 0;
+
+  regex_t reg;
+  TEST_COMPARE (regcomp (&reg, regexp, 0), 0);
+}
+
+/* Perform regcomp in a subprocess with fault injection.  */
+static void
+test_in_subprocess (void *regexp1)
+{
+  const char *regexp = regexp1;
+  unsigned int inject_at = shared->failing_allocation;
+
+  regex_t reg;
+  int ret = regcomp (&reg, regexp, 0);
+
+  if (ret != 0)
+    {
+      TEST_COMPARE (ret, REG_ESPACE);
+      printf ("info: allocation %u failure results in return value %d,"
+              " error %s (%d)\n",
+              inject_at, ret, strerrorname_np (errno), errno);
+    }
+}
+
+static int
+do_test (void)
+{
+  char regexp[] = "[:alpha:]";
+
+  shared = support_shared_allocate (sizeof (*shared));
+
+  /* Disable fault injection.  */
+  shared->failing_allocation = ~0U;
+
+  support_isolate_in_subprocess (no_op, NULL);
+  TEST_COMPARE (shared->allocation_count, 0);
+
+  support_isolate_in_subprocess (initialize, regexp);
+
+  /* The number of allocations in the successful case, plus some
+     slack.  Once the number of expected allocations is exceeded,
+     injecting further failures does not make a difference.  */
+  unsigned int maximum_allocation_count = shared->allocation_count;
+  printf ("info: successful call performs %u allocations\n",
+          maximum_allocation_count);
+  maximum_allocation_count += 10;
+
+  for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
+       ++inject_at)
+    {
+      shared->allocation_count = 0;
+      shared->failing_allocation = inject_at;
+      support_isolate_in_subprocess (test_in_subprocess, regexp);
+    }
+
+  support_shared_free (shared);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/tst-truncate-common.c b/posix/tst-truncate-common.c
index c8093c5473..39061ce6c5 100644
--- a/posix/tst-truncate-common.c
+++ b/posix/tst-truncate-common.c
@@ -21,6 +21,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <support/check.h>
+
 static void do_prepare (void);
 #define PREPARE(argc, argv)     do_prepare ()
 static int do_test (void);
@@ -42,9 +44,6 @@ do_prepare (void)
     }
 }
 
-#define FAIL(str) \
-  do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0)
-
 static int
 do_test_with_offset (off_t offset)
 {
@@ -54,35 +53,35 @@ do_test_with_offset (off_t offset)
   memset (buf, 0xcf, sizeof (buf));
 
   if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf))
-    FAIL ("write failed");
+    FAIL_RET ("write failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf)))
-    FAIL ("initial size wrong");
+    FAIL_RET ("initial size wrong");
 
   if (ftruncate (temp_fd, offset + 800) < 0)
-    FAIL ("size reduction with ftruncate failed");
+    FAIL_RET ("size reduction with ftruncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
-    FAIL ("size after reduction with ftruncate is incorrect");
+    FAIL_RET ("size after reduction with ftruncate is incorrect");
 
   /* The following test covers more than POSIX.  POSIX does not require
      that ftruncate() can increase the file size.  But we are testing
      Unix systems.  */
   if (ftruncate (temp_fd, offset + 1200) < 0)
-    FAIL ("size increate with ftruncate failed");
+    FAIL_RET ("size increate with ftruncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
-    FAIL ("size after increase is incorrect");
+    FAIL_RET ("size after increase is incorrect");
 
   if (truncate (temp_filename, offset + 800) < 0)
-    FAIL ("size reduction with truncate failed");
+    FAIL_RET ("size reduction with truncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
-    FAIL ("size after reduction with truncate incorrect");
+    FAIL_RET ("size after reduction with truncate incorrect");
 
   /* The following test covers more than POSIX.  POSIX does not require
      that truncate() can increase the file size.  But we are testing
      Unix systems.  */
   if (truncate (temp_filename, (offset + 1200)) < 0)
-    FAIL ("size increase with truncate failed");
+    FAIL_RET ("size increase with truncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
-    FAIL ("size increase with truncate is incorrect");
+    FAIL_RET ("size increase with truncate is incorrect");
 
   return 0;
 }
diff --git a/resolv/Makefile b/resolv/Makefile
index 5b15321f9b..e5165fb34b 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -40,12 +40,16 @@ routines := \
   inet_pton \
   ns_makecanon \
   ns_name_compress \
+  ns_name_length_uncompressed \
   ns_name_ntop \
   ns_name_pack \
   ns_name_pton \
   ns_name_skip \
   ns_name_uncompress \
   ns_name_unpack \
+  ns_rr_cursor_init \
+  ns_rr_cursor_next \
+  ns_samebinaryname \
   ns_samename \
   nsap_addr \
   nss_dns_functions \
@@ -89,14 +93,20 @@ tests += \
   tst-ns_name_pton \
   tst-res_hconf_reorder \
   tst-res_hnok \
+  tst-resolv-aliases \
   tst-resolv-basic \
   tst-resolv-binary \
+  tst-resolv-byaddr \
   tst-resolv-edns \
+  tst-resolv-invalid-cname \
   tst-resolv-network \
   tst-resolv-noaaaa \
+  tst-resolv-noaaaa-vc \
   tst-resolv-nondecimal \
   tst-resolv-res_init-multi \
   tst-resolv-search \
+  tst-resolv-semi-failure \
+  tst-resolv-short-response \
   tst-resolv-trailing \
 
 # This test calls __res_context_send directly, which is not exported
@@ -104,6 +114,18 @@ tests += \
 tests-internal += tst-resolv-txnid-collision
 tests-static += tst-resolv-txnid-collision
 
+# Likewise for __ns_samebinaryname.
+tests-internal += tst-ns_samebinaryname
+tests-static += tst-ns_samebinaryname
+
+# Likewise for __ns_name_length_uncompressed.
+tests-internal += tst-ns_name_length_uncompressed
+tests-static += tst-ns_name_length_uncompressed
+
+# Likewise for struct ns_rr_cursor and its functions.
+tests-internal += tst-ns_rr_cursor
+tests-static += tst-ns_rr_cursor
+
 # These tests need libdl.
 ifeq (yes,$(build-shared))
 tests += \
@@ -258,8 +280,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales)
 $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales)
 $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \
   $(gen-locales) $(objpfx)tst-no-libidn2.so
+$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
@@ -267,11 +291,18 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
   $(shared-thread-library)
 $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
   $(shared-thread-library)
+$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
+  $(shared-thread-library)
 $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-semi-failure: $(objpfx)libresolv.so \
+  $(shared-thread-library)
+$(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \
+  $(shared-thread-library)
 $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-threads: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \
diff --git a/resolv/README b/resolv/README
index 514e9bb617..2146bc3b27 100644
--- a/resolv/README
+++ b/resolv/README
@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c.
 
 res_hconf.c and res_hconf.h were contributed by David Mosberger, and
 do not come from BIND.
-
-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are
-leftovers from BIND 4.9.7.
diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h
deleted file mode 100644
index 7f85f7d5e3..0000000000
--- a/resolv/mapv4v6addr.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * ++Copyright++ 1985, 1988, 1993
- * -
- * Copyright (c) 1985, 1988, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- * -
- * --Copyright--
- */
-
-#include <string.h>
-#include <arpa/nameser.h>
-
-static void
-map_v4v6_address (const char *src, char *dst)
-{
-  u_char *p = (u_char *) dst;
-  int i;
-
-  /* Move the IPv4 part to the right position.  */
-  memcpy (dst + 12, src, INADDRSZ);
-
-  /* Mark this ipv6 addr as a mapped ipv4. */
-  for (i = 0; i < 10; i++)
-    *p++ = 0x00;
-  *p++ = 0xff;
-  *p = 0xff;
-}
diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h
deleted file mode 100644
index c11038adf3..0000000000
--- a/resolv/mapv4v6hostent.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * ++Copyright++ 1985, 1988, 1993
- * -
- * Copyright (c) 1985, 1988, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * -
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- * -
- * --Copyright--
- */
-
-#include <arpa/nameser.h>
-#include <sys/socket.h>
-
-typedef union {
-    int32_t al;
-    char ac;
-} align;
-
-static int
-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
-{
-  char **ap;
-
-  if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
-    return 0;
-  hp->h_addrtype = AF_INET6;
-  hp->h_length = IN6ADDRSZ;
-  for (ap = hp->h_addr_list; *ap; ap++)
-    {
-      int i = sizeof (align) - ((u_long) *bpp % sizeof (align));
-
-      if (*lenp < (i + IN6ADDRSZ))
-	/* Out of memory.  */
-	return 1;
-      *bpp += i;
-      *lenp -= i;
-      map_v4v6_address (*ap, *bpp);
-      *ap = *bpp;
-      *bpp += IN6ADDRSZ;
-      *lenp -= IN6ADDRSZ;
-    }
-  return 0;
-}
diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c
new file mode 100644
index 0000000000..51296b47ef
--- /dev/null
+++ b/resolv/ns_name_length_uncompressed.c
@@ -0,0 +1,72 @@
+/* Skip over an uncompressed name in wire format.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <errno.h>
+#include <stdbool.h>
+
+int
+__ns_name_length_uncompressed (const unsigned char *p,
+                                const unsigned char *eom)
+{
+  const unsigned char *start = p;
+
+  while (true)
+    {
+      if (p == eom)
+        {
+          /* Truncated packet: no room for label length.  */
+          __set_errno (EMSGSIZE);
+          return -1;
+        }
+
+      unsigned char b = *p;
+      ++p;
+      if (b == 0)
+        {
+          /* Root label.  */
+          size_t length = p - start;
+          if (length > NS_MAXCDNAME)
+            {
+              /* Domain name too long.  */
+              __set_errno (EMSGSIZE);
+              return -1;
+            }
+          return length;
+        }
+
+      if (b <= 63)
+        {
+          /* Regular label.  */
+          if (b <= eom - p)
+            p += b;
+          else
+            {
+              /* Truncated packet: label incomplete.  */
+              __set_errno (EMSGSIZE);
+              return -1;
+            }
+        }
+      else
+        {
+          /* Compression reference or corrupted label length.  */
+          __set_errno (EMSGSIZE);
+          return -1;
+        }
+    }
+}
diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c
new file mode 100644
index 0000000000..6ee80b30e9
--- /dev/null
+++ b/resolv/ns_rr_cursor_init.c
@@ -0,0 +1,62 @@
+/* Initialize a simple DNS packet parser.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+bool
+__ns_rr_cursor_init (struct ns_rr_cursor *c,
+                     const unsigned char *buf, size_t len)
+{
+  c->begin = buf;
+  c->end = buf + len;
+
+  /* Check for header size and 16-bit question count value (it must be 1).  */
+  if (len < 12 || buf[4] != 0 || buf[5] != 1)
+    {
+      __set_errno (EMSGSIZE);
+      c->current = c->end;
+      return false;
+    }
+  c->current = buf + 12;
+
+  int consumed = __ns_name_length_uncompressed (c->current, c->end);
+  if (consumed < 0)
+    {
+      __set_errno (EMSGSIZE);
+      c->current = c->end;
+      c->first_rr = NULL;
+      return false;
+    }
+  c->current += consumed;
+
+  /* Ensure there is room for question type and class.  */
+  if (c->end - c->current < 4)
+    {
+      __set_errno (EMSGSIZE);
+      c->current = c->end;
+      c->first_rr = NULL;
+      return false;
+    }
+  c->current += 4;
+  c->first_rr = c->current;
+
+  return true;
+}
diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c
new file mode 100644
index 0000000000..33652fc5da
--- /dev/null
+++ b/resolv/ns_rr_cursor_next.c
@@ -0,0 +1,74 @@
+/* Simple DNS record parser without textual name decoding.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+bool
+__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
+{
+  rr->rdata = NULL;
+
+  /* Extract the record owner name.  */
+  int consumed = __ns_name_unpack (c->begin, c->end, c->current,
+                                   rr->rname, sizeof (rr->rname));
+  if (consumed < 0)
+    {
+      memset (rr, 0, sizeof (*rr));
+      __set_errno (EMSGSIZE);
+      return false;
+    }
+  c->current += consumed;
+
+  /* Extract the metadata.  */
+  struct
+  {
+    uint16_t rtype;
+    uint16_t rclass;
+    uint32_t ttl;
+    uint16_t rdlength;
+  } __attribute__ ((packed)) metadata;
+  _Static_assert (sizeof (metadata) == 10, "sizeof metadata");
+  if (c->end - c->current < sizeof (metadata))
+    {
+      memset (rr, 0, sizeof (*rr));
+      __set_errno (EMSGSIZE);
+      return false;
+    }
+  memcpy (&metadata, c->current, sizeof (metadata));
+  c->current += sizeof (metadata);
+  /* Endianess conversion.  */
+  rr->rtype = ntohs (metadata.rtype);
+  rr->rclass = ntohs (metadata.rclass);
+  rr->ttl = ntohl (metadata.ttl);
+  rr->rdlength = ntohs (metadata.rdlength);
+
+  /* Extract record data.  */
+  if (c->end - c->current < rr->rdlength)
+    {
+      memset (rr, 0, sizeof (*rr));
+      __set_errno (EMSGSIZE);
+      return false;
+    }
+  rr->rdata = c->current;
+  c->current += rr->rdlength;
+
+  return true;
+}
diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c
new file mode 100644
index 0000000000..9a47d8e97a
--- /dev/null
+++ b/resolv/ns_samebinaryname.c
@@ -0,0 +1,55 @@
+/* Compare two binary domain names for quality.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <stdbool.h>
+
+/* Convert ASCII letters to upper case.  */
+static inline int
+ascii_toupper (unsigned char ch)
+{
+  if (ch >= 'a' && ch <= 'z')
+    return ch - 'a' + 'A';
+  else
+    return ch;
+}
+
+bool
+__ns_samebinaryname (const unsigned char *a, const unsigned char *b)
+{
+  while (*a != 0 && *b != 0)
+    {
+      if (*a != *b)
+        /* Different label length.  */
+        return false;
+      int labellen = *a;
+      ++a;
+      ++b;
+      for (int i = 0; i < labellen; ++i)
+        {
+          if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
+            /* Different character in label.  */
+            return false;
+          ++a;
+          ++b;
+        }
+    }
+
+  /* Match if both names are at the root label.  */
+  return *a == 0 && *b == 0;
+}
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 544cffbecd..227734da5c 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -69,6 +69,7 @@
  * --Copyright--
  */
 
+#include <alloc_buffer.h>
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
@@ -86,10 +87,6 @@
 #include <resolv/resolv-internal.h>
 #include <resolv/resolv_context.h>
 
-/* Get implementations of some internal functions.  */
-#include <resolv/mapv4v6addr.h>
-#include <resolv/mapv4v6hostent.h>
-
 #define RESOLVSORT
 
 #if PACKETSZ > 65536
@@ -103,32 +100,36 @@
 #endif
 #define MAXHOSTNAMELEN 256
 
-/* We need this time later.  */
-typedef union querybuf
-{
-  HEADER hdr;
-  u_char buf[MAXPACKET];
-} querybuf;
-
-static enum nss_status getanswer_r (struct resolv_context *ctx,
-				    const querybuf *answer, int anslen,
-				    const char *qname, int qtype,
-				    struct hostent *result, char *buffer,
-				    size_t buflen, int *errnop, int *h_errnop,
-				    int map, int32_t *ttlp, char **canonp);
-
-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
-				       const querybuf *answer2, int anslen2,
-				       const char *qname,
+/* For historic reasons, pointers to IP addresses are char *, so use a
+   single list type for addresses and host names.  */
+#define DYNARRAY_STRUCT ptrlist
+#define DYNARRAY_ELEMENT char *
+#define DYNARRAY_PREFIX ptrlist_
+#include <malloc/dynarray-skeleton.c>
+
+static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen,
+				    uint16_t qtype, struct alloc_buffer *abuf,
+				    struct ptrlist *addresses,
+				    struct ptrlist *aliases,
+				    int *errnop, int *h_errnop, int32_t *ttlp);
+static void addrsort (struct resolv_context *ctx, char **ap, int num);
+static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
+				      struct alloc_buffer *abuf,
+				      char **hnamep, int *errnop,
+				      int *h_errnop, int32_t *ttlp);
+
+static enum nss_status gaih_getanswer (unsigned char *packet1,
+				       size_t packet1len,
+				       unsigned char *packet2,
+				       size_t packet2len,
+				       struct alloc_buffer *abuf,
 				       struct gaih_addrtuple **pat,
-				       char *buffer, size_t buflen,
 				       int *errnop, int *h_errnop,
 				       int32_t *ttlp);
-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1,
-					      int anslen1,
-					      const char *qname,
+static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
+					      size_t packetlen,
+					      struct alloc_buffer *abuf,
 					      struct gaih_addrtuple **pat,
-					      char *buffer, size_t buflen,
 					      int *errnop, int *h_errnop,
 					      int32_t *ttlp);
 
@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx,
 			char *buffer, size_t buflen, int *errnop,
 			int *h_errnop, int32_t *ttlp, char **canonp)
 {
-  union
-  {
-    querybuf *buf;
-    u_char *ptr;
-  } host_buffer;
-  querybuf *orig_host_buffer;
   char tmp[NS_MAXDNAME];
   int size, type, n;
   const char *cp;
-  int map = 0;
   int olderr = errno;
   enum nss_status status;
 
@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx,
       && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
     name = cp;
 
-  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+  unsigned char dns_packet_buffer[1024];
+  unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
 
-  n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
-			    1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+  n = __res_context_search (ctx, name, C_IN, type,
+			    dns_packet_buffer, sizeof (dns_packet_buffer),
+			    &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
   if (n < 0)
     {
       switch (errno)
@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx,
 	*errnop = EAGAIN;
       else
 	__set_errno (olderr);
+    }
+  else
+    {
+      struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
 
-      /* If we are looking for an IPv6 address and mapping is enabled
-	 by having the RES_USE_INET6 bit in _res.options set, we try
-	 another lookup.  */
-      if (af == AF_INET6 && res_use_inet6 ())
-	n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
-				  host_buffer.buf != orig_host_buffer
-				  ? MAXPACKET : 1024, &host_buffer.ptr,
-				  NULL, NULL, NULL, NULL);
+      struct ptrlist addresses;
+      ptrlist_init (&addresses);
+      struct ptrlist aliases;
+      ptrlist_init (&aliases);
 
-      if (n < 0)
+      status = getanswer_r (alt_dns_packet_buffer, n, type,
+			    &abuf, &addresses, &aliases,
+			    errnop, h_errnop, ttlp);
+      if (status == NSS_STATUS_SUCCESS)
 	{
-	  if (host_buffer.buf != orig_host_buffer)
-	    free (host_buffer.buf);
-	  return status;
-	}
+	  if (ptrlist_has_failed (&addresses)
+	      || ptrlist_has_failed (&aliases))
+	    {
+	      /* malloc failure.  Do not retry using the ERANGE protocol.  */
+	      *errnop = ENOMEM;
+	      *h_errnop = NETDB_INTERNAL;
+	      status = NSS_STATUS_UNAVAIL;
+	    }
 
-      map = 1;
+	  /* Reserve the address and alias arrays in the result
+	     buffer.  Both are NULL-terminated, but the first element
+	     of the alias array is stored in h_name, so no extra space
+	     for the NULL terminator is needed there.  */
+	  result->h_addr_list
+	    = alloc_buffer_alloc_array (&abuf, char *,
+					ptrlist_size (&addresses) + 1);
+	  result->h_aliases
+	    = alloc_buffer_alloc_array (&abuf, char *,
+					ptrlist_size (&aliases));
+	  if (alloc_buffer_has_failed (&abuf))
+	    {
+	      /* Retry using the ERANGE protocol.  */
+	      *errnop = ERANGE;
+	      *h_errnop = NETDB_INTERNAL;
+	      status = NSS_STATUS_TRYAGAIN;
+	    }
+	  else
+	    {
+	      /* Copy the address list and NULL-terminate it.  */
+	      memcpy (result->h_addr_list, ptrlist_begin (&addresses),
+		      ptrlist_size (&addresses) * sizeof (char *));
+	      result->h_addr_list[ptrlist_size (&addresses)] = NULL;
+
+	      /* Sort the address list if requested.  */
+	      if (type == T_A && __resolv_context_sort_count (ctx) > 0)
+		addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses));
 
-      result->h_addrtype = AF_INET;
-      result->h_length = INADDRSZ;
+	      /* Copy the aliases,  excluding the last one. */
+	      memcpy (result->h_aliases, ptrlist_begin (&aliases),
+		      (ptrlist_size (&aliases) - 1) * sizeof (char *));
+	      result->h_aliases[ptrlist_size (&aliases) - 1] = NULL;
+
+	      /* The last alias goes into h_name.  */
+	      assert (ptrlist_size (&aliases) >= 1);
+	      result->h_name = ptrlist_end (&aliases)[-1];
+
+	      /* This is also the canonical name.  */
+	      if (canonp != NULL)
+		*canonp = result->h_name;
+	    }
+	}
+
+      ptrlist_free (&aliases);
+      ptrlist_free (&addresses);
     }
 
-  status = getanswer_r
-    (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
-     errnop, h_errnop, map, ttlp, canonp);
-  if (host_buffer.buf != orig_host_buffer)
-    free (host_buffer.buf);
+  if (alt_dns_packet_buffer != dns_packet_buffer)
+    free (alt_dns_packet_buffer);
   return status;
 }
 
@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
       *h_errnop = NETDB_INTERNAL;
       return NSS_STATUS_UNAVAIL;
     }
-  status = NSS_STATUS_NOTFOUND;
-  if (res_use_inet6 ())
-    status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
-				     buflen, errnop, h_errnop, NULL, NULL);
-  if (status == NSS_STATUS_NOTFOUND)
-    status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
-				     buflen, errnop, h_errnop, NULL, NULL);
+  status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
+				   buflen, errnop, h_errnop, NULL, NULL);
   __resolv_context_put (ctx);
   return status;
 }
@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
 	name = cp;
     }
 
-  union
-  {
-    querybuf *buf;
-    u_char *ptr;
-  } host_buffer;
-  querybuf *orig_host_buffer;
-  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
+  unsigned char dns_packet_buffer[2048];
+  unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
   u_char *ans2p = NULL;
   int nans2p = 0;
   int resplen2 = 0;
   int ans2p_malloced = 0;
+  struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
 
 
   int olderr = errno;
@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
   if ((ctx->resp->options & RES_NOAAAA) == 0)
     {
       n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
-				host_buffer.buf->buf, 2048, &host_buffer.ptr,
-				&ans2p, &nans2p, &resplen2, &ans2p_malloced);
+				dns_packet_buffer, sizeof (dns_packet_buffer),
+				&alt_dns_packet_buffer, &ans2p, &nans2p,
+				&resplen2, &ans2p_malloced);
       if (n >= 0)
-	status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
-				 resplen2, name, pat, buffer, buflen,
-				 errnop, herrnop, ttlp);
+	status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
+				 &abuf, pat, errnop, herrnop, ttlp);
     }
   else
     {
       n = __res_context_search (ctx, name, C_IN, T_A,
-				host_buffer.buf->buf, 2048, NULL,
-				NULL, NULL, NULL, NULL);
+				dns_packet_buffer, sizeof (dns_packet_buffer),
+				&alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
       if (n >= 0)
-	status = gaih_getanswer_noaaaa (host_buffer.buf, n,
-					name, pat, buffer, buflen,
-					errnop, herrnop, ttlp);
+	status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
+					&abuf, pat, errnop, herrnop, ttlp);
     }
   if (n < 0)
     {
@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
 	__set_errno (olderr);
     }
 
+  /* Implement the buffer resizing protocol.  */
+  if (alloc_buffer_has_failed (&abuf))
+    {
+      *errnop = ERANGE;
+      *herrnop = NETDB_INTERNAL;
+      status = NSS_STATUS_TRYAGAIN;
+    }
+
   /* Check whether ans2p was separately allocated.  */
   if (ans2p_malloced)
     free (ans2p);
 
-  if (host_buffer.buf != orig_host_buffer)
-    free (host_buffer.buf);
+  if (alt_dns_packet_buffer != dns_packet_buffer)
+    free (alt_dns_packet_buffer);
 
   __resolv_context_put (ctx);
   return status;
@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
   static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
   static const u_char v6local[] = { 0,0, 0,1 };
   const u_char *uaddr = (const u_char *)addr;
-  struct host_data
-  {
-    char *aliases[MAX_NR_ALIASES];
-    unsigned char host_addr[16];	/* IPv4 or IPv6 */
-    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
-    char linebuffer[0];
-  } *host_data = (struct host_data *) buffer;
-  union
-  {
-    querybuf *buf;
-    u_char *ptr;
-  } host_buffer;
-  querybuf *orig_host_buffer;
   char qbuf[MAXDNAME+1], *qp = NULL;
   size_t size;
   int n, status;
   int olderr = errno;
 
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
- buffer += pad;
- buflen = buflen > pad ? buflen - pad : 0;
-
- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
-   {
-     *errnop = ERANGE;
-     *h_errnop = NETDB_INTERNAL;
-     return NSS_STATUS_TRYAGAIN;
-   }
-
- host_data = (struct host_data *) buffer;
+  /* Prepare the allocation buffer.  Store the pointer array first, to
+     benefit from buffer alignment.  */
+  struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
+  char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2);
+  if (address_array == NULL)
+    {
+      *errnop = ERANGE;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
   struct resolv_context *ctx = __resolv_context_get ();
   if (ctx == NULL)
@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
       return NSS_STATUS_UNAVAIL;
     }
 
-  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
-
   switch (af)
     {
     case AF_INET:
@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
       break;
     }
 
-  n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
-			   1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+  unsigned char dns_packet_buffer[1024];
+  unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
+  n = __res_context_query (ctx, qbuf, C_IN, T_PTR,
+			   dns_packet_buffer, sizeof (dns_packet_buffer),
+			   &alt_dns_packet_buffer,
+			   NULL, NULL, NULL, NULL);
   if (n < 0)
     {
       *h_errnop = h_errno;
       __set_errno (olderr);
-      if (host_buffer.buf != orig_host_buffer)
-	free (host_buffer.buf);
+      if (alt_dns_packet_buffer != dns_packet_buffer)
+	free (alt_dns_packet_buffer);
       __resolv_context_put (ctx);
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     }
 
-  status = getanswer_r
-    (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
-     errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
-  if (host_buffer.buf != orig_host_buffer)
-    free (host_buffer.buf);
+  status = getanswer_ptr (alt_dns_packet_buffer, n,
+			  &abuf, &result->h_name, errnop, h_errnop, ttlp);
+
+  if (alt_dns_packet_buffer != dns_packet_buffer)
+    free (alt_dns_packet_buffer);
+  __resolv_context_put (ctx);
+
   if (status != NSS_STATUS_SUCCESS)
-    {
-      __resolv_context_put (ctx);
-      return status;
-    }
+    return status;
 
+  /* result->h_name has already been set by getanswer_ptr.  */
   result->h_addrtype = af;
   result->h_length = len;
-  memcpy (host_data->host_addr, addr, len);
-  host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
-  host_data->h_addr_ptrs[1] = NULL;
+  /* Increase the alignment to 4, in case there are applications out
+     there that expect at least this level of address alignment.  */
+  address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t);
+  alloc_buffer_copy_bytes (&abuf, uaddr, len);
+  address_array[1] = NULL;
+
+  /* This check also covers allocation failure in getanswer_ptr.  */
+  if (alloc_buffer_has_failed (&abuf))
+    {
+      *errnop = ERANGE;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+  result->h_addr_list = address_array;
+  result->h_aliases = &address_array[1]; /* Points to NULL.  */
+
   *h_errnop = NETDB_SUCCESS;
-  __resolv_context_put (ctx);
   return NSS_STATUS_SUCCESS;
 }
 libc_hidden_def (_nss_dns_gethostbyaddr2_r)
@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num)
 	break;
 }
 
-static enum nss_status
-getanswer_r (struct resolv_context *ctx,
-	     const querybuf *answer, int anslen, const char *qname, int qtype,
-	     struct hostent *result, char *buffer, size_t buflen,
-	     int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
+/* Convert the uncompressed, binary domain name CDNAME into its
+   textual representation and add it to the end of ALIASES, allocating
+   space for a copy of the name from ABUF.  Skip adding the name if it
+   is not a valid host name, and return false in that case, otherwise
+   true.  */
+static bool
+getanswer_r_store_alias (const unsigned char *cdname,
+			 struct alloc_buffer *abuf,
+			 struct ptrlist *aliases)
 {
-  struct host_data
-  {
-    char *aliases[MAX_NR_ALIASES];
-    unsigned char host_addr[16];	/* IPv4 or IPv6 */
-    char *h_addr_ptrs[0];
-  } *host_data;
-  int linebuflen;
-  const HEADER *hp;
-  const u_char *end_of_message, *cp;
-  int n, ancount, qdcount;
-  int haveanswer, had_error;
-  char *bp, **ap, **hap;
-  char tbuf[MAXDNAME];
-  const char *tname;
-  int (*name_ok) (const char *);
-  u_char packtmp[NS_MAXCDNAME];
-  int have_to_map = 0;
-  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
-  buffer += pad;
-  buflen = buflen > pad ? buflen - pad : 0;
-  if (__glibc_unlikely (buflen < sizeof (struct host_data)))
-    {
-      /* The buffer is too small.  */
-    too_small:
-      *errnop = ERANGE;
-      *h_errnop = NETDB_INTERNAL;
-      return NSS_STATUS_TRYAGAIN;
-    }
-  host_data = (struct host_data *) buffer;
-  linebuflen = buflen - sizeof (struct host_data);
-  if (buflen - sizeof (struct host_data) != linebuflen)
-    linebuflen = INT_MAX;
-
-  tname = qname;
-  result->h_name = NULL;
-  end_of_message = answer->buf + anslen;
-  switch (qtype)
-    {
-    case T_A:
-    case T_AAAA:
-      name_ok = __libc_res_hnok;
-      break;
-    case T_PTR:
-      name_ok = __libc_res_dnok;
-      break;
-    default:
-      *errnop = ENOENT;
-      return NSS_STATUS_UNAVAIL;  /* XXX should be abort(); */
-    }
+  /* Filter out domain names that are not host names.  */
+  if (!__res_binary_hnok (cdname))
+    return false;
+
+  /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks
+     for length.  */
+  char dname[MAXHOSTNAMELEN + 1];
+  if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0)
+    return false;
+  /* Do not report an error on allocation failure, instead store NULL
+     or do nothing.  getanswer_r's caller will see NSS_STATUS_SUCCESS
+     and detect the memory allocation failure or buffer space
+     exhaustion, and report it accordingly.  */
+  ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname));
+  return true;
+}
 
-  /*
-   * find first satisfactory answer
-   */
-  hp = &answer->hdr;
-  ancount = ntohs (hp->ancount);
-  qdcount = ntohs (hp->qdcount);
-  cp = answer->buf + HFIXEDSZ;
-  if (__glibc_unlikely (qdcount != 1))
+static enum nss_status __attribute__ ((noinline))
+getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype,
+	     struct alloc_buffer *abuf,
+	     struct ptrlist *addresses, struct ptrlist *aliases,
+	     int *errnop, int *h_errnop, int32_t *ttlp)
+{
+  struct ns_rr_cursor c;
+  if (!__ns_rr_cursor_init (&c, packet, packetlen))
     {
+      /* This should not happen because __res_context_query already
+	 perfroms response validation.  */
       *h_errnop = NO_RECOVERY;
       return NSS_STATUS_UNAVAIL;
     }
-  if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
-    goto too_small;
-  bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
-  linebuflen -= (ancount + 1) * sizeof (char *);
-
-  n = __ns_name_unpack (answer->buf, end_of_message, cp,
-			packtmp, sizeof packtmp);
-  if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
-    {
-      if (__glibc_unlikely (errno == EMSGSIZE))
-	goto too_small;
 
-      n = -1;
-    }
-
-  if (__glibc_unlikely (n < 0))
+  /* Treat the QNAME just like an alias.  Error out if it is not a
+     valid host name.  */
+  if (ns_rr_cursor_rcode (&c) == NXDOMAIN
+      || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases))
     {
-      *errnop = errno;
-      *h_errnop = NO_RECOVERY;
-      return NSS_STATUS_UNAVAIL;
-    }
-  if (__glibc_unlikely (name_ok (bp) == 0))
-    {
-      errno = EBADMSG;
-      *errnop = EBADMSG;
-      *h_errnop = NO_RECOVERY;
-      return NSS_STATUS_UNAVAIL;
+      if (ttlp != NULL)
+	/* No negative caching.  */
+	*ttlp = 0;
+      *h_errnop = HOST_NOT_FOUND;
+      *errnop = ENOENT;
+      return NSS_STATUS_NOTFOUND;
     }
-  cp += n + QFIXEDSZ;
 
-  if (qtype == T_A || qtype == T_AAAA)
+  int ancount = ns_rr_cursor_ancount (&c);
+  const unsigned char *expected_name = ns_rr_cursor_qname (&c);
+  /* expected_name may be updated to point into this buffer.  */
+  unsigned char name_buffer[NS_MAXCDNAME];
+
+  for (; ancount > 0; --ancount)
     {
-      /* res_send() has already verified that the query name is the
-       * same as the one we sent; this just gets the expanded name
-       * (i.e., with the succeeding search-domain tacked on).
-       */
-      n = strlen (bp) + 1;             /* for the \0 */
-      if (n >= MAXHOSTNAMELEN)
+      struct ns_rr_wire rr;
+      if (!__ns_rr_cursor_next (&c, &rr))
 	{
 	  *h_errnop = NO_RECOVERY;
-	  *errnop = ENOENT;
-	  return NSS_STATUS_TRYAGAIN;
+	  return NSS_STATUS_UNAVAIL;
 	}
-      result->h_name = bp;
-      bp += n;
-      linebuflen -= n;
-      if (linebuflen < 0)
-	goto too_small;
-      /* The qname can be abbreviated, but h_name is now absolute. */
-      qname = result->h_name;
-    }
 
-  ap = host_data->aliases;
-  *ap = NULL;
-  result->h_aliases = host_data->aliases;
-  hap = host_data->h_addr_ptrs;
-  *hap = NULL;
-  result->h_addr_list = host_data->h_addr_ptrs;
-  haveanswer = 0;
-  had_error = 0;
+      /* Skip over records with the wrong class.  */
+      if (rr.rclass != C_IN)
+	continue;
 
-  while (ancount-- > 0 && cp < end_of_message && had_error == 0)
-    {
-      int type, class;
+      /* Update TTL for recognized record types.  */
+      if ((rr.rtype == T_CNAME || rr.rtype == qtype)
+	  && ttlp != NULL && *ttlp > rr.ttl)
+	*ttlp = rr.ttl;
 
-      n = __ns_name_unpack (answer->buf, end_of_message, cp,
-			    packtmp, sizeof packtmp);
-      if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+      if (rr.rtype == T_CNAME)
 	{
-	  if (__glibc_unlikely (errno == EMSGSIZE))
-	    goto too_small;
-
-	  n = -1;
+	  /* NB: No check for owner name match, based on historic
+	     precedent.  Record the CNAME target as the new expected
+	     name.  */
+	  int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
+				    name_buffer, sizeof (name_buffer));
+	  if (n < 0)
+	    {
+	      *h_errnop = NO_RECOVERY;
+	      return NSS_STATUS_UNAVAIL;
+	    }
+	  /* And store the new name as an alias.  */
+	  getanswer_r_store_alias (name_buffer, abuf, aliases);
+	  expected_name = name_buffer;
 	}
-
-      if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0))
+      else if (rr.rtype == qtype
+	       && __ns_samebinaryname (rr.rname, expected_name)
+	       && rr.rdlength == rrtype_to_rdata_length (qtype))
 	{
-	  ++had_error;
-	  continue;
+	  /* Make a copy of the address and store it.  Increase the
+	     alignment to 4, in case there are applications out there
+	     that expect at least this level of address alignment.  */
+	  ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t));
+	  alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength);
 	}
-      cp += n;				/* name */
+    }
 
-      if (__glibc_unlikely (cp + 10 > end_of_message))
-	{
-	  ++had_error;
-	  continue;
-	}
+  if (ptrlist_size (addresses) == 0)
+    {
+      /* No address record found.  */
+      if (ttlp != NULL)
+	/* No caching of negative responses.  */
+	*ttlp = 0;
 
-      NS_GET16 (type, cp);
-      NS_GET16 (class, cp);
-      int32_t ttl;
-      NS_GET32 (ttl, cp);
-      NS_GET16 (n, cp);		/* RDATA length.  */
+      *h_errnop = NO_RECOVERY;
+      *errnop = ENOENT;
+      return NSS_STATUS_TRYAGAIN;
+    }
+  else
+    {
+      *h_errnop = NETDB_SUCCESS;
+      return NSS_STATUS_SUCCESS;
+    }
+}
 
-      if (end_of_message - cp < n)
-	{
-	  /* RDATA extends beyond the end of the packet.  */
-	  ++had_error;
-	  continue;
-	}
+static enum nss_status
+getanswer_ptr (unsigned char *packet, size_t packetlen,
+	       struct alloc_buffer *abuf, char **hnamep,
+	       int *errnop, int *h_errnop, int32_t *ttlp)
+{
+  struct ns_rr_cursor c;
+  if (!__ns_rr_cursor_init (&c, packet, packetlen))
+    {
+      /* This should not happen because __res_context_query already
+	 perfroms response validation.  */
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+  int ancount = ns_rr_cursor_ancount (&c);
+  const unsigned char *expected_name = ns_rr_cursor_qname (&c);
+  /* expected_name may be updated to point into this buffer.  */
+  unsigned char name_buffer[NS_MAXCDNAME];
 
-      if (__glibc_unlikely (class != C_IN))
+  while (ancount > 0)
+    {
+      struct ns_rr_wire rr;
+      if (!__ns_rr_cursor_next (&c, &rr))
 	{
-	  /* XXX - debug? syslog? */
-	  cp += n;
-	  continue;			/* XXX - had_error++ ? */
+	  *h_errnop = NO_RECOVERY;
+	  return NSS_STATUS_UNAVAIL;
 	}
 
-      if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
-	{
-	  /* A CNAME could also have a TTL entry.  */
-	  if (ttlp != NULL && ttl < *ttlp)
-	      *ttlp = ttl;
-
-	  if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
-	    continue;
-	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
-				tbuf, sizeof tbuf);
-	  if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
-	    {
-	      ++had_error;
-	      continue;
-	    }
-	  cp += n;
-	  /* Store alias.  */
-	  *ap++ = bp;
-	  n = strlen (bp) + 1;		/* For the \0.  */
-	  if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
-	    {
-	      ++had_error;
-	      continue;
-	    }
-	  bp += n;
-	  linebuflen -= n;
-	  /* Get canonical name.  */
-	  n = strlen (tbuf) + 1;	/* For the \0.  */
-	  if (__glibc_unlikely (n > linebuflen))
-	    goto too_small;
-	  if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
-	    {
-	      ++had_error;
-	      continue;
-	    }
-	  result->h_name = bp;
-	  bp = __mempcpy (bp, tbuf, n);	/* Cannot overflow.  */
-	  linebuflen -= n;
-	  continue;
-	}
+      /* Skip over records with the wrong class.  */
+      if (rr.rclass != C_IN)
+	continue;
 
-      if (qtype == T_PTR && type == T_CNAME)
-	{
-	  /* A CNAME could also have a TTL entry.  */
-	  if (ttlp != NULL && ttl < *ttlp)
-	      *ttlp = ttl;
+      /* Update TTL for known record types.  */
+      if ((rr.rtype == T_CNAME || rr.rtype == T_PTR)
+	  && ttlp != NULL && *ttlp > rr.ttl)
+	*ttlp = rr.ttl;
 
-	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
-				tbuf, sizeof tbuf);
-	  if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
-	    {
-	      ++had_error;
-	      continue;
-	    }
-	  cp += n;
-	  /* Get canonical name.  */
-	  n = strlen (tbuf) + 1;   /* For the \0.  */
-	  if (__glibc_unlikely (n > linebuflen))
-	    goto too_small;
-	  if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+      if (rr.rtype == T_CNAME)
+	{
+	  /* NB: No check for owner name match, based on historic
+	     precedent.  Record the CNAME target as the new expected
+	     name.  */
+	  int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
+				    name_buffer, sizeof (name_buffer));
+	  if (n < 0)
 	    {
-	      ++had_error;
-	      continue;
+	      *h_errnop = NO_RECOVERY;
+	      return NSS_STATUS_UNAVAIL;
 	    }
-	  tname = bp;
-	  bp = __mempcpy (bp, tbuf, n);	/* Cannot overflow.  */
-	  linebuflen -= n;
-	  continue;
+	  expected_name = name_buffer;
 	}
-
-      if (type == T_A && qtype == T_AAAA && map)
-	have_to_map = 1;
-      else if (__glibc_unlikely (type != qtype))
+      else if (rr.rtype == T_PTR
+	       && __ns_samebinaryname (rr.rname, expected_name))
 	{
-	  cp += n;
-	  continue;			/* XXX - had_error++ ? */
-	}
-
-      switch (type)
-	{
-	case T_PTR:
-	  if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
+	  /* Decompress the target of the PTR record.  This is the
+	     host name we are looking for.  We can only use it if it
+	     is syntactically valid.  Historically, only one host name
+	     is returned here.  If the recursive resolver performs DNS
+	     record rotation, the returned host name is essentially
+	     random, which is why multiple PTR records are rarely
+	     used.  Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for
+	     additional length checking.  */
+	  char hname[MAXHOSTNAMELEN + 1];
+	  if (__ns_name_unpack (c.begin, c.end, rr.rdata,
+				name_buffer, sizeof (name_buffer)) < 0
+	      || !__res_binary_hnok (expected_name)
+	      || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
 	    {
-	      cp += n;
-	      continue;			/* XXX - had_error++ ? */
+	      *h_errnop = NO_RECOVERY;
+	      return NSS_STATUS_UNAVAIL;
 	    }
-
-	  n = __ns_name_unpack (answer->buf, end_of_message, cp,
-				packtmp, sizeof packtmp);
-	  if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
-	    {
-	      if (__glibc_unlikely (errno == EMSGSIZE))
-		goto too_small;
-
-	      n = -1;
-	    }
-
-	  if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
-	    {
-	      ++had_error;
-	      break;
-	    }
-	  if (ttlp != NULL && ttl < *ttlp)
-	      *ttlp = ttl;
-	  /* bind would put multiple PTR records as aliases, but we don't do
-	     that.  */
-	  result->h_name = bp;
-	  *h_errnop = NETDB_SUCCESS;
+	  /* Successful allocation is checked by the caller.  */
+	  *hnamep = alloc_buffer_copy_string (abuf, hname);
 	  return NSS_STATUS_SUCCESS;
-	case T_A:
-	case T_AAAA:
-	  if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
-	    {
-	      cp += n;
-	      continue;			/* XXX - had_error++ ? */
-	    }
-
-	  /* Stop parsing at a record whose length is incorrect.  */
-	  if (n != rrtype_to_rdata_length (type))
-	    {
-	      ++had_error;
-	      break;
-	    }
-
-	  /* Skip records of the wrong type.  */
-	  if (n != result->h_length)
-	    {
-	      cp += n;
-	      continue;
-	    }
-	  if (!haveanswer)
-	    {
-	      int nn;
-
-	      /* We compose a single hostent out of the entire chain of
-	         entries, so the TTL of the hostent is essentially the lowest
-		 TTL in the chain.  */
-	      if (ttlp != NULL && ttl < *ttlp)
-		*ttlp = ttl;
-	      if (canonp != NULL)
-		*canonp = bp;
-	      result->h_name = bp;
-	      nn = strlen (bp) + 1;	/* for the \0 */
-	      bp += nn;
-	      linebuflen -= nn;
-	    }
-
-	  /* Provide sufficient alignment for both address
-	     families.  */
-	  enum { align = 4 };
-	  _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
-			  "struct in_addr alignment");
-	  _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
-			  "struct in6_addr alignment");
-	  {
-	    char *new_bp = PTR_ALIGN_UP (bp, align);
-	    linebuflen -= new_bp - bp;
-	    bp = new_bp;
-	  }
-
-	  if (__glibc_unlikely (n > linebuflen))
-	    goto too_small;
-	  bp = __mempcpy (*hap++ = bp, cp, n);
-	  cp += n;
-	  linebuflen -= n;
-	  break;
-	default:
-	  abort ();
 	}
-      if (had_error == 0)
-	++haveanswer;
     }
 
-  if (haveanswer > 0)
-    {
-      *ap = NULL;
-      *hap = NULL;
-      /*
-       * Note: we sort even if host can take only one address
-       * in its return structures - should give it the "best"
-       * address in that case, not some random one
-       */
-      if (haveanswer > 1 && qtype == T_A
-	  && __resolv_context_sort_count (ctx) > 0)
-	addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
-
-      if (result->h_name == NULL)
-	{
-	  n = strlen (qname) + 1;	/* For the \0.  */
-	  if (n > linebuflen)
-	    goto too_small;
-	  if (n >= MAXHOSTNAMELEN)
-	    goto no_recovery;
-	  result->h_name = bp;
-	  bp = __mempcpy (bp, qname, n);	/* Cannot overflow.  */
-	  linebuflen -= n;
-	}
+  /* No PTR record found.  */
+  if (ttlp != NULL)
+    /* No caching of negative responses.  */
+    *ttlp = 0;
 
-      if (have_to_map)
-	if (map_v4v6_hostent (result, &bp, &linebuflen))
-	  goto too_small;
-      *h_errnop = NETDB_SUCCESS;
-      return NSS_STATUS_SUCCESS;
-    }
- no_recovery:
   *h_errnop = NO_RECOVERY;
   *errnop = ENOENT;
-  /* Special case here: if the resolver sent a result but it only
-     contains a CNAME while we are looking for a T_A or T_AAAA record,
-     we fail with NOTFOUND instead of TRYAGAIN.  */
-  return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
-	   ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
+  return NSS_STATUS_TRYAGAIN;
 }
 
-
+/* Parses DNS data found in PACKETLEN bytes at PACKET in struct
+   gaih_addrtuple address tuples.  The new address tuples are linked
+   from **TAILP, with backing store allocated from ABUF, and *TAILP is
+   updated to point where the next tuple pointer should be stored.  If
+   TTLP is not null, *TTLP is updated to reflect the minimum TTL.  If
+   STORE_CANON is true, the canonical name is stored as part of the
+   first address tuple being written.  */
 static enum nss_status
-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
-		      struct gaih_addrtuple ***patp,
-		      char **bufferp, size_t *buflenp,
-		      int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
+gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
+		      struct alloc_buffer *abuf,
+		      struct gaih_addrtuple ***tailp,
+		      int *errnop, int *h_errnop, int32_t *ttlp,
+		      bool store_canon)
 {
-  char *buffer = *bufferp;
-  size_t buflen = *buflenp;
-
-  struct gaih_addrtuple **pat = *patp;
-  const HEADER *hp = &answer->hdr;
-  int ancount = ntohs (hp->ancount);
-  int qdcount = ntohs (hp->qdcount);
-  const u_char *cp = answer->buf + HFIXEDSZ;
-  const u_char *end_of_message = answer->buf + anslen;
-  if (__glibc_unlikely (qdcount != 1))
-    {
-      *h_errnop = NO_RECOVERY;
-      return NSS_STATUS_UNAVAIL;
-    }
-
-  u_char packtmp[NS_MAXCDNAME];
-  int n = __ns_name_unpack (answer->buf, end_of_message, cp,
-			    packtmp, sizeof packtmp);
-  /* We unpack the name to check it for validity.  But we do not need
-     it later.  */
-  if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
-    {
-      if (__glibc_unlikely (errno == EMSGSIZE))
-	{
-	too_small:
-	  *errnop = ERANGE;
-	  *h_errnop = NETDB_INTERNAL;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      n = -1;
-    }
-
-  if (__glibc_unlikely (n < 0))
+  struct ns_rr_cursor c;
+  if (!__ns_rr_cursor_init (&c, packet, packetlen))
     {
-      *errnop = errno;
+      /* This should not happen because __res_context_query already
+	 perfroms response validation.  */
       *h_errnop = NO_RECOVERY;
       return NSS_STATUS_UNAVAIL;
     }
-  if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
-    {
-      errno = EBADMSG;
-      *errnop = EBADMSG;
-      *h_errnop = NO_RECOVERY;
-      return NSS_STATUS_UNAVAIL;
-    }
-  cp += n + QFIXEDSZ;
-
-  int haveanswer = 0;
-  int had_error = 0;
-  char *canon = NULL;
-  char *h_name = NULL;
-  int h_namelen = 0;
-
-  if (ancount == 0)
+  bool haveanswer = false; /* Set to true if at least one address.  */
+  uint16_t qtype = ns_rr_cursor_qtype (&c);
+  int ancount = ns_rr_cursor_ancount (&c);
+  const unsigned char *expected_name = ns_rr_cursor_qname (&c);
+  /* expected_name may be updated to point into this buffer.  */
+  unsigned char name_buffer[NS_MAXCDNAME];
+
+  /* This is a pointer to a possibly-compressed name in the packet.
+     Eventually it is equivalent to the canonical name.  If needed, it
+     is uncompressed and translated to text form when the first
+     address tuple is encountered.  */
+  const unsigned char *compressed_alias_name = expected_name;
+
+  if (ancount == 0 || !__res_binary_hnok (compressed_alias_name))
     {
       *h_errnop = HOST_NOT_FOUND;
       return NSS_STATUS_NOTFOUND;
     }
 
-  while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+  for (; ancount > -0; --ancount)
     {
-      n = __ns_name_unpack (answer->buf, end_of_message, cp,
-			    packtmp, sizeof packtmp);
-      if (n != -1 &&
-	  (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
+      struct ns_rr_wire rr;
+      if (!__ns_rr_cursor_next (&c, &rr))
 	{
-	  if (__glibc_unlikely (errno == EMSGSIZE))
-	    goto too_small;
-
-	  n = -1;
-	}
-      if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0))
-	{
-	  ++had_error;
-	  continue;
-	}
-      if (*firstp && canon == NULL)
-	{
-	  h_name = buffer;
-	  buffer += h_namelen;
-	  buflen -= h_namelen;
-	}
-
-      cp += n;				/* name */
-
-      if (__glibc_unlikely (cp + 10 > end_of_message))
-	{
-	  ++had_error;
-	  continue;
+	  *h_errnop = NO_RECOVERY;
+	  return NSS_STATUS_UNAVAIL;
 	}
 
-      uint16_t type;
-      NS_GET16 (type, cp);
-      uint16_t class;
-      NS_GET16 (class, cp);
-      int32_t ttl;
-      NS_GET32 (ttl, cp);
-      NS_GET16 (n, cp);		/* RDATA length.  */
+      /* Update TTL for known record types.  */
+      if ((rr.rtype == T_CNAME || rr.rtype == qtype)
+	  && ttlp != NULL && *ttlp > rr.ttl)
+	*ttlp = rr.ttl;
 
-      if (end_of_message - cp < n)
+      if (rr.rtype == T_CNAME)
 	{
-	  /* RDATA extends beyond the end of the packet.  */
-	  ++had_error;
-	  continue;
-	}
-
-      if (class != C_IN)
-	{
-	  cp += n;
-	  continue;
-	}
-
-      if (type == T_CNAME)
-	{
-	  char tbuf[MAXDNAME];
-
-	  /* A CNAME could also have a TTL entry.  */
-	  if (ttlp != NULL && ttl < *ttlp)
-	      *ttlp = ttl;
-
-	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
-				tbuf, sizeof tbuf);
-	  if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0))
+	  /* NB: No check for owner name match, based on historic
+	     precedent.  Record the CNAME target as the new expected
+	     name.  */
+	  int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
+				    name_buffer, sizeof (name_buffer));
+	  if (n < 0)
 	    {
-	      ++had_error;
-	      continue;
-	    }
-	  cp += n;
-
-	  if (*firstp)
-	    {
-	      /* Reclaim buffer space.  */
-	      if (h_name + h_namelen == buffer)
-		{
-		  buffer = h_name;
-		  buflen += h_namelen;
-		}
-
-	      n = strlen (tbuf) + 1;
-	      if (__glibc_unlikely (n > buflen))
-		goto too_small;
-	      if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
-		{
-		  ++had_error;
-		  continue;
-		}
-
-	      canon = buffer;
-	      buffer = __mempcpy (buffer, tbuf, n);
-	      buflen -= n;
-	      h_namelen = 0;
+	      *h_errnop = NO_RECOVERY;
+	      return NSS_STATUS_UNAVAIL;
 	    }
-	  continue;
+	  expected_name = name_buffer;
+	  if (store_canon && __res_binary_hnok (name_buffer))
+	    /* This name can be used as a canonical name.  Do not
+	       translate to text form here to conserve buffer space.
+	       Point to the compressed name because name_buffer can be
+	       overwritten with an unusable name later.  */
+	    compressed_alias_name = rr.rdata;
 	}
-
-      /* Stop parsing if we encounter a record with incorrect RDATA
-	 length.  */
-      if (type == T_A || type == T_AAAA)
+      else if (rr.rtype == qtype
+	       && __ns_samebinaryname (rr.rname, expected_name)
+	       && rr.rdlength == rrtype_to_rdata_length (qtype))
 	{
-	  if (n != rrtype_to_rdata_length (type))
+	  struct gaih_addrtuple *ntup
+	    = alloc_buffer_alloc (abuf, struct gaih_addrtuple);
+	  /* Delay error reporting to the callers (they implement the
+	     ERANGE buffer resizing handshake).  */
+	  if (ntup != NULL)
 	    {
-	      ++had_error;
-	      continue;
+	      ntup->next = NULL;
+	      if (store_canon && compressed_alias_name != NULL)
+		{
+		  /* This assumes that all the CNAME records come
+		     first.  Use MAXHOSTNAMELEN instead of
+		     NS_MAXCDNAME for additional length checking.
+		     However, these checks are not expected to fail
+		     because all size NS_MAXCDNAME names should into
+		     the hname buffer because no escaping is
+		     needed.  */
+		  char unsigned nbuf[NS_MAXCDNAME];
+		  char hname[MAXHOSTNAMELEN + 1];
+		  if (__ns_name_unpack (c.begin, c.end,
+					compressed_alias_name,
+					nbuf, sizeof (nbuf)) >= 0
+		      && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0)
+		    /* Space checking is performed by the callers.  */
+		    ntup->name = alloc_buffer_copy_string (abuf, hname);
+		  store_canon = false;
+		}
+	      else
+		ntup->name = NULL;
+	      if (rr.rdlength == 4)
+		ntup->family = AF_INET;
+	      else
+		ntup->family = AF_INET6;
+	      memcpy (ntup->addr, rr.rdata, rr.rdlength);
+	      ntup->scopeid = 0;
+
+	      /* Link in the new tuple, and update the tail pointer to
+		 point to its next field.  */
+	      **tailp = ntup;
+	      *tailp = &ntup->next;
+
+	      haveanswer = true;
 	    }
 	}
-      else
-	{
-	  /* Skip unknown records.  */
-	  cp += n;
-	  continue;
-	}
-
-      assert (type == T_A || type == T_AAAA);
-      if (*pat == NULL)
-	{
-	  uintptr_t pad = (-(uintptr_t) buffer
-			   % __alignof__ (struct gaih_addrtuple));
-	  buffer += pad;
-	  buflen = buflen > pad ? buflen - pad : 0;
-
-	  if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
-	    goto too_small;
-
-	  *pat = (struct gaih_addrtuple *) buffer;
-	  buffer += sizeof (struct gaih_addrtuple);
-	  buflen -= sizeof (struct gaih_addrtuple);
-	}
-
-      (*pat)->name = NULL;
-      (*pat)->next = NULL;
-
-      if (*firstp)
-	{
-	  /* We compose a single hostent out of the entire chain of
-	     entries, so the TTL of the hostent is essentially the lowest
-	     TTL in the chain.  */
-	  if (ttlp != NULL && ttl < *ttlp)
-	    *ttlp = ttl;
-
-	  (*pat)->name = canon ?: h_name;
-
-	  *firstp = 0;
-	}
-
-      (*pat)->family = type == T_A ? AF_INET : AF_INET6;
-      memcpy ((*pat)->addr, cp, n);
-      cp += n;
-      (*pat)->scopeid = 0;
-
-      pat = &((*pat)->next);
-
-      haveanswer = 1;
     }
 
   if (haveanswer)
     {
-      *patp = pat;
-      *bufferp = buffer;
-      *buflenp = buflen;
-
       *h_errnop = NETDB_SUCCESS;
       return NSS_STATUS_SUCCESS;
     }
-
-  /* Special case here: if the resolver sent a result but it only
-     contains a CNAME while we are looking for a T_A or T_AAAA record,
-     we fail with NOTFOUND instead of TRYAGAIN.  */
-  if (canon != NULL)
+  else
     {
+      /* Special case here: if the resolver sent a result but it only
+	 contains a CNAME while we are looking for a T_A or T_AAAA
+	 record, we fail with NOTFOUND.  */
       *h_errnop = HOST_NOT_FOUND;
       return NSS_STATUS_NOTFOUND;
     }
-
-  *h_errnop = NETDB_INTERNAL;
-  return NSS_STATUS_TRYAGAIN;
 }
 
 
 static enum nss_status
-gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
-		int anslen2, const char *qname,
-		struct gaih_addrtuple **pat, char *buffer, size_t buflen,
+gaih_getanswer (unsigned char *packet1, size_t packet1len,
+		unsigned char *packet2, size_t packet2len,
+		struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
 		int *errnop, int *h_errnop, int32_t *ttlp)
 {
-  int first = 1;
-
   enum nss_status status = NSS_STATUS_NOTFOUND;
 
   /* Combining the NSS status of two distinct queries requires some
@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
      between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
      A recoverable TRYAGAIN is almost always due to buffer size issues
      and returns ERANGE in errno and the caller is expected to retry
-     with a larger buffer.
+     with a larger buffer.  (The caller, _nss_dns_gethostbyname4_r,
+     ignores the return status if it detects that the result buffer
+     has been exhausted and generates a TRYAGAIN failure with an
+     ERANGE code.)
 
      Lastly, you may be tempted to make significant changes to the
      conditions in this code to bring about symmetry between responses.
@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
 	 is a recoverable error we now return TRYAGIN even if the first
 	 response was SUCCESS.  */
 
-  if (anslen1 > 0)
-    status = gaih_getanswer_slice(answer1, anslen1, qname,
-				  &pat, &buffer, &buflen,
-				  errnop, h_errnop, ttlp,
-				  &first);
-
-  if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
-       || (status == NSS_STATUS_TRYAGAIN
-	   /* We want to look at the second answer in case of an
-	      NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
-	      *h_errnop is NO_RECOVERY. If not, and if the failure was due to
-	      an insufficient buffer (ERANGE), then we need to drop the results
-	      and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
-	      repeat the query with a larger buffer.  */
-	   && (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
-      && answer2 != NULL && anslen2 > 0)
+  if (packet1len > 0)
     {
-      enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
-						     &pat, &buffer, &buflen,
-						     errnop, h_errnop, ttlp,
-						     &first);
+      status = gaih_getanswer_slice (packet1, packet1len,
+				     abuf, &pat, errnop, h_errnop, ttlp, true);
+      if (alloc_buffer_has_failed (abuf))
+	/* Do not try parsing the second packet if a larger result
+	   buffer is needed.  The caller implements the resizing
+	   protocol because *abuf has been exhausted.  */
+	return NSS_STATUS_TRYAGAIN; /* Ignored by the caller.  */
+    }
+
+  if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
+      && packet2 != NULL && packet2len > 0)
+    {
+      enum nss_status status2
+	= gaih_getanswer_slice (packet2, packet2len,
+				abuf, &pat, errnop, h_errnop, ttlp,
+				/* Success means that data with a
+				   canonical name has already been
+				   stored.  Do not store the name again.  */
+				status != NSS_STATUS_SUCCESS);
       /* Use the second response status in some cases.  */
       if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
 	status = status2;
-      /* Do not return a truncated second response (unless it was
-	 unavoidable e.g. unrecoverable TRYAGAIN).  */
-      if (status == NSS_STATUS_SUCCESS
-	  && (status2 == NSS_STATUS_TRYAGAIN
-	      && *errnop == ERANGE && *h_errnop != NO_RECOVERY))
-	status = NSS_STATUS_TRYAGAIN;
     }
 
   return status;
@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
 
 /* Variant of gaih_getanswer without a second (AAAA) response.  */
 static enum nss_status
-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname,
-		       struct gaih_addrtuple **pat,
-		       char *buffer, size_t buflen,
+gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
+		       struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
 		       int *errnop, int *h_errnop, int32_t *ttlp)
 {
-  int first = 1;
-
   enum nss_status status = NSS_STATUS_NOTFOUND;
-  if (anslen1 > 0)
-    status = gaih_getanswer_slice (answer1, anslen1, qname,
-				   &pat, &buffer, &buflen,
-				   errnop, h_errnop, ttlp,
-				   &first);
+  if (packetlen > 0)
+    status = gaih_getanswer_slice (packet, packetlen,
+				   abuf, &pat, errnop, h_errnop, ttlp, true);
   return status;
 }
diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c
index 07a412d8ff..213edceaf3 100644
--- a/resolv/res-name-checking.c
+++ b/resolv/res-name-checking.c
@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn)
   return dn[0] > 0 && dn[1] == '-';
 }
 
+bool
+__res_binary_hnok (const unsigned char *dn)
+{
+  return !binary_leading_dash (dn) && binary_hnok (dn);
+}
+
 /* Return 1 if res_hnok is a valid host name.  Labels must only
    contain [0-9a-zA-Z_-] characters, and the name must not start with
    a '-'.  The latter is to avoid confusion with program options.  */
@@ -145,11 +151,9 @@ int
 ___res_hnok (const char *dn)
 {
   unsigned char buf[NS_MAXCDNAME];
-  if (!printable_string (dn)
-      || __ns_name_pton (dn, buf, sizeof (buf)) < 0
-      || binary_leading_dash (buf))
-    return 0;
-  return binary_hnok (buf);
+  return (printable_string (dn)
+	  && __ns_name_pton (dn, buf, sizeof (buf)) >= 0
+	  && __res_binary_hnok (buf));
 }
 versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34);
 versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE);
diff --git a/resolv/res_send.c b/resolv/res_send.c
index 6a08e729a4..1bcc98ed21 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -947,9 +947,11 @@ send_dg(res_state statp,
 		seconds /= statp->nscount;
 	if (seconds <= 0)
 		seconds = 1;
-	bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
-	bool single_request = (((statp->options & RES_SNGLKUP) != 0)
-			       | single_request_reopen);
+	bool single_request_reopen = ((statp->options & RES_SNGLKUPREOP)
+				      || (statp->_flags & RES_F_SNGLKUPREOP));
+	bool single_request = ((statp->options & RES_SNGLKUP)
+			       || (statp->_flags & RES_F_SNGLKUP)
+			       || single_request_reopen);
 	int save_gotsomewhere = *gotsomewhere;
 
 	int retval;
@@ -1006,14 +1008,14 @@ send_dg(res_state statp,
 		       have received the first answer.  */
 		    if (!single_request)
 		      {
-			statp->options |= RES_SNGLKUP;
+			statp->_flags |= RES_F_SNGLKUP;
 			single_request = true;
 			*gotsomewhere = save_gotsomewhere;
 			goto retry;
 		      }
 		    else if (!single_request_reopen)
 		      {
-			statp->options |= RES_SNGLKUPREOP;
+			statp->_flags |= RES_F_SNGLKUPREOP;
 			single_request_reopen = true;
 			*gotsomewhere = save_gotsomewhere;
 			__res_iclose (statp, false);
@@ -1197,19 +1199,30 @@ send_dg(res_state statp,
 		}
 
 		/* Check for the correct header layout and a matching
-		   question.  */
+		   question.  Some recursive resolvers send REFUSED
+		   without copying back the question section
+		   (producing a response that is only HFIXEDSZ bytes
+		   long).  Skip query matching in this case.  */
+		bool thisansp_error = (anhp->rcode == SERVFAIL ||
+				       anhp->rcode == NOTIMP ||
+				       anhp->rcode == REFUSED);
+		bool skip_query_match = (*thisresplenp == HFIXEDSZ
+					 && ntohs (anhp->qdcount) == 0
+					 && thisansp_error);
 		int matching_query = 0; /* Default to no matching query.  */
 		if (!recvresp1
 		    && anhp->id == hp->id
-		    && __libc_res_queriesmatch (buf, buf + buflen,
-						*thisansp,
-						*thisansp + *thisanssizp))
+		    && (skip_query_match
+			|| __libc_res_queriesmatch (buf, buf + buflen,
+						    *thisansp,
+						    *thisansp + *thisanssizp)))
 		  matching_query = 1;
 		if (!recvresp2
 		    && anhp->id == hp2->id
-		    && __libc_res_queriesmatch (buf2, buf2 + buflen2,
-						*thisansp,
-						*thisansp + *thisanssizp))
+		    && (skip_query_match
+			|| __libc_res_queriesmatch (buf2, buf2 + buflen2,
+						    *thisansp,
+						    *thisansp + *thisanssizp)))
 		  matching_query = 2;
 		if (matching_query == 0)
 		  /* Spurious UDP packet.  Drop it and continue
@@ -1219,15 +1232,13 @@ send_dg(res_state statp,
 		    goto wait;
 		  }
 
-		if (anhp->rcode == SERVFAIL ||
-		    anhp->rcode == NOTIMP ||
-		    anhp->rcode == REFUSED) {
+		if (thisansp_error) {
 		next_ns:
 			if (recvresp1 || (buf2 != NULL && recvresp2)) {
 			  *resplen2 = 0;
 			  return resplen;
 			}
-			if (buf2 != NULL)
+			if (buf2 != NULL && !single_request)
 			  {
 			    /* No data from the first reply.  */
 			    resplen = 0;
diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
index bb12f474d2..170a4b9101 100644
--- a/resolv/resolv-internal.h
+++ b/resolv/resolv-internal.h
@@ -26,6 +26,8 @@
 #define RES_F_VC        0x00000001 /* Socket is TCP.  */
 #define RES_F_CONN      0x00000002 /* Socket is connected.  */
 #define RES_F_EDNS0ERR  0x00000004 /* EDNS0 caused errors.  */
+#define RES_F_SNGLKUP	0x00200000 /* Private version of RES_SNGLKUP.  */
+#define RES_F_SNGLKUPREOP 0x00400000 /* Private version of RES_SNGLKUPREOP.  */
 
 /* The structure HEADER is normally aligned on a word boundary.  In
    some code, we need to access this structure when it may be aligned
diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c
new file mode 100644
index 0000000000..c4a2904db7
--- /dev/null
+++ b/resolv/tst-ns_name_length_uncompressed.c
@@ -0,0 +1,135 @@
+/* Test __ns_name_length_uncompressed.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <array_length.h>
+#include <errno.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+
+/* Reference implementation based on other building blocks.  */
+static int
+reference_length (const unsigned char *p, const unsigned char *eom)
+{
+  unsigned char buf[NS_MAXCDNAME];
+  int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf));
+  if (n < 0)
+    return n;
+  const unsigned char *q = buf;
+  if (__ns_name_skip (&q, array_end (buf)) < 0)
+    return -1;
+  if (q - buf != n)
+    /* Compressed name.  */
+    return -1;
+  return n;
+}
+
+static int
+do_test (void)
+{
+  {
+    unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 };
+    TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2);
+    TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)),
+                  sizeof (buf) - 2);
+    TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1);
+    TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1,
+                                                 array_end (buf)), 1);
+    buf[4]  = 0xc0;             /* Forward compression reference.  */
+    buf[5]  = 0x06;
+    TEST_COMPARE (reference_length (buf, array_end (buf)), -1);
+    TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1);
+  }
+
+  struct support_next_to_fault ntf = support_next_to_fault_allocate (300);
+
+  /* Buffer region with all possible bytes at start and end.  */
+  for (int length = 1; length <= 300; ++length)
+    {
+      unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
+      unsigned char *start = end - length;
+      memset (start, 'X', length);
+      for (int first = 0; first <= 255; ++first)
+        {
+          *start = first;
+          for (int last = 0; last <= 255; ++last)
+            {
+              start[length - 1] = last;
+              TEST_COMPARE (reference_length (start, end),
+                            __ns_name_length_uncompressed (start, end));
+            }
+        }
+    }
+
+  /* Poor man's fuzz testing: patch two bytes.   */
+  {
+    unsigned char ref[] =
+      {
+        7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0
+      };
+    TEST_COMPARE (reference_length (ref, array_end (ref)), 13);
+    TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13);
+
+    int good = 0;
+    int bad = 0;
+    for (int length = 1; length <= sizeof (ref); ++length)
+      {
+        unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
+        unsigned char *start = end - length;
+        memcpy (start, ref, length);
+
+        for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos)
+          {
+            for (int patch1_value = 0; patch1_value <= 255; ++patch1_value)
+              {
+                start[patch1_pos] = patch1_value;
+                for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos)
+                  {
+                    for (int patch2_value = 0; patch2_value <= 255;
+                         ++patch2_value)
+                      {
+                        start[patch2_pos] = patch2_value;
+                        int expected = reference_length (start, end);
+                        errno = EINVAL;
+                        int actual
+                          =  __ns_name_length_uncompressed (start, end);
+                        if (actual > 0)
+                          ++good;
+                        else
+                          {
+                            TEST_COMPARE (errno, EMSGSIZE);
+                            ++bad;
+                          }
+                        TEST_COMPARE (expected, actual);
+                      }
+                    start[patch2_pos] = ref[patch2_pos];
+                  }
+              }
+            start[patch1_pos] = ref[patch1_pos];
+          }
+      }
+    printf ("info: patched inputs with success: %d\n", good);
+    printf ("info: patched inputs with failure: %d\n", bad);
+  }
+
+  support_next_to_fault_free (&ntf);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c
new file mode 100644
index 0000000000..c3c0908905
--- /dev/null
+++ b/resolv/tst-ns_rr_cursor.c
@@ -0,0 +1,227 @@
+/* Tests for resource record parsing.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+
+/* Reference packet for packet parsing.  */
+static const unsigned char valid_packet[] =
+  { 0x11, 0x12, 0x13, 0x14,
+    0x00, 0x01,               /* Question count.  */
+    0x00, 0x02,               /* Answer count.  */
+    0x21, 0x22, 0x23, 0x24,   /* Other counts (not actually in packet).  */
+    3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0,
+    0x00, 0x1c,               /* Question type: AAAA.  */
+    0x00, 0x01,               /* Question class: IN.  */
+    0xc0, 0x0c,               /* Compression reference to QNAME.  */
+    0x00, 0x1c,               /* Record type: AAAA.  */
+    0x00, 0x01,               /* Record class: IN.  */
+    0x12, 0x34, 0x56, 0x78,   /* Record TTL.  */
+    0x00, 0x10,               /* Record data length (16 bytes).  */
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address.  */
+    0xc0, 0x0c,               /* Compression reference to QNAME.  */
+    0x00, 0x1c,               /* Record type: AAAA.  */
+    0x00, 0x01,               /* Record class: IN.  */
+    0x11, 0x33, 0x55, 0x77,   /* Record TTL.  */
+    0x00, 0x10,               /* Record data length (16 bytes).  */
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address.  */
+  };
+
+/* Special offsets in valid_packet.  */
+enum
+  {
+    offset_of_first_record = 29,
+    offset_of_second_record = 57,
+  };
+
+/* Check that parsing valid_packet succeeds.  */
+static void
+test_valid (void)
+{
+  struct ns_rr_cursor c;
+  TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet,
+                                         sizeof (valid_packet)));
+  TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
+  TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
+  TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
+  TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
+  TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
+  TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
+  TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
+  TEST_COMPARE (c.current - valid_packet, offset_of_first_record);
+
+  struct ns_rr_wire r;
+  TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
+  TEST_COMPARE (r.rtype, T_AAAA);
+  TEST_COMPARE (r.rclass, C_IN);
+  TEST_COMPARE (r.ttl, 0x12345678);
+  TEST_COMPARE_BLOB (r.rdata, r.rdlength,
+                     "\x90\x91\x92\x93\x94\x95\x96\x97"
+                     "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
+  TEST_COMPARE (c.current - valid_packet, offset_of_second_record);
+  TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
+  TEST_COMPARE (r.rtype, T_AAAA);
+  TEST_COMPARE (r.rclass, C_IN);
+  TEST_COMPARE (r.ttl, 0x11335577);
+  TEST_COMPARE_BLOB (r.rdata, r.rdlength,
+                     "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                     "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16);
+  TEST_VERIFY (c.current == c.end);
+}
+
+/* Check that trying to parse a packet with a compressed QNAME fails.  */
+static void
+test_compressed_qname (void)
+{
+  static const unsigned char packet[] =
+    { 0x11, 0x12, 0x13, 0x14,
+      0x00, 0x01,               /* Question count.  */
+      0x00, 0x00,               /* Answer count.  */
+      0x00, 0x00, 0x00, 0x00,   /* Other counts.  */
+      3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
+      0x00, 0x01,               /* Question type: A.  */
+      0x00, 0x01,               /* Question class: IN.  */
+    };
+
+  struct ns_rr_cursor c;
+  TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
+}
+
+/* Check that trying to parse a packet with two questions fails.  */
+static void
+test_two_questions (void)
+{
+  static const unsigned char packet[] =
+    { 0x11, 0x12, 0x13, 0x14,
+      0x00, 0x02,               /* Question count.  */
+      0x00, 0x00,               /* Answer count.  */
+      0x00, 0x00, 0x00, 0x00,   /* Other counts.  */
+      3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
+      0x00, 0x01,               /* Question type: A.  */
+      0x00, 0x01,               /* Question class: IN.  */
+      3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
+      0x00, 0x1c,               /* Question type: AAAA.  */
+      0x00, 0x01,               /* Question class: IN.  */
+    };
+
+  struct ns_rr_cursor c;
+  TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
+}
+
+/* Used to check that parsing truncated packets does not over-read.  */
+static struct support_next_to_fault ntf;
+
+/* Truncated packet in the second resource record.  */
+static void
+test_truncated_one_rr (size_t length)
+{
+  unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
+  unsigned char *start = end - length;
+
+  /* Produce the truncated packet.  */
+  memcpy (start, valid_packet, length);
+
+  struct ns_rr_cursor c;
+  TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
+  TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
+  TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
+  TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
+  TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
+  TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
+  TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
+  TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
+  TEST_COMPARE (c.current - start, offset_of_first_record);
+
+  struct ns_rr_wire r;
+  TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
+  TEST_COMPARE (r.rtype, T_AAAA);
+  TEST_COMPARE (r.rclass, C_IN);
+  TEST_COMPARE (r.ttl, 0x12345678);
+  TEST_COMPARE_BLOB (r.rdata, r.rdlength,
+                     "\x90\x91\x92\x93\x94\x95\x96\x97"
+                     "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
+  TEST_COMPARE (c.current - start, offset_of_second_record);
+  TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
+}
+
+/* Truncated packet in the first resource record.  */
+static void
+test_truncated_no_rr (size_t length)
+{
+  unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
+  unsigned char *start = end - length;
+
+  /* Produce the truncated packet.  */
+  memcpy (start, valid_packet, length);
+
+  struct ns_rr_cursor c;
+  TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
+  TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
+  TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
+  TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
+  TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
+  TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
+  TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
+  TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
+  TEST_COMPARE (c.current - start, offset_of_first_record);
+
+  struct ns_rr_wire r;
+  TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
+}
+
+/* Truncated packet before first resource record.  */
+static void
+test_truncated_before_rr (size_t length)
+{
+  unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
+  unsigned char *start = end - length;
+
+  /* Produce the truncated packet.  */
+  memcpy (start, valid_packet, length);
+
+  struct ns_rr_cursor c;
+  TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length));
+}
+
+static int
+do_test (void)
+{
+  ntf = support_next_to_fault_allocate (sizeof (valid_packet));
+
+  test_valid ();
+  test_compressed_qname ();
+  test_two_questions ();
+
+  for (int length = offset_of_second_record; length < sizeof (valid_packet);
+       ++length)
+    test_truncated_one_rr (length);
+  for (int length = offset_of_first_record; length < offset_of_second_record;
+       ++length)
+    test_truncated_no_rr (length);
+  for (int length = 0; length < offset_of_first_record; ++length)
+    test_truncated_before_rr (length);
+
+  support_next_to_fault_free (&ntf);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c
new file mode 100644
index 0000000000..b06ac610b4
--- /dev/null
+++ b/resolv/tst-ns_samebinaryname.c
@@ -0,0 +1,62 @@
+/* Test the __ns_samebinaryname function.
+   Copyright (C) 2022 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 <arpa/nameser.h>
+#include <array_length.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <support/check.h>
+
+/* First character denotes the comparison group: All names with the
+   same first character are expected to compare equal.  */
+static const char *const cases[] =
+  {
+    " ",
+    "1\001a", "1\001A",
+    "2\002ab", "2\002aB", "2\002Ab", "2\002AB",
+    "3\001a\002ab", "3\001A\002ab",
+    "w\003www\007example\003com", "w\003Www\007Example\003Com",
+    "w\003WWW\007EXAMPLE\003COM",
+    "W\003WWW", "W\003www",
+  };
+
+static int
+do_test (void)
+{
+  for (int i = 0; i < array_length (cases); ++i)
+    for (int j = 0; j < array_length (cases); ++j)
+      {
+        unsigned char *a = (unsigned char *) &cases[i][1];
+        unsigned char *b = (unsigned char *) &cases[j][1];
+        bool actual = __ns_samebinaryname (a, b);
+        bool expected = cases[i][0] == cases[j][0];
+        if (actual != expected)
+          {
+            char a1[NS_MAXDNAME];
+            TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0);
+            char b1[NS_MAXDNAME];
+            TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0);
+            printf ("error: \"%s\" \"%s\": expected %s\n",
+                    a1, b1, expected ? "equal" : "unqueal");
+            support_record_failure ();
+          }
+      }
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c
new file mode 100644
index 0000000000..b212823aa0
--- /dev/null
+++ b/resolv/tst-resolv-aliases.c
@@ -0,0 +1,254 @@
+/* Test alias handling (mainly for gethostbyname).
+   Copyright (C) 2022 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 <array_length.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+#include "tst-resolv-maybe_insert_sig.h"
+
+/* QNAME format:
+
+   aADDRESSES-cCNAMES.example.net
+
+   CNAMES is the length of the CNAME chain, ADDRESSES is the number of
+   addresses in the response.  The special value 255 means that there
+   are no addresses, and the RCODE is NXDOMAIN.  */
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  TEST_COMPARE (qclass, C_IN);
+  if (qtype != T_A)
+    TEST_COMPARE (qtype, T_AAAA);
+
+  unsigned int addresses, cnames;
+  char *tail;
+  if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3)
+    {
+      if (strcmp (tail, ".example.com") == 0
+          || strcmp (tail, ".example.net.example.net") == 0
+          || strcmp (tail, ".example.net.example.com") == 0)
+        /* These only happen after NXDOMAIN.  */
+        TEST_VERIFY (addresses == 255);
+      else if (strcmp (tail, ".example.net") != 0)
+        FAIL_EXIT1 ("invalid QNAME: %s", qname);
+    }
+  free (tail);
+
+  int rcode;
+  if (addresses == 255)
+    {
+      /* Special case: Use no addresses with NXDOMAIN response.  */
+      rcode = ns_r_nxdomain;
+      addresses = 0;
+    }
+  else
+    rcode = 0;
+
+  struct resolv_response_flags flags = { .rcode = rcode };
+  resolv_response_init (b, flags);
+  resolv_response_add_question (b, qname, qclass, qtype);
+  resolv_response_section (b, ns_s_an);
+  maybe_insert_sig (b, qname);
+
+  /* Provide the requested number of CNAME records.  */
+  char *previous_name = (char *) qname;
+  for (int unique = 0; unique < cnames; ++unique)
+    {
+      resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
+      char *new_name = xasprintf ("%d.alias.example", unique);
+      resolv_response_add_name (b, new_name);
+      resolv_response_close_record (b);
+
+      maybe_insert_sig (b, qname);
+
+      if (previous_name != qname)
+        free (previous_name);
+      previous_name = new_name;
+    }
+
+  for (int unique = 0; unique < addresses; ++unique)
+    {
+      resolv_response_open_record (b, previous_name, qclass, qtype, 60);
+
+      if (qtype == T_A)
+        {
+          char ipv4[4] = {192, 0, 2, 1 + unique};
+          resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+        }
+      else if (qtype == T_AAAA)
+        {
+          char ipv6[16] =
+            {
+              0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+              1 + unique
+            };
+          resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+        }
+      resolv_response_close_record (b);
+    }
+
+  if (previous_name != qname)
+    free (previous_name);
+}
+
+static char *
+make_qname (bool do_search, int cnames, int addresses)
+{
+  return xasprintf ("a%d-c%d%s",
+                    addresses, cnames, do_search ? "" : ".example.net");
+}
+
+static void
+check_cnames_failure (int af, bool do_search, int cnames, int addresses)
+{
+  char *qname = make_qname (do_search, cnames, addresses);
+
+  struct hostent *e;
+  if (af == AF_UNSPEC)
+    e = gethostbyname (qname);
+  else
+    e = gethostbyname2 (qname, af);
+
+  if (addresses == 0)
+    check_hostent (qname, e, "error: NO_RECOVERY\n");
+  else
+    check_hostent (qname, e, "error: HOST_NOT_FOUND\n");
+
+  free (qname);
+}
+
+static void
+check (int af, bool do_search, int cnames, int addresses)
+{
+  char *qname = make_qname (do_search, cnames, addresses);
+  char *fqdn = make_qname (false, cnames, addresses);
+
+  struct hostent *e;
+  if (af == AF_UNSPEC)
+    e = gethostbyname (qname);
+  else
+    e = gethostbyname2 (qname, af);
+  if (e == NULL)
+    FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses);
+
+  if (af == AF_UNSPEC || af == AF_INET)
+    {
+      TEST_COMPARE (e->h_addrtype, AF_INET);
+      TEST_COMPARE (e->h_length, 4);
+    }
+  else
+    {
+      TEST_COMPARE (e->h_addrtype, AF_INET6);
+      TEST_COMPARE (e->h_length, 16);
+    }
+
+  for (int i = 0; i < addresses; ++i)
+    {
+      char ipv4[4] = {192, 0, 2, 1 + i};
+      char ipv6[16] =
+        { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i };
+      char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6;
+      TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length,
+                         expected, e->h_length);
+    }
+  TEST_VERIFY (e->h_addr_list[addresses] == NULL);
+
+
+  if (cnames == 0)
+    {
+      /* QNAME is fully qualified.  */
+      TEST_COMPARE_STRING (e->h_name, fqdn);
+      TEST_VERIFY (e->h_aliases[0] == NULL);
+    }
+  else
+   {
+     /* Fully-qualified QNAME is demoted to an aliases.  */
+     TEST_COMPARE_STRING (e->h_aliases[0], fqdn);
+
+     for (int i = 1; i <= cnames; ++i)
+       {
+         char *expected = xasprintf ("%d.alias.example", i - 1);
+         if (i == cnames)
+           TEST_COMPARE_STRING (e->h_name, expected);
+         else
+           TEST_COMPARE_STRING (e->h_aliases[i], expected);
+         free (expected);
+       }
+     TEST_VERIFY (e->h_aliases[cnames] == NULL);
+   }
+
+  free (fqdn);
+  free (qname);
+}
+
+static int
+do_test (void)
+{
+  struct resolv_test *obj = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response,
+       .search = { "example.net", "example.com" },
+     });
+
+  static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 };
+
+  for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
+    {
+      insert_sig = do_insert_sig;
+
+      /* If do_search is true, a bare host name (for example, a1-c1)
+         is used.  This exercises search path processing and FQDN
+         qualification.  */
+      for (int do_search = 0; do_search < 2; ++do_search)
+        for (const int *paf = families; paf != array_end (families); ++paf)
+          {
+            for (int cnames = 0; cnames <= 100; ++cnames)
+              {
+                check_cnames_failure (*paf, do_search, cnames, 0);
+                /* Now with NXDOMAIN responses.  */
+                check_cnames_failure (*paf, do_search, cnames, 255);
+              }
+
+            for (int cnames = 0; cnames <= 10; ++cnames)
+              for (int addresses = 1; addresses <= 10; ++addresses)
+                check (*paf, do_search, cnames, addresses);
+
+            /* The current implementation is limited to 47 aliases.
+               Addresses do not have such a limit.  */
+            check (*paf, do_search, 47, 60);
+          }
+    }
+
+  resolv_test_end (obj);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c
new file mode 100644
index 0000000000..6299e89837
--- /dev/null
+++ b/resolv/tst-resolv-byaddr.c
@@ -0,0 +1,326 @@
+/* Test reverse DNS lookup.
+   Copyright (C) 2022 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 <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/next_to_fault.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+#include "tst-resolv-maybe_insert_sig.h"
+
+/* QNAME format:
+
+   ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa.
+   CNAMES|ADDRESSES.2.0.192.in-addr-arpa.
+
+   For the IPv4 reverse lookup, the address count is in the lower
+   bits.
+
+   CNAMES is the length of the CNAME chain, ADDRESSES is the number of
+   addresses in the response.  The special value 15 means that there
+   are no addresses, and the RCODE is NXDOMAIN.  */
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  TEST_COMPARE (qclass, C_IN);
+  TEST_COMPARE (qtype, T_PTR);
+
+  unsigned int addresses, cnames, bits;
+  char *tail;
+  if (strstr (qname, "ip6.arpa") != NULL
+      && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3)
+    TEST_COMPARE_STRING (tail, "\
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
+  else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2)
+    {
+      TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa");
+      addresses = bits & 0x0f;
+      cnames = bits >> 4;
+    }
+  else
+    FAIL_EXIT1 ("invalid QNAME: %s", qname);
+  free (tail);
+
+  int rcode;
+  if (addresses == 15)
+    {
+      /* Special case: Use no addresses with NXDOMAIN response.  */
+      rcode = ns_r_nxdomain;
+      addresses = 0;
+    }
+  else
+    rcode = 0;
+
+  struct resolv_response_flags flags = { .rcode = rcode };
+  resolv_response_init (b, flags);
+  resolv_response_add_question (b, qname, qclass, qtype);
+  resolv_response_section (b, ns_s_an);
+  maybe_insert_sig (b, qname);
+
+  /* Provide the requested number of CNAME records.  */
+  char *previous_name = (char *) qname;
+  for (int unique = 0; unique < cnames; ++unique)
+    {
+      resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
+      char *new_name = xasprintf ("%d.alias.example", unique);
+      resolv_response_add_name (b, new_name);
+      resolv_response_close_record (b);
+
+      maybe_insert_sig (b, qname);
+
+      if (previous_name != qname)
+        free (previous_name);
+      previous_name = new_name;
+    }
+
+  for (int unique = 0; unique < addresses; ++unique)
+    {
+      resolv_response_open_record (b, previous_name, qclass, T_PTR, 60);
+      char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example",
+                             unique, cnames, addresses);
+      resolv_response_add_name (b, ptr);
+      free (ptr);
+      resolv_response_close_record (b);
+    }
+
+  if (previous_name != qname)
+    free (previous_name);
+}
+
+/* Used to check that gethostbyaddr_r does not write past the buffer
+   end.  */
+static struct support_next_to_fault ntf;
+
+/* Perform a gethostbyaddr call and check the result.  */
+static void
+check_gethostbyaddr (const char *address, const char *expected)
+{
+  unsigned char bytes[16];
+  unsigned int byteslen;
+  int family;
+  if (strchr (address, ':') != NULL)
+    {
+      family = AF_INET6;
+      byteslen = 16;
+    }
+  else
+    {
+      family = AF_INET;
+      byteslen = 4;
+    }
+  TEST_COMPARE (inet_pton (family, address, bytes), 1);
+
+  struct hostent *e = gethostbyaddr (bytes, byteslen, family);
+  check_hostent (address, e, expected);
+
+  if (e == NULL)
+    return;
+
+  /* Try gethostbyaddr_r with increasing sizes until success.  First
+     compute a reasonable minimum buffer size, to avoid many pointless
+     attempts.  */
+  size_t minimum_size = strlen (e->h_name);
+  for (int i = 0; e->h_addr_list[i] != NULL; ++i)
+    minimum_size += e->h_length + sizeof (char *);
+  for (int i = 0; e->h_aliases[i] != NULL; ++i)
+    minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *);
+
+  /* Gradually increase the size until success.  */
+  for (size_t size = minimum_size; size < ntf.length; ++size)
+    {
+      struct hostent result;
+      int herrno;
+      int ret = gethostbyaddr_r (bytes, byteslen, family, &result,
+                                 ntf.buffer + ntf.length - size, size,
+                                 &e, &herrno);
+      if (ret == ERANGE)
+        /* Retry with larger size.  */
+        TEST_COMPARE (herrno, NETDB_INTERNAL);
+      else if (ret == 0)
+        {
+         TEST_VERIFY (size > minimum_size);
+         check_hostent (address, e, expected);
+         return;
+        }
+      else
+        FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret);
+    }
+
+  FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address);
+}
+
+/* Perform a getnameinfo call and check the result.  */
+static void
+check_getnameinfo (const char *address, const char *expected)
+{
+  struct sockaddr_in sin = { };
+  struct sockaddr_in6 sin6 = { };
+  void *sa;
+  socklen_t salen;
+  if (strchr (address, ':') != NULL)
+    {
+      sin6.sin6_family = AF_INET6;
+      TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1);
+      sin6.sin6_port = htons (80);
+      sa = &sin6;
+      salen = sizeof (sin6);
+    }
+  else
+    {
+      sin.sin_family = AF_INET;
+      TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1);
+      sin.sin_port = htons (80);
+      sa = &sin;
+      salen = sizeof (sin);
+    }
+
+  char host[64];
+  char service[64];
+  int ret = getnameinfo (sa, salen, host,
+                         sizeof (host), service, sizeof (service),
+                         NI_NAMEREQD | NI_NUMERICSERV);
+  switch (ret)
+    {
+    case 0:
+      TEST_COMPARE_STRING (host, expected);
+      TEST_COMPARE_STRING (service, "80");
+      break;
+    case EAI_SYSTEM:
+      TEST_COMPARE_STRING (strerror (errno), expected);
+      break;
+    default:
+      TEST_COMPARE_STRING (gai_strerror (ret), expected);
+    }
+}
+
+static int
+do_test (void)
+{
+  /* Some reasonably upper bound for the maximum response size.  */
+  ntf = support_next_to_fault_allocate (4096);
+
+  struct resolv_test *obj = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response
+     });
+
+  for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig)
+    {
+      insert_sig = do_insert_sig;
+
+      /* No PTR record, RCODE=0.  */
+      check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n");
+      check_getnameinfo ("192.0.2.0", "Name or service not known");
+      check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n");
+      check_getnameinfo ("192.0.2.16", "Name or service not known");
+      check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n");
+      check_getnameinfo ("192.0.2.32", "Name or service not known");
+      check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n");
+      check_getnameinfo ("2001:db8::", "Name or service not known");
+      check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n");
+      check_getnameinfo ("2001:db8::10", "Name or service not known");
+      check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n");
+      check_getnameinfo ("2001:db8::20", "Name or service not known");
+
+      /* No PTR record, NXDOMAIN.  */
+      check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n");
+      check_getnameinfo ("192.0.2.15", "Name or service not known");
+      check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n");
+      check_getnameinfo ("192.0.2.31", "Name or service not known");
+      check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n");
+      check_getnameinfo ("192.0.2.47", "Name or service not known");
+      check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n");
+      check_getnameinfo ("2001:db8::f", "Name or service not known");
+      check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n");
+      check_getnameinfo ("2001:db8::1f", "Name or service not known");
+      check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n");
+      check_getnameinfo ("2001:db8::2f", "Name or service not known");
+
+      /* Actual response data.  Only the first PTR record is returned.  */
+      check_gethostbyaddr ("192.0.2.1",
+                           "name: unique-0.cnames-0.addresses-1.example\n"
+                           "address: 192.0.2.1\n");
+      check_getnameinfo ("192.0.2.1",
+                         "unique-0.cnames-0.addresses-1.example");
+      check_gethostbyaddr ("192.0.2.17",
+                           "name: unique-0.cnames-1.addresses-1.example\n"
+                           "address: 192.0.2.17\n");
+      check_getnameinfo ("192.0.2.17",
+                         "unique-0.cnames-1.addresses-1.example");
+      check_gethostbyaddr ("192.0.2.18",
+                           "name: unique-0.cnames-1.addresses-2.example\n"
+                           "address: 192.0.2.18\n");
+      check_getnameinfo ("192.0.2.18",
+                         "unique-0.cnames-1.addresses-2.example");
+      check_gethostbyaddr ("192.0.2.33",
+                           "name: unique-0.cnames-2.addresses-1.example\n"
+                           "address: 192.0.2.33\n");
+      check_getnameinfo ("192.0.2.33",
+                         "unique-0.cnames-2.addresses-1.example");
+      check_gethostbyaddr ("192.0.2.34",
+                           "name: unique-0.cnames-2.addresses-2.example\n"
+                           "address: 192.0.2.34\n");
+      check_getnameinfo ("192.0.2.34",
+                         "unique-0.cnames-2.addresses-2.example");
+
+      /* Same for IPv6 addresses.  */
+      check_gethostbyaddr ("2001:db8::1",
+                           "name: unique-0.cnames-0.addresses-1.example\n"
+                           "address: 2001:db8::1\n");
+      check_getnameinfo ("2001:db8::1",
+                         "unique-0.cnames-0.addresses-1.example");
+      check_gethostbyaddr ("2001:db8::11",
+                           "name: unique-0.cnames-1.addresses-1.example\n"
+                           "address: 2001:db8::11\n");
+      check_getnameinfo ("2001:db8::11",
+                         "unique-0.cnames-1.addresses-1.example");
+      check_gethostbyaddr ("2001:db8::12",
+                           "name: unique-0.cnames-1.addresses-2.example\n"
+                           "address: 2001:db8::12\n");
+      check_getnameinfo ("2001:db8::12",
+                         "unique-0.cnames-1.addresses-2.example");
+      check_gethostbyaddr ("2001:db8::21",
+                           "name: unique-0.cnames-2.addresses-1.example\n"
+                           "address: 2001:db8::21\n");
+      check_getnameinfo ("2001:db8::21",
+                         "unique-0.cnames-2.addresses-1.example");
+      check_gethostbyaddr ("2001:db8::22",
+                           "name: unique-0.cnames-2.addresses-2.example\n"
+                           "address: 2001:db8::22\n");
+      check_getnameinfo ("2001:db8::22",
+                         "unique-0.cnames-2.addresses-2.example");
+    }
+
+  resolv_test_end (obj);
+
+  support_next_to_fault_free (&ntf);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c
new file mode 100644
index 0000000000..63dac90e02
--- /dev/null
+++ b/resolv/tst-resolv-invalid-cname.c
@@ -0,0 +1,406 @@
+/* Test handling of CNAMEs with non-host domain names (bug 12154).
+   Copyright (C) 2022 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 <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* Query strings describe the CNAME chain in the response.  They have
+   the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are
+   replaced by unsigned decimal numbers.  COUNT is the number of CNAME
+   records in the response.  BITS has two bits for each CNAME record,
+   describing a special prefix that is added to that CNAME.
+
+   0: No special leading label.
+   1: Starting with "*.".
+   2: Starting with "-x.".
+   3: Starting with "star.*.".
+
+   The first CNAME in the response using the two least significant
+   bits.
+
+   For PTR queries, the QNAME format is different, it is either
+   COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still
+   decimal), or:
+
+COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
+
+   where BITS and COUNT are hexadecimal.  */
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  TEST_COMPARE (qclass, C_IN);
+
+  /* The only other query type besides A is PTR.  */
+  if (qtype != T_A && qtype != T_AAAA)
+    TEST_COMPARE (qtype, T_PTR);
+
+  unsigned int bits, bits1, count;
+  char *tail = NULL;
+  if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3)
+    TEST_COMPARE_STRING (tail, "example");
+  else if (strstr (qname, "in-addr.arpa") != NULL
+           && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3)
+    TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa");
+  else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4)
+    {
+      TEST_COMPARE_STRING (tail, "\
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
+      bits |= bits1 << 4;
+    }
+  else
+    FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
+  free (tail);
+
+  struct resolv_response_flags flags = {};
+  resolv_response_init (b, flags);
+  resolv_response_add_question (b, qname, qclass, qtype);
+  resolv_response_section (b, ns_s_an);
+
+  /* Provide the requested number of CNAME records.  */
+  char *previous_name = (char *) qname;
+  unsigned int original_bits = bits;
+  for (int unique = 0; unique < count; ++unique)
+    {
+      resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60);
+
+      static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." };
+      char *new_name = xasprintf ("%sunique%d.example",
+                                  bits_to_prefix[bits & 3], unique);
+      bits >>= 2;
+      resolv_response_add_name (b, new_name);
+      resolv_response_close_record (b);
+
+      if (previous_name != qname)
+        free (previous_name);
+      previous_name = new_name;
+    }
+
+  /* Actual answer record.  */
+  resolv_response_open_record (b, previous_name, qclass, qtype, 60);
+  switch (qtype)
+    {
+    case T_A:
+      {
+        char ipv4[4] = {192, 168, count, original_bits};
+        resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+      }
+      break;
+    case T_AAAA:
+      {
+        char ipv6[16] =
+          {
+            0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            count, original_bits
+          };
+        resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+      }
+      break;
+
+    case T_PTR:
+      {
+        char *name = xasprintf ("bits%u.count%u.example",
+                                original_bits, count);
+        resolv_response_add_name (b, name);
+        free (name);
+      }
+      break;
+    }
+  resolv_response_close_record (b);
+
+  if (previous_name != qname)
+    free (previous_name);
+}
+
+/* Controls which name resolution function is invoked.  */
+enum test_mode
+  {
+    byname,                     /* gethostbyname.  */
+    byname2,                    /* gethostbyname2.  */
+    gai,                        /* getaddrinfo without AI_CANONNAME.  */
+    gai_canon,                  /* getaddrinfo with AI_CANONNAME.  */
+
+    test_mode_num               /* Number of enum values.  */
+  };
+
+static const char *
+test_mode_to_string (enum test_mode mode)
+{
+  switch (mode)
+    {
+    case byname:
+      return "byname";
+    case byname2:
+      return "byname2";
+    case gai:
+      return "gai";
+    case gai_canon:
+      return "gai_canon";
+    case test_mode_num:
+      break;                    /* Report error below.  */
+    }
+  FAIL_EXIT1 ("invalid test_mode: %d", mode);
+}
+
+/* Append the name and aliases to OUT.  */
+static void
+append_names (FILE *out, const char *qname, int bits, int count,
+              enum test_mode mode)
+{
+  /* Largest valid index which has a corresponding zero in bits
+     (meaning a syntactically valid CNAME).  */
+  int last_valid_cname = -1;
+
+  for (int i = 0; i < count; ++i)
+    if ((bits & (3 << (i * 2))) == 0)
+      last_valid_cname = i;
+
+  if (mode != gai)
+    {
+      const char *label;
+      if (mode == gai_canon)
+        label = "canonname";
+      else
+        label = "name";
+      if (last_valid_cname >= 0)
+        fprintf (out, "%s: unique%d.example\n", label, last_valid_cname);
+      else
+        fprintf (out, "%s: %s\n", label, qname);
+    }
+
+  if (mode == byname || mode == byname2)
+    {
+      if (last_valid_cname >= 0)
+        fprintf (out, "alias: %s\n", qname);
+      for (int i = 0; i < count; ++i)
+        {
+          if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname)
+            fprintf (out, "alias: unique%d.example\n", i);
+        }
+    }
+}
+
+/* Append the address information to OUT.  */
+static void
+append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode)
+{
+  int last = count * 256 + bits;
+  if (mode == gai || mode == gai_canon)
+    {
+      if (af == AF_INET || af == AF_UNSPEC)
+        fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits);
+      if (af == AF_INET6 || af == AF_UNSPEC)
+        {
+          if (last == 0)
+            fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n");
+          else
+            fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last);
+        }
+    }
+  else
+    {
+      TEST_VERIFY (af != AF_UNSPEC);
+      if (af == AF_INET)
+        fprintf (out, "address: 192.168.%d.%d\n", count, bits);
+      if (af == AF_INET6)
+        {
+          if (last == 0)
+            fprintf (out, "address: 2001:db8::\n");
+          else
+            fprintf (out, "address: 2001:db8::%x\n", last);
+        }
+    }
+}
+
+/* Perform one test using a forward lookup.  */
+static void
+check_forward (int af, int bits, int count, enum test_mode mode)
+{
+  char *qname = xasprintf ("bits%d.count%d.example", bits, count);
+  char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s",
+                           af, bits, count, test_mode_to_string (mode), qname);
+
+  struct xmemstream expected;
+  xopen_memstream (&expected);
+  if (mode == gai_canon)
+    fprintf (expected.out, "flags: AI_CANONNAME\n");
+  append_names (expected.out, qname, bits, count, mode);
+  append_addresses (expected.out, af, bits, count, mode);
+  xfclose_memstream (&expected);
+
+  if (mode == gai || mode == gai_canon)
+    {
+      struct addrinfo *ai;
+      struct addrinfo hints =
+        {
+          .ai_family = af,
+          .ai_socktype = SOCK_STREAM,
+        };
+      if (mode == gai_canon)
+        hints.ai_flags |= AI_CANONNAME;
+      int ret = getaddrinfo (qname, "80", &hints, &ai);
+      check_addrinfo (label, ai, ret, expected.buffer);
+      if (ret == 0)
+        freeaddrinfo (ai);
+    }
+  else
+    {
+      struct hostent *e;
+      if (mode == gai)
+        {
+          TEST_COMPARE (af, AF_INET);
+          e = gethostbyname (qname);
+        }
+      else
+        {
+          if (af != AF_INET)
+            TEST_COMPARE (af, AF_INET6);
+          e = gethostbyname2 (qname, af);
+        }
+      check_hostent (label, e, expected.buffer);
+    }
+
+  free (expected.buffer);
+  free (label);
+  free (qname);
+}
+
+/* Perform one check using a reverse lookup.  */
+
+static void
+check_reverse (int af, int bits, int count)
+{
+  TEST_VERIFY (af == AF_INET || af == AF_INET6);
+
+  char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count);
+  char *fqdn = xasprintf ("bits%d.count%d.example", bits, count);
+
+  struct xmemstream expected;
+  xopen_memstream (&expected);
+  fprintf (expected.out, "name: %s\n", fqdn);
+  append_addresses (expected.out, af, bits, count, byname);
+  xfclose_memstream (&expected);
+
+  char addr[16] = { 0 };
+  socklen_t addrlen;
+  if (af == AF_INET)
+    {
+      addr[0] = 192;
+      addr[1] = 168;
+      addr[2] = count;
+      addr[3] = bits;
+      addrlen = 4;
+    }
+  else
+    {
+      addr[0] = 0x20;
+      addr[1] = 0x01;
+      addr[2] = 0x0d;
+      addr[3] = 0xb8;
+      addr[14] = count;
+      addr[15] = bits;
+      addrlen = 16;
+    }
+
+  struct hostent *e = gethostbyaddr (addr, addrlen, af);
+  check_hostent (label, e, expected.buffer);
+
+  /* getnameinfo check is different.  There is no generic check_*
+     function for it.  */
+  {
+    struct sockaddr_in sin = { };
+    struct sockaddr_in6 sin6 = { };
+    void *sa;
+    socklen_t salen;
+    if (af == AF_INET)
+      {
+        sin.sin_family = AF_INET;
+        memcpy (&sin.sin_addr, addr, addrlen);
+        sin.sin_port = htons (80);
+        sa = &sin;
+        salen = sizeof (sin);
+      }
+    else
+      {
+        sin6.sin6_family = AF_INET6;
+        memcpy (&sin6.sin6_addr, addr, addrlen);
+        sin6.sin6_port = htons (80);
+        sa = &sin6;
+        salen = sizeof (sin6);
+      }
+
+    char host[64];
+    char service[64];
+    int ret = getnameinfo (sa, salen, host,
+                           sizeof (host), service, sizeof (service),
+                           NI_NAMEREQD | NI_NUMERICSERV);
+    TEST_COMPARE (ret, 0);
+    TEST_COMPARE_STRING (host, fqdn);
+    TEST_COMPARE_STRING (service, "80");
+  }
+
+  free (expected.buffer);
+  free (fqdn);
+  free (label);
+}
+
+static int
+do_test (void)
+{
+  struct resolv_test *obj = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response
+     });
+
+  for (int count = 0; count <= 3; ++count)
+    for (int bits = 0; bits <= 1 << (count * 2); ++bits)
+      {
+        if (count > 0 && bits == count)
+          /* The last bits value is only checked if count == 0.  */
+          continue;
+
+        for (enum test_mode mode = 0; mode < test_mode_num; ++mode)
+          {
+            check_forward (AF_INET, bits, count, mode);
+            if (mode != byname)
+              check_forward (AF_INET6, bits, count, mode);
+            if (mode == gai || mode == gai_canon)
+              check_forward (AF_UNSPEC, bits, count, mode);
+          }
+
+        check_reverse (AF_INET, bits, count);
+        check_reverse (AF_INET6, bits, count);
+      }
+
+  resolv_test_end (obj);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h
new file mode 100644
index 0000000000..05725225af
--- /dev/null
+++ b/resolv/tst-resolv-maybe_insert_sig.h
@@ -0,0 +1,32 @@
+/* Code snippet for optionally inserting ignored SIG records in resolver tests.
+   Copyright (C) 2022 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/>.  */
+
+/* Set to true for an alternative pass that inserts (ignored) SIG
+   records.  This does not alter the response, so this property is not
+   encoded in the QNAME.  The variable needs to be volatile because
+   leaf attributes tell GCC that the response function is not
+   called.  */
+static volatile bool insert_sig;
+
+static void
+maybe_insert_sig (struct resolv_response_builder *b, const char *owner)
+{
+  resolv_response_open_record (b, owner, C_IN, T_SIG, 60);
+  resolv_response_add_data (b, "", 1);
+  resolv_response_close_record (b);
+}
diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c
new file mode 100644
index 0000000000..9f5aebd99f
--- /dev/null
+++ b/resolv/tst-resolv-noaaaa-vc.c
@@ -0,0 +1,129 @@
+/* Test the RES_NOAAAA resolver option with a large response.
+   Copyright (C) 2022-2023 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 <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* Used to keep track of the number of queries.  */
+static volatile unsigned int queries;
+
+/* If true, add a large TXT record at the start of the answer section.  */
+static volatile bool stuff_txt;
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  /* If not using TCP, just force its use.  */
+  if (!ctx->tcp)
+    {
+      struct resolv_response_flags flags = {.tc = true};
+      resolv_response_init (b, flags);
+      resolv_response_add_question (b, qname, qclass, qtype);
+      return;
+    }
+
+  /* The test needs to send four queries, the first three are used to
+     grow the NSS buffer via the ERANGE handshake.  */
+  ++queries;
+  TEST_VERIFY (queries <= 4);
+
+  /* AAAA queries are supposed to be disabled.  */
+  TEST_COMPARE (qtype, T_A);
+  TEST_COMPARE (qclass, C_IN);
+  TEST_COMPARE_STRING (qname, "example.com");
+
+  struct resolv_response_flags flags = {};
+  resolv_response_init (b, flags);
+  resolv_response_add_question (b, qname, qclass, qtype);
+
+  resolv_response_section (b, ns_s_an);
+
+  if (stuff_txt)
+    {
+      resolv_response_open_record (b, qname, qclass, T_TXT, 60);
+      int zero = 0;
+      for (int i = 0; i <= 15000; ++i)
+        resolv_response_add_data (b, &zero, sizeof (zero));
+      resolv_response_close_record (b);
+    }
+
+  for (int i = 0; i < 200; ++i)
+    {
+      resolv_response_open_record (b, qname, qclass, qtype, 60);
+      char ipv4[4] = {192, 0, 2, i + 1};
+      resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+      resolv_response_close_record (b);
+    }
+}
+
+static int
+do_test (void)
+{
+  struct resolv_test *obj = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response
+     });
+
+  _res.options |= RES_NOAAAA;
+
+  for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt)
+    {
+      queries = 0;
+      stuff_txt = do_stuff_txt;
+
+      struct addrinfo *ai = NULL;
+      int ret;
+      ret = getaddrinfo ("example.com", "80",
+                         &(struct addrinfo)
+                         {
+                           .ai_family = AF_UNSPEC,
+                           .ai_socktype = SOCK_STREAM,
+                         }, &ai);
+
+      char *expected_result;
+      {
+        struct xmemstream mem;
+        xopen_memstream (&mem);
+        for (int i = 0; i < 200; ++i)
+          fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1);
+        xfclose_memstream (&mem);
+        expected_result = mem.buffer;
+      }
+
+      check_addrinfo ("example.com", ai, ret, expected_result);
+
+      free (expected_result);
+      freeaddrinfo (ai);
+    }
+
+  resolv_test_end (obj);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c
new file mode 100644
index 0000000000..aa9798b5a7
--- /dev/null
+++ b/resolv/tst-resolv-semi-failure.c
@@ -0,0 +1,133 @@
+/* Test parallel failure/success responses (bug 30081).
+   Copyright (C) 2024 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 <resolv.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/check_nss.h>
+
+/* The rcode in the initial response.  */
+static volatile int rcode;
+
+/* Whether to fail the initial A query (!fail_aaaa) or the initial
+   AAAA query (fail_aaaa).  */
+static volatile bool fail_aaaa;
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  /* Handle the failing query.  */
+  if ((fail_aaaa && qtype == T_AAAA) && ctx->server_index == 0)
+    {
+      struct resolv_response_flags flags = {.rcode = rcode};
+      resolv_response_init (b, flags);
+      return;
+    }
+
+  /* Otherwise produce a response.  */
+  resolv_response_init (b, (struct resolv_response_flags) {});
+  resolv_response_add_question (b, qname, qclass, qtype);
+  resolv_response_section (b, ns_s_an);
+  resolv_response_open_record (b, qname, qclass, qtype, 0);
+  switch (qtype)
+    {
+    case T_A:
+      {
+        char ipv4[4] = {192, 0, 2, 17};
+        resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+      }
+      break;
+    case T_AAAA:
+      {
+        char ipv6[16]
+          = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+        resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+      }
+      break;
+    default:
+      FAIL_EXIT1 ("unexpected TYPE%d query", qtype);
+    }
+  resolv_response_close_record (b);
+}
+
+static void
+check_one (void)
+{
+
+  /* The buggy 1-second query timeout results in 30 seconds of delay,
+     which triggers are test timeout failure.  */
+  for (int i = 0;  i < 30; ++i)
+    {
+      static const struct addrinfo hints =
+        {
+          .ai_family = AF_UNSPEC,
+          .ai_socktype = SOCK_STREAM,
+        };
+      struct addrinfo *ai;
+      int ret = getaddrinfo ("www.example", "80", &hints, &ai);
+      const char *expected;
+      if (ret == 0 && ai->ai_next != NULL)
+        expected = ("address: STREAM/TCP 192.0.2.17 80\n"
+                    "address: STREAM/TCP 2001:db8::1 80\n");
+      else
+        /* Only one response because the AAAA lookup failure is
+           treated as an ignoreable error.  */
+        expected = "address: STREAM/TCP 192.0.2.17 80\n";
+      check_addrinfo ("www.example", ai, ret, expected);
+      if (ret == 0)
+        freeaddrinfo (ai);
+    }
+}
+
+static int
+do_test (void)
+{
+  for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup)
+    {
+      struct resolv_test *aux = resolv_test_start
+        ((struct resolv_redirect_config)
+         {
+           .response_callback = response,
+         });
+
+      if (do_single_lookup)
+        _res.options |= RES_SNGLKUP;
+
+      for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa)
+        {
+          fail_aaaa = do_fail_aaaa;
+
+          rcode = 2; /* SERVFAIL.  */
+          check_one ();
+
+          rcode = 4; /* NOTIMP.  */
+          check_one ();
+
+          rcode = 5; /* REFUSED.  */
+          check_one ();
+        }
+
+      resolv_test_end (aux);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c
new file mode 100644
index 0000000000..9b06b0c176
--- /dev/null
+++ b/resolv/tst-resolv-short-response.c
@@ -0,0 +1,126 @@
+/* Test for spurious timeouts with short 12-byte responses (bug 31890).
+   Copyright (C) 2024 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 <resolv.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/check_nss.h>
+
+/* The rcode in the initial response.  */
+static volatile int rcode;
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  switch (ctx->server_index)
+    {
+    case 0:
+      /* First server times out.  */
+      {
+        struct resolv_response_flags flags = {.rcode = rcode};
+        resolv_response_init (b, flags);
+      }
+      break;
+    case 1:
+      /* Second server sends reply.  */
+      resolv_response_init (b, (struct resolv_response_flags) {});
+      resolv_response_add_question (b, qname, qclass, qtype);
+      resolv_response_section (b, ns_s_an);
+      resolv_response_open_record (b, qname, qclass, qtype, 0);
+      switch (qtype)
+        {
+        case T_A:
+          {
+            char ipv4[4] = {192, 0, 2, 17};
+            resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+          }
+          break;
+        case T_AAAA:
+          {
+            char ipv6[16]
+              = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+            resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+          }
+          break;
+        default:
+          FAIL_EXIT1 ("unexpected TYPE%d query", qtype);
+        }
+      resolv_response_close_record (b);
+      break;
+    default:
+      FAIL_EXIT1 ("unexpected query to server %d", ctx->server_index);
+    }
+}
+
+static void
+check_one (void)
+{
+
+  /* The buggy 1-second query timeout results in 30 seconds of delay,
+     which triggers a test timeout failure.  */
+  for (int i = 0;  i < 10; ++i)
+    {
+      check_hostent ("www.example", gethostbyname ("www.example"),
+                     "name: www.example\n"
+                     "address: 192.0.2.17\n");
+      check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6),
+                     "name: www.example\n"
+                     "address: 2001:db8::1\n");
+      static const struct addrinfo hints =
+        {
+          .ai_family = AF_UNSPEC,
+          .ai_socktype = SOCK_STREAM,
+        };
+      struct addrinfo *ai;
+      int ret = getaddrinfo ("www.example", "80", &hints, &ai);
+      check_addrinfo ("www.example", ai, ret,
+                      "address: STREAM/TCP 192.0.2.17 80\n"
+                      "address: STREAM/TCP 2001:db8::1 80\n");
+      if (ret == 0)
+        freeaddrinfo (ai);
+    }
+}
+
+static int
+do_test (void)
+{
+  struct resolv_test *aux = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response,
+     });
+
+  _res.options |= RES_SNGLKUP;
+
+  rcode = 2; /* SERVFAIL.  */
+  check_one ();
+
+  rcode = 4; /* NOTIMP.  */
+  check_one ();
+
+  rcode = 5; /* REFUSED.  */
+  check_one ();
+
+  resolv_test_end (aux);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/rt/aio_misc.c b/rt/aio_misc.c
index b4304d0a6f..5f9e52bcba 100644
--- a/rt/aio_misc.c
+++ b/rt/aio_misc.c
@@ -698,7 +698,7 @@ libc_freeres_fn (free_res)
 {
   size_t row;
 
-  for (row = 0; row < pool_max_size; ++row)
+  for (row = 0; row < pool_size; ++row)
     free (pool[row]);
 
   free (pool);
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
index 2dd6bfda18..b87cf2f809 100644
--- a/scripts/dso-ordering-test.py
+++ b/scripts/dso-ordering-test.py
@@ -707,13 +707,12 @@ def process_testcase(t):
                 "\t$(compile.c) $(OUTPUT_OPTION)\n")
         makefile.write (rule)
 
-        not_depended_objs = find_objs_not_depended_on(test_descr)
-        if not_depended_objs:
-            depstr = ""
-            for dep in not_depended_objs:
-                depstr += (" $(objpfx)" + test_subdir + "/"
-                           + test_name + "-" + dep + ".so")
-            makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
+        # Ensure that all shared objects are built before running the
+        # test, whether there link-time dependencies or not.
+        depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
+                   for dep in test_descr.objs]
+        makefile.write("$(objpfx){}.out: {}\n".format(
+            base_test_name, " ".join(depobjs)))
 
         # Add main executable to test-srcs
         makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
index 43ab58ffe2..36d204c9b0 100644
--- a/scripts/glibcextract.py
+++ b/scripts/glibcextract.py
@@ -17,6 +17,7 @@
 # License along with the GNU C Library; if not, see
 # <https://www.gnu.org/licenses/>.
 
+import collections
 import os.path
 import re
 import subprocess
@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
             if not allow_extra_2:
                 ret = 1
     return ret
+
+CompileResult = collections.namedtuple("CompileResult", "returncode output")
+
+def compile_c_snippet(snippet, cc, extra_cc_args=''):
+    """Compile and return whether the SNIPPET can be build with CC along
+       EXTRA_CC_ARGS compiler flags.  Return a CompileResult with RETURNCODE
+       being 0 for success, or the failure value and the compiler output.
+    """
+    with tempfile.TemporaryDirectory() as temp_dir:
+        c_file_name = os.path.join(temp_dir, 'test.c')
+        obj_file_name = os.path.join(temp_dir, 'test.o')
+        with open(c_file_name, 'w') as c_file:
+            c_file.write(snippet + '\n')
+        cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
+                c_file_name]
+        r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
+                stderr=subprocess.STDOUT)
+        return CompileResult(r.returncode, r.stdout)
diff --git a/socket/Makefile b/socket/Makefile
index 156eec6c85..2bde78387f 100644
--- a/socket/Makefile
+++ b/socket/Makefile
@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt	\
 tests := \
   tst-accept4 \
   tst-sockopt \
+  tst-cmsghdr \
   # tests
 
 tests-internal := \
diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
index 0aface5639..0b1cb015ce 100644
--- a/socket/bits/socket2.h
+++ b/socket/bits/socket2.h
@@ -33,12 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
 __fortify_function ssize_t
 recv (int __fd, void *__buf, size_t __n, int __flags)
 {
-  size_t sz = __glibc_objsize0 (__buf);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize0 (__buf);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __recv_alias (__fd, __buf, __n, __flags);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __recv_chk_warn (__fd, __buf, __n, sz, __flags);
-  return __recv_chk (__fd, __buf, __n, sz, __flags);
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __recv_chk_warn (__fd, __buf, __n, __sz, __flags);
+  return __recv_chk (__fd, __buf, __n, __sz, __flags);
 }
 
 extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
@@ -61,11 +61,11 @@ __fortify_function ssize_t
 recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
 	  __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
 {
-  size_t sz = __glibc_objsize0 (__buf);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize0 (__buf);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr,
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __recvfrom_chk_warn (__fd, __buf, __n, __sz, __flags, __addr,
 				__addr_len);
-  return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
+  return __recvfrom_chk (__fd, __buf, __n, __sz, __flags, __addr, __addr_len);
 }
diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
new file mode 100644
index 0000000000..4c6898569b
--- /dev/null
+++ b/socket/tst-cmsghdr-skeleton.c
@@ -0,0 +1,92 @@
+/* Test ancillary data header creation.
+   Copyright (C) 2022 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/>.  */
+
+/* We use the preprocessor to generate the function/macro tests instead of
+   using indirection because having all the macro expansions alongside
+   each other lets the compiler warn us about suspicious pointer
+   arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions.  */
+
+#include <stdint.h>
+
+#define RUN_TEST_CONCAT(suffix) run_test_##suffix
+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
+
+static void
+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
+{
+  struct msghdr m = {0};
+  struct cmsghdr *cmsg;
+  char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
+
+  m.msg_control = cmsgbuf;
+  m.msg_controllen = sizeof (cmsgbuf);
+
+  /* First header should point to the start of the buffer.  */
+  cmsg = CMSG_FIRSTHDR (&m);
+  TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
+
+  /* If the first header length consumes the entire buffer, there is no
+     space remaining for additional headers.  */
+  cmsg->cmsg_len = sizeof (cmsgbuf);
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg == NULL);
+
+  /* The first header length is so big, using it would cause an overflow.  */
+  cmsg = CMSG_FIRSTHDR (&m);
+  TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
+  cmsg->cmsg_len = SIZE_MAX;
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg == NULL);
+
+  /* The first header leaves just enough space to hold another header.  */
+  cmsg = CMSG_FIRSTHDR (&m);
+  TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
+  cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg != NULL);
+
+  /* The first header leaves space but not enough for another header.  */
+  cmsg = CMSG_FIRSTHDR (&m);
+  TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
+  cmsg->cmsg_len ++;
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg == NULL);
+
+  /* The second header leaves just enough space to hold another header.  */
+  cmsg = CMSG_FIRSTHDR (&m);
+  TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
+  cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg != NULL);
+  cmsg->cmsg_len = sizeof (cmsgbuf)
+                   - CMSG_SPACE (sizeof (PAYLOAD)) /* First header.  */
+                   - sizeof (struct cmsghdr);
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg != NULL);
+
+  /* The second header leaves space but not enough for another header.  */
+  cmsg = CMSG_FIRSTHDR (&m);
+  TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg != NULL);
+  cmsg->cmsg_len ++;
+  cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
+  TEST_VERIFY_EXIT (cmsg == NULL);
+
+  return;
+}
diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
new file mode 100644
index 0000000000..68c96d3c9d
--- /dev/null
+++ b/socket/tst-cmsghdr.c
@@ -0,0 +1,56 @@
+/* Test ancillary data header creation.
+   Copyright (C) 2022 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 <sys/socket.h>
+#include <gnu/lib-names.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+
+#define PAYLOAD "Hello, World!"
+
+/* CMSG_NXTHDR is a macro that calls an inline function defined in
+   bits/socket.h.  In case the function cannot be inlined, libc.so carries
+   a copy.  Both versions need to be tested.  */
+
+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
+#include "tst-cmsghdr-skeleton.c"
+#undef CMSG_NXTHDR_IMPL
+
+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
+
+#define CMSG_NXTHDR_IMPL cmsg_nxthdr
+#include "tst-cmsghdr-skeleton.c"
+#undef CMSG_NXTHDR_IMPL
+
+static int
+do_test (void)
+{
+  static void *handle;
+
+  run_test_CMSG_NXTHDR ();
+
+  handle = xdlopen (LIBC_SO, RTLD_LAZY);
+  cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
+                  xdlsym (handle, "__cmsg_nxthdr");
+
+  run_test_cmsg_nxthdr ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index b1e9144de0..743e2611fa 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -190,6 +190,7 @@ tests := \
   tst-put-error \
   tst-renameat2 \
   tst-rndseek \
+  tst-scanf-bz27650 \
   tst-scanf-round \
   tst-setvbuf1 \
   tst-sprintf \
@@ -201,6 +202,7 @@ tests := \
   tst-swscanf \
   tst-tmpnam \
   tst-ungetc \
+  tst-ungetc-leak \
   tst-unlockedio \
   tst-vfprintf-mbs-prec \
   tst-vfprintf-user-type \
@@ -233,6 +235,7 @@ tests-special += \
   $(objpfx)tst-printfsz-islongdouble.out \
   $(objpfx)tst-setvbuf1-cmp.out \
   $(objpfx)tst-unbputc.out \
+  $(objpfx)tst-ungetc-leak-mem.out \
   $(objpfx)tst-vfprintf-width-prec-mem.out \
   # tests-special
 
@@ -246,6 +249,9 @@ generated += \
   tst-printf-fp-free.mtrace \
   tst-printf-fp-leak-mem.out \
   tst-printf-fp-leak.mtrace \
+  tst-scanf-bz27650.mtrace \
+  tst-ungetc-leak-mem.out \
+  tst-ungetc-leak.mtrace \
   tst-vfprintf-width-prec-mem.out \
   tst-vfprintf-width-prec.mtrace \
   # generated
@@ -316,6 +322,12 @@ tst-printf-fp-free-ENV = \
 tst-printf-fp-leak-ENV = \
   MALLOC_TRACE=$(objpfx)tst-printf-fp-leak.mtrace \
   LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+tst-scanf-bz27650-ENV = \
+  MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \
+  LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-ungetc-leak-ENV = \
+  MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \
+  LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
 
 $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
 	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-scanf-bz27650.c b/stdio-common/tst-scanf-bz27650.c
new file mode 100644
index 0000000000..3a742bc865
--- /dev/null
+++ b/stdio-common/tst-scanf-bz27650.c
@@ -0,0 +1,108 @@
+/* Test for BZ #27650, formatted input matching beyond INT_MAX.
+   Copyright (C) 2024 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 <error.h>
+#include <errno.h>
+#include <limits.h>
+#include <mcheck.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+/* Produce a stream of more than INT_MAX characters via buffer BUF of
+   size SIZE according to bookkeeping in COOKIE and then return EOF.  */
+
+static ssize_t
+io_read (void *cookie, char *buf, size_t size)
+{
+  unsigned int *written = cookie;
+  unsigned int w = *written;
+
+  if (w > INT_MAX)
+    return 0;
+
+  memset (buf, 'a', size);
+  *written = w + size;
+  return size;
+}
+
+/* Consume a stream of more than INT_MAX characters from an artificial
+   input stream of which none is the new line character.  The call to
+   fscanf is supposed to complete upon the EOF condition of input,
+   however in the presence of BZ #27650 it will terminate prematurely
+   with characters still outstanding in input.  Diagnose the condition
+   and return status accordingly.  */
+
+int
+do_test (void)
+{
+  static cookie_io_functions_t io_funcs = { .read = io_read };
+  unsigned int written = 0;
+  FILE *in;
+  int v;
+
+  mtrace ();
+
+  in = fopencookie (&written, "r", io_funcs);
+  if (in == NULL)
+    {
+      FAIL ("fopencookie: %m");
+      goto out;
+    }
+
+  v = fscanf (in, "%*[^\n]");
+  if (ferror (in))
+    {
+      FAIL ("fscanf: input failure, at %u: %m", written);
+      goto out_close;
+    }
+  else if (v == EOF)
+    {
+      FAIL ("fscanf: unexpected end of file, at %u", written);
+      goto out_close;
+    }
+
+  if (!feof (in))
+    {
+      v = fgetc (in);
+      if (ferror (in))
+	FAIL ("fgetc: input failure: %m");
+      else if (v == EOF)
+	FAIL ("fgetc: unexpected end of file after missing end of file");
+      else if (v == '\n')
+	FAIL ("unexpected new line character received");
+      else
+	FAIL ("character received after end of file expected: \\x%02x", v);
+    }
+
+out_close:
+  if (fclose (in) != 0)
+    FAIL ("fclose: %m");
+
+out:
+  return EXIT_SUCCESS;
+}
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 8)
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-ungetc-leak.c b/stdio-common/tst-ungetc-leak.c
new file mode 100644
index 0000000000..6c5152b43f
--- /dev/null
+++ b/stdio-common/tst-ungetc-leak.c
@@ -0,0 +1,32 @@
+/* Test for memory leak with ungetc when stream is unused.
+   Copyright The GNU Toolchain Authors.
+   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 <stdio.h>
+#include <mcheck.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+do_test (void)
+{
+  mtrace ();
+  TEST_COMPARE (ungetc('y', stdin), 'y');
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c
index 1344b2b591..388b202493 100644
--- a/stdio-common/tst-ungetc.c
+++ b/stdio-common/tst-ungetc.c
@@ -1,70 +1,74 @@
-/* Test for ungetc bugs.  */
+/* Test for ungetc bugs.
+   Copyright (C) 1996-2024 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
+   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 <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-
-#undef assert
-#define assert(x) \
-  if (!(x)) \
-    { \
-      fputs ("test failed: " #x "\n", stderr); \
-      retval = 1; \
-      goto the_end; \
-    }
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
 
-int
-main (int argc, char *argv[])
+static int
+do_test (void)
 {
-  char name[] = "/tmp/tst-ungetc.XXXXXX";
+  char *name = NULL;
   FILE *fp = NULL;
-  int retval = 0;
   int c;
   char buffer[64];
 
-  int fd = mkstemp (name);
+  int fd = create_temp_file ("tst-ungetc.", &name);
   if (fd == -1)
-    {
-      printf ("mkstemp failed: %m\n");
-      return 1;
-    }
-  close (fd);
-  fp = fopen (name, "w");
-  assert (fp != NULL)
-  fputs ("bla", fp);
-  fclose (fp);
-  fp = NULL;
+    FAIL_EXIT1 ("cannot create temporary file: %m");
+  xclose (fd);
 
-  fp = fopen (name, "r");
-  assert (fp != NULL);
-  assert (ungetc ('z', fp) == 'z');
-  assert (getc (fp) == 'z');
-  assert (getc (fp) == 'b');
-  assert (getc (fp) == 'l');
-  assert (ungetc ('m', fp) == 'm');
-  assert (getc (fp) == 'm');
-  assert ((c = getc (fp)) == 'a');
-  assert (getc (fp) == EOF);
-  assert (ungetc (c, fp) == c);
-  assert (feof (fp) == 0);
-  assert (getc (fp) == c);
-  assert (getc (fp) == EOF);
-  fclose (fp);
-  fp = NULL;
+  fp = xfopen (name, "w");
+  fputs ("bla", fp);
+  xfclose (fp);
 
-  fp = fopen (name, "r");
-  assert (fp != NULL);
-  assert (getc (fp) == 'b');
-  assert (getc (fp) == 'l');
-  assert (ungetc ('b', fp) == 'b');
-  assert (fread (buffer, 1, 64, fp) == 2);
-  assert (buffer[0] == 'b');
-  assert (buffer[1] == 'a');
+  fp = xfopen (name, "r");
+  TEST_VERIFY_EXIT (ungetc ('z', fp) == 'z');
+  TEST_VERIFY_EXIT (getc (fp) == 'z');
+  TEST_VERIFY_EXIT (getc (fp) == 'b');
+  TEST_VERIFY_EXIT (getc (fp) == 'l');
+  TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm');
+  TEST_VERIFY_EXIT (ungetc ('n', fp) == 'n');
+  TEST_VERIFY_EXIT (getc (fp) == 'n');
+  TEST_VERIFY_EXIT (getc (fp) == 'm');
+  TEST_VERIFY_EXIT ((c = getc (fp)) == 'a');
+  TEST_VERIFY_EXIT (getc (fp) == EOF);
+  TEST_VERIFY_EXIT (ungetc (c, fp) == c);
+  TEST_VERIFY_EXIT (feof (fp) == 0);
+  TEST_VERIFY_EXIT (getc (fp) == c);
+  TEST_VERIFY_EXIT (getc (fp) == EOF);
+  xfclose (fp);
 
-the_end:
-  if (fp != NULL)
-    fclose (fp);
-  unlink (name);
+  fp = xfopen (name, "r");
+  TEST_VERIFY_EXIT (getc (fp) == 'b');
+  TEST_VERIFY_EXIT (getc (fp) == 'l');
+  TEST_VERIFY_EXIT (ungetc ('b', fp) == 'b');
+  TEST_VERIFY_EXIT (fread (buffer, 1, 64, fp) == 2);
+  TEST_VERIFY_EXIT (buffer[0] == 'b');
+  TEST_VERIFY_EXIT (buffer[1] == 'a');
+  xfclose (fp);
 
-  return retval;
+  return 0;
 }
+
+#include <support/test-driver.c>
diff --git a/stdlib/Makefile b/stdlib/Makefile
index f7b25c1981..2da3030efc 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -171,6 +171,7 @@ tests := \
   test-a64l \
   test-at_quick_exit-race \
   test-atexit-race \
+  test-atexit-recursive \
   test-bz22786 \
   test-canon \
   test-canon2 \
@@ -221,6 +222,7 @@ tests := \
   tst-setcontext7 \
   tst-setcontext8 \
   tst-setcontext9 \
+  tst-setenv-environ \
   tst-strfmon_l \
   tst-strfrom \
   tst-strfrom-locale \
diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c
index e417ef624d..960a38f295 100644
--- a/stdlib/arc4random.c
+++ b/stdlib/arc4random.c
@@ -34,7 +34,7 @@ void
 __arc4random_buf (void *p, size_t n)
 {
   static int seen_initialized;
-  size_t l;
+  ssize_t l;
   int fd;
 
   if (n == 0)
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
index de1c3b20f0..19f8bd5b52 100644
--- a/stdlib/bits/stdlib.h
+++ b/stdlib/bits/stdlib.h
@@ -36,16 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
 __fortify_function __wur char *
 __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
 {
-  size_t sz = __glibc_objsize (__resolved);
+  size_t __sz = __glibc_objsize (__resolved);
 
-  if (sz == (size_t) -1)
+  if (__sz == (size_t) -1)
     return __realpath_alias (__name, __resolved);
 
 #if defined _LIBC_LIMITS_H_ && defined PATH_MAX
-  if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
-    return __realpath_chk_warn (__name, __resolved, sz);
+  if (__glibc_unsafe_len (PATH_MAX, sizeof (char), __sz))
+    return __realpath_chk_warn (__name, __resolved, __sz);
 #endif
-  return __realpath_chk (__name, __resolved, sz);
+  return __realpath_chk (__name, __resolved, __sz);
 }
 
 
diff --git a/stdlib/exit.c b/stdlib/exit.c
index bc46109f3e..dc12e212bc 100644
--- a/stdlib/exit.c
+++ b/stdlib/exit.c
@@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
      exit (). */
   while (true)
     {
-      struct exit_function_list *cur = *listp;
+      struct exit_function_list *cur;
+
+    restart:
+      cur = *listp;
 
       if (cur == NULL)
 	{
@@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
 	  if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
 	    /* The last exit function, or another thread, has registered
 	       more exit functions.  Start the loop over.  */
-            continue;
+	    goto restart;
 	}
 
       *listp = cur->next;
diff --git a/stdlib/longlong.h b/stdlib/longlong.h
index 9b89469ac2..d8f76a43b5 100644
--- a/stdlib/longlong.h
+++ b/stdlib/longlong.h
@@ -593,6 +593,18 @@ extern UDItype __umulsidi3 (USItype, USItype);
 #define UMUL_TIME 14
 #endif
 
+#ifdef __loongarch__
+# if W_TYPE_SIZE == 32
+#  define count_leading_zeros(count, x)  ((count) = __builtin_clz (x))
+#  define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x))
+#  define COUNT_LEADING_ZEROS_0 32
+# elif W_TYPE_SIZE == 64
+#  define count_leading_zeros(count, x)  ((count) = __builtin_clzll (x))
+#  define count_trailing_zeros(count, x) ((count) = __builtin_ctzll (x))
+#  define COUNT_LEADING_ZEROS_0 64
+# endif
+#endif
+
 #if defined (__M32R__) && W_TYPE_SIZE == 32
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   /* The cmp clears the condition bit.  */ \
diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c
new file mode 100644
index 0000000000..0596b9763b
--- /dev/null
+++ b/stdlib/test-atexit-recursive.c
@@ -0,0 +1,75 @@
+/* Support file for atexit/exit, etc. race tests (BZ #27749).
+   Copyright (C) 2023 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/>.  */
+
+/* Check that atexit handler registed from another handler still called. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static void
+atexit_cb (void)
+{
+}
+
+static void
+atexit_last (void)
+{
+  _exit (1);
+}
+
+static void
+atexit_recursive (void)
+{
+  atexit (&atexit_cb);
+  atexit (&atexit_last);
+}
+
+_Noreturn static void
+test_and_exit (int count)
+{
+  for (int i = 0; i < count; ++i)
+    atexit (&atexit_cb);
+  atexit (&atexit_recursive);
+  exit (0);
+}
+
+static int
+do_test (void)
+{
+  for (int i = 0; i < 100; ++i)
+    if (xfork () == 0)
+      test_and_exit (i);
+
+  for (int i = 0; i < 100; ++i)
+    {
+      int status;
+      xwaitpid (0, &status, 0);
+      if (!WIFEXITED (status))
+	FAIL_EXIT1 ("Failed iterations %d", i);
+      TEST_COMPARE (WEXITSTATUS (status), 1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test
+#include <support/test-driver.c>
diff --git a/stdlib/tst-secure-getenv.c b/stdlib/tst-secure-getenv.c
index 69719a8acb..ed4728cbba 100644
--- a/stdlib/tst-secure-getenv.c
+++ b/stdlib/tst-secure-getenv.c
@@ -57,13 +57,7 @@ do_test (void)
       exit (1);
     }
 
-  int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
-
-  if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
-    return EXIT_UNSUPPORTED;
-
-  if (!WIFEXITED (status))
-    FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+  support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
 
   return 0;
 }
@@ -82,6 +76,7 @@ alternative_main (int argc, char **argv)
       if (secure_getenv ("PATH") != NULL)
 	FAIL_EXIT (4, "PATH variable not filtered out\n");
 
+      support_record_failure_barrier ();
       exit (EXIT_SUCCESS);
     }
 }
diff --git a/stdlib/tst-setenv-environ.c b/stdlib/tst-setenv-environ.c
new file mode 100644
index 0000000000..02fcef96d0
--- /dev/null
+++ b/stdlib/tst-setenv-environ.c
@@ -0,0 +1,36 @@
+/* Test using setenv with updated environ.
+   Copyright (C) 2025 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 <stdlib.h>
+#include <support/check.h>
+
+extern char **environ;
+
+int
+do_test (void)
+{
+  char *valp;
+  static char *dummy_environ[] = { NULL };
+  environ = dummy_environ;
+  setenv ("A", "1", 0);
+  valp = getenv ("A");
+  TEST_VERIFY_EXIT (valp[0] == '1' && valp[1] == '\0');
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c
index f7fa74b2a6..5e0c79475f 100644
--- a/stdlib/tst-system.c
+++ b/stdlib/tst-system.c
@@ -25,6 +25,7 @@
 #include <support/check.h>
 #include <support/temp_file.h>
 #include <support/support.h>
+#include <support/xthread.h>
 #include <support/xunistd.h>
 
 static char *tmpdir;
@@ -71,6 +72,20 @@ call_system (void *closure)
     }
 }
 
+static void *
+sleep_and_check_sigchld (void *closure)
+{
+  double *seconds = (double *) closure;
+  char cmd[namemax];
+  sprintf (cmd, "sleep %lf" , *seconds);
+  TEST_COMPARE (system (cmd), 0);
+
+  sigset_t blocked = {0};
+  TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0);
+  TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0);
+  return NULL;
+}
+
 static int
 do_test (void)
 {
@@ -154,6 +169,17 @@ do_test (void)
     xchmod (_PATH_BSHELL, st.st_mode);
   }
 
+  {
+    pthread_t long_sleep_thread = xpthread_create (NULL,
+                                                   sleep_and_check_sigchld,
+                                                   &(double) { 0.2 });
+    pthread_t short_sleep_thread = xpthread_create (NULL,
+                                                    sleep_and_check_sigchld,
+                                                    &(double) { 0.1 });
+    xpthread_join (short_sleep_thread);
+    xpthread_join (long_sleep_thread);
+  }
+
   TEST_COMPARE (system (""), 0);
 
   return 0;
diff --git a/string/test-strnlen.c b/string/test-strnlen.c
index 4a9375112a..5cbaf4b734 100644
--- a/string/test-strnlen.c
+++ b/string/test-strnlen.c
@@ -73,7 +73,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
 {
   size_t i;
 
-  align &= 63;
+  align &= (getpagesize () / sizeof (CHAR) - 1);
   if ((align + len) * sizeof (CHAR) >= page_size)
     return;
 
@@ -90,38 +90,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
 static void
 do_overflow_tests (void)
 {
-  size_t i, j, len;
+  size_t i, j, al_idx, repeats, len;
   const size_t one = 1;
   uintptr_t buf_addr = (uintptr_t) buf1;
+  const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 };
 
-  for (i = 0; i < 750; ++i)
+  for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]);
+       al_idx++)
     {
-      do_test (1, i, SIZE_MAX, BIG_CHAR);
-
-      do_test (0, i, SIZE_MAX - i, BIG_CHAR);
-      do_test (0, i, i - buf_addr, BIG_CHAR);
-      do_test (0, i, -buf_addr - i, BIG_CHAR);
-      do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
-      do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
-
-      len = 0;
-      for (j = 8 * sizeof(size_t) - 1; j ; --j)
-        {
-          len |= one << j;
-          do_test (0, i, len - i, BIG_CHAR);
-          do_test (0, i, len + i, BIG_CHAR);
-          do_test (0, i, len - buf_addr - i, BIG_CHAR);
-          do_test (0, i, len - buf_addr + i, BIG_CHAR);
-
-          do_test (0, i, ~len - i, BIG_CHAR);
-          do_test (0, i, ~len + i, BIG_CHAR);
-          do_test (0, i, ~len - buf_addr - i, BIG_CHAR);
-          do_test (0, i, ~len - buf_addr + i, BIG_CHAR);
-
-          do_test (0, i, -buf_addr, BIG_CHAR);
-          do_test (0, i, j - buf_addr, BIG_CHAR);
-          do_test (0, i, -buf_addr - j, BIG_CHAR);
-        }
+      for (repeats = 0; repeats < 2; ++repeats)
+	{
+	  size_t align = repeats ? (getpagesize () - alignments[al_idx])
+				 : alignments[al_idx];
+	  align /= sizeof (CHAR);
+	  for (i = 0; i < 750; ++i)
+	    {
+	      do_test (align, i, SIZE_MAX, BIG_CHAR);
+
+	      do_test (align, i, SIZE_MAX - i, BIG_CHAR);
+	      do_test (align, i, i - buf_addr, BIG_CHAR);
+	      do_test (align, i, -buf_addr - i, BIG_CHAR);
+	      do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
+	      do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
+
+	      len = 0;
+	      for (j = 8 * sizeof (size_t) - 1; j; --j)
+		{
+		  len |= one << j;
+		  do_test (align, i, len, BIG_CHAR);
+		  do_test (align, i, len - i, BIG_CHAR);
+		  do_test (align, i, len + i, BIG_CHAR);
+		  do_test (align, i, len - buf_addr - i, BIG_CHAR);
+		  do_test (align, i, len - buf_addr + i, BIG_CHAR);
+
+		  do_test (align, i, ~len - i, BIG_CHAR);
+		  do_test (align, i, ~len + i, BIG_CHAR);
+		  do_test (align, i, ~len - buf_addr - i, BIG_CHAR);
+		  do_test (align, i, ~len - buf_addr + i, BIG_CHAR);
+
+		  do_test (align, i, -buf_addr, BIG_CHAR);
+		  do_test (align, i, j - buf_addr, BIG_CHAR);
+		  do_test (align, i, -buf_addr - j, BIG_CHAR);
+		}
+	    }
+	}
     }
 }
 
diff --git a/sunrpc/netname.c b/sunrpc/netname.c
index bf7f0b81c4..c1d1c43e50 100644
--- a/sunrpc/netname.c
+++ b/sunrpc/netname.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <rpc/rpc.h>
 #include <shlib-compat.h>
+#include <libc-diag.h>
 
 #include "nsswitch.h"
 
@@ -48,7 +49,12 @@ user2netname (char netname[MAXNETNAMELEN + 1], const uid_t uid,
   if ((strlen (dfltdom) + OPSYS_LEN + 3 + MAXIPRINT) > (size_t) MAXNETNAMELEN)
     return 0;
 
+  /* GCC with -Os warns that sprint might overflow while handling dfltdom,
+     however the above test does check if an overflow would happen.  */
+  DIAG_PUSH_NEEDS_COMMENT;
+  DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wformat-overflow");
   sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom);
+  DIAG_POP_NEEDS_COMMENT;
   i = strlen (netname);
   if (netname[i - 1] == '.')
     netname[i - 1] = '\0';
diff --git a/support/Makefile b/support/Makefile
index 9b50eac117..c8c1363b76 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -32,6 +32,8 @@ libsupport-routines = \
   check_hostent \
   check_netent \
   delayed_exit \
+  dtotimespec \
+  dtotimespec-time64 \
   ignore_stderr \
   next_to_fault \
   oom_error \
@@ -159,6 +161,7 @@ libsupport-routines = \
   xpthread_cancel \
   xpthread_check_return \
   xpthread_cond_wait \
+  xpthread_cond_signal \
   xpthread_create \
   xpthread_detach \
   xpthread_join \
@@ -205,6 +208,7 @@ libsupport-routines = \
   xstrndup \
   xsymlink \
   xsysconf \
+  xsystem \
   xunlink \
   xuselocale \
   xwaitpid \
@@ -237,6 +241,24 @@ CFLAGS-support_paths.c = \
 CFLAGS-timespec.c += -fexcess-precision=standard
 CFLAGS-timespec-time64.c += -fexcess-precision=standard
 
+# Ensure that general support files use 64-bit time_t
+CFLAGS-delayed_exit.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-shell-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_can_chroot.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_copy_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_copy_file_range.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_descriptor_supports_holes.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_descriptors.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_process_state.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_stat_nanoseconds.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_subprocess.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-support_test_main.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-test-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+CFLAGS-xmkdirp.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+# This is required to get an mkstemp which can create large files on some
+# 32-bit platforms.
+CFLAGS-temp_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
+
 ifeq (,$(CXX))
 LINKS_DSO_PROGRAM = links-dso-program-c
 else
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
index e44c965ef3..8cae175bfe 100644
--- a/support/capture_subprocess.h
+++ b/support/capture_subprocess.h
@@ -41,11 +41,12 @@ struct support_capture_subprocess support_capture_subprocess
 struct support_capture_subprocess support_capture_subprogram
   (const char *file, char *const argv[]);
 
-/* Copy the running program into a setgid binary and run it with CHILD_ID
-   argument.  If execution is successful, return the exit status of the child
-   program, otherwise return a non-zero failure exit code.  */
-int support_capture_subprogram_self_sgid
-  (char *child_id);
+/* Copy the running program into a setgid binary and run it with
+   CHILD_ID argument.  If the program exits with a non-zero status,
+   exit with that exit status (or status 1 if the program did not exit
+   normally).  If the test cannot be performed, exit with
+   EXIT_UNSUPPORTED.  */
+void support_capture_subprogram_self_sgid (const char *child_id);
 
 /* Deallocate the subprocess data captured by
    support_capture_subprocess.  */
diff --git a/support/check.h b/support/check.h
index fa080cf480..dac6f04b56 100644
--- a/support/check.h
+++ b/support/check.h
@@ -24,6 +24,11 @@
 
 __BEGIN_DECLS
 
+/* Record a test failure, print the failure message to standard output
+   and pass the result of 1 through.  */
+#define FAIL(...) \
+  support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
+
 /* Record a test failure, print the failure message to standard output
    and return 1.  */
 #define FAIL_RET(...) \
@@ -202,6 +207,9 @@ void support_record_failure_reset (void);
    failures or not.  */
 int support_record_failure_is_failed (void);
 
+/* Terminate the process if any failures have been encountered so far.  */
+void support_record_failure_barrier (void);
+
 __END_DECLS
 
 #endif /* SUPPORT_CHECK_H */
diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c
new file mode 100644
index 0000000000..b3d5e351e3
--- /dev/null
+++ b/support/dtotimespec-time64.c
@@ -0,0 +1,27 @@
+/* Convert double to timespec.  64-bit time support.
+   Copyright (C) 2011-2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library and is also part of gnulib.
+   Patches to this file should be submitted to both projects.
+
+   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 <time.h>
+
+#if __TIMESIZE != 64
+# define timespec      __timespec64
+# define time_t        __time64_t
+# define dtotimespec   dtotimespec_time64
+# include "dtotimespec.c"
+#endif
diff --git a/support/dtotimespec.c b/support/dtotimespec.c
new file mode 100644
index 0000000000..cde5b4d74c
--- /dev/null
+++ b/support/dtotimespec.c
@@ -0,0 +1,50 @@
+/* Convert double to timespec.
+   Copyright (C) 2011-2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library and is also part of gnulib.
+   Patches to this file should be submitted to both projects.
+
+   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/>.  */
+
+/* Convert the double value SEC to a struct timespec.  Round toward
+   positive infinity.  On overflow, return an extremal value.  */
+
+#include <support/timespec.h>
+#include <intprops.h>
+
+struct timespec
+dtotimespec (double sec)
+{
+  if (sec <= TYPE_MINIMUM (time_t))
+    return make_timespec (TYPE_MINIMUM (time_t), 0);
+  else if (sec >= 1.0 + TYPE_MAXIMUM (time_t))
+    return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1);
+  else
+    {
+      time_t s = sec;
+      double frac = TIMESPEC_HZ * (sec - s);
+      long ns = frac;
+      ns += ns < frac;
+      s += ns / TIMESPEC_HZ;
+      ns %= TIMESPEC_HZ;
+
+      if (ns < 0)
+        {
+          s--;
+          ns += TIMESPEC_HZ;
+        }
+
+      return make_timespec (s, ns);
+    }
+}
diff --git a/support/shell-container.c b/support/shell-container.c
index 1c73666f0a..019a6c47d1 100644
--- a/support/shell-container.c
+++ b/support/shell-container.c
@@ -16,8 +16,6 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#define _FILE_OFFSET_BITS 64
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,6 +37,7 @@
 #include <error.h>
 
 #include <support/support.h>
+#include <support/timespec.h>
 
 /* Design considerations
 
@@ -171,6 +170,32 @@ kill_func (char **argv)
   return 0;
 }
 
+/* Emulate the "/bin/sleep" command.  No suffix support.  Options are
+   ignored.  */
+static int
+sleep_func (char **argv)
+{
+  if (argv[0] == NULL)
+    {
+      fprintf (stderr, "sleep: missing operand\n");
+      return 1;
+    }
+  char *endptr = NULL;
+  double sec = strtod (argv[0], &endptr);
+  if (endptr == argv[0] || errno == ERANGE || sec < 0)
+    {
+      fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]);
+      return 1;
+    }
+  struct timespec ts = dtotimespec (sec);
+  if (nanosleep (&ts, NULL) < 0)
+    {
+      fprintf (stderr, "sleep: failed to nanosleep: %s\n", strerror (errno));
+      return 1;
+    }
+  return 0;
+}
+
 /* This is a list of all the built-in commands we understand.  */
 static struct {
   const char *name;
@@ -181,6 +206,7 @@ static struct {
   { "cp", copy_func },
   { "exit", exit_func },
   { "kill", kill_func },
+  { "sleep", sleep_func },
   { NULL, NULL }
 };
 
diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
index ca0e5f7ef4..43979f7c3f 100644
--- a/support/support_can_chroot.c
+++ b/support/support_can_chroot.c
@@ -29,14 +29,14 @@ static void
 callback (void *closure)
 {
   int *result = closure;
-  struct stat64 before;
+  struct stat before;
   xstat ("/dev", &before);
   if (chroot ("/dev") != 0)
     {
       *result = errno;
       return;
     }
-  struct stat64 after;
+  struct stat after;
   xstat ("/", &after);
   TEST_VERIFY (before.st_dev == after.st_dev);
   TEST_VERIFY (before.st_ino == after.st_ino);
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index a8bcb23d40..424d6a910e 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -21,12 +21,17 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <grp.h>
+#include <scratch_buffer.h>
+#include <stdio_ext.h>
 #include <stdlib.h>
+#include <string.h>
 #include <support/check.h>
 #include <support/xunistd.h>
 #include <support/xsocket.h>
 #include <support/xspawn.h>
 #include <support/support.h>
+#include <support/temp_file.h>
 #include <support/test-driver.h>
 
 static void
@@ -108,100 +113,88 @@ support_capture_subprogram (const char *file, char *const argv[])
 /* Copies the executable into a restricted directory, so that we can
    safely make it SGID with the TARGET group ID.  Then runs the
    executable.  */
-static int
-copy_and_spawn_sgid (char *child_id, gid_t gid)
+static void
+copy_and_spawn_sgid (const char *child_id, gid_t gid)
 {
-  char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
-			     test_dir, (intmax_t) getpid ());
+  char *dirname = support_create_temp_directory ("tst-glibc-sgid-");
   char *execname = xasprintf ("%s/bin", dirname);
-  int infd = -1;
-  int outfd = -1;
-  int ret = 1, status = 1;
-
-  TEST_VERIFY (mkdir (dirname, 0700) == 0);
-  if (support_record_failure_is_failed ())
-    goto err;
+  add_temp_file (execname);
 
-  infd = open ("/proc/self/exe", O_RDONLY);
-  if (infd < 0)
+  if (access ("/proc/self/exe", R_OK) != 0)
     FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
 
-  outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
-  TEST_VERIFY (outfd >= 0);
-  if (support_record_failure_is_failed ())
-    goto err;
+  support_copy_file ("/proc/self/exe", execname);
 
-  char buf[4096];
-  for (;;)
-    {
-      ssize_t rdcount = read (infd, buf, sizeof (buf));
-      TEST_VERIFY (rdcount >= 0);
-      if (support_record_failure_is_failed ())
-	goto err;
-      if (rdcount == 0)
-	break;
-      char *p = buf;
-      char *end = buf + rdcount;
-      while (p != end)
-	{
-	  ssize_t wrcount = write (outfd, buf, end - p);
-	  if (wrcount == 0)
-	    errno = ENOSPC;
-	  TEST_VERIFY (wrcount > 0);
-	  if (support_record_failure_is_failed ())
-	    goto err;
-	  p += wrcount;
-	}
-    }
-  TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
-  if (support_record_failure_is_failed ())
-    goto err;
-  TEST_VERIFY (fchmod (outfd, 02750) == 0);
-  if (support_record_failure_is_failed ())
-    goto err;
-  TEST_VERIFY (close (outfd) == 0);
-  if (support_record_failure_is_failed ())
-    goto err;
-  TEST_VERIFY (close (infd) == 0);
-  if (support_record_failure_is_failed ())
-    goto err;
+  if (chown (execname, getuid (), gid) != 0)
+    FAIL_UNSUPPORTED ("cannot change group of \"%s\" to %jd: %m",
+		      execname, (intmax_t) gid);
+
+  if (chmod (execname, 02750) != 0)
+    FAIL_UNSUPPORTED ("cannot make \"%s\" SGID: %m ", execname);
 
   /* We have the binary, now spawn the subprocess.  Avoid using
      support_subprogram because we only want the program exit status, not the
      contents.  */
-  ret = 0;
-  infd = outfd = -1;
 
-  char * const args[] = {execname, child_id, NULL};
+  char * const args[] = {execname, (char *) child_id, NULL};
+  int status = support_subprogram_wait (args[0], args);
 
-  status = support_subprogram_wait (args[0], args);
+  free (execname);
+  free (dirname);
 
-err:
-  if (outfd >= 0)
-    close (outfd);
-  if (infd >= 0)
-    close (infd);
-  if (execname != NULL)
+  if (WIFEXITED (status))
     {
-      unlink (execname);
-      free (execname);
+      if (WEXITSTATUS (status) == 0)
+	return;
+      else
+	exit (WEXITSTATUS (status));
     }
-  if (dirname != NULL)
+  else
+    FAIL_EXIT1 ("subprogram failed with status %d", status);
+}
+
+/* Returns true if a group with NAME has been found, and writes its
+   GID to *TARGET.  */
+static bool
+find_sgid_group (gid_t *target, const char *name)
+{
+  /* Do not use getgrname_r because it does not work in statically
+     linked binaries if the system libc is different.  */
+  FILE *fp = fopen ("/etc/group", "rce");
+  if (fp == NULL)
+    return false;
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  bool ok = false;
+  struct scratch_buffer buf;
+  scratch_buffer_init (&buf);
+  while (true)
     {
-      rmdir (dirname);
-      free (dirname);
+      struct group grp;
+      struct group *result = NULL;
+      int status = fgetgrent_r (fp, &grp, buf.data, buf.length, &result);
+      if (status == 0 && result != NULL)
+	{
+	  if (strcmp (result->gr_name, name) == 0)
+	    {
+	      *target = result->gr_gid;
+	      ok = true;
+	      break;
+	    }
+	}
+      else if (errno != ERANGE)
+	break;
+      else if (!scratch_buffer_grow (&buf))
+	break;
     }
-
-  if (ret != 0)
-    FAIL_EXIT1("Failed to make sgid executable for test\n");
-
-  return status;
+  scratch_buffer_free (&buf);
+  fclose (fp);
+  return ok;
 }
 
-int
-support_capture_subprogram_self_sgid (char *child_id)
+void
+support_capture_subprogram_self_sgid (const char *child_id)
 {
-  gid_t target = 0;
   const int count = 64;
   gid_t groups[count];
 
@@ -213,6 +206,7 @@ support_capture_subprogram_self_sgid (char *child_id)
 		     (intmax_t) getuid ());
 
   gid_t current = getgid ();
+  gid_t target = current;
   for (int i = 0; i < ret; ++i)
     {
       if (groups[i] != current)
@@ -222,11 +216,18 @@ support_capture_subprogram_self_sgid (char *child_id)
 	}
     }
 
-  if (target == 0)
-    FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
-		     (intmax_t) getuid ());
+  if (target == current)
+    {
+      /* If running as root, try to find a harmless group for SGID.  */
+      if (getuid () != 0
+	  || (!find_sgid_group (&target, "nogroup")
+	      && !find_sgid_group (&target, "bin")
+	      && !find_sgid_group (&target, "daemon")))
+	FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
+			 (intmax_t) getuid ());
+    }
 
-  return copy_and_spawn_sgid (child_id, target);
+  copy_and_spawn_sgid (child_id, target);
 }
 
 void
diff --git a/support/support_copy_file.c b/support/support_copy_file.c
index 9a936b37c7..52ed90fae0 100644
--- a/support/support_copy_file.c
+++ b/support/support_copy_file.c
@@ -24,7 +24,7 @@
 void
 support_copy_file (const char *from, const char *to)
 {
-  struct stat64 st;
+  struct stat st;
   xstat (from, &st);
   int fd_from = xopen (from, O_RDONLY, 0);
   mode_t mode = st.st_mode & 0777;
diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c
index d9bcade1cf..83f02f7cf6 100644
--- a/support/support_descriptor_supports_holes.c
+++ b/support/support_descriptor_supports_holes.c
@@ -40,7 +40,7 @@ support_descriptor_supports_holes (int fd)
       block_headroom = 32,
     };
 
-  struct stat64 st;
+  struct stat st;
   xfstat (fd, &st);
   if (!S_ISREG (st.st_mode))
     FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd);
diff --git a/support/support_record_failure.c b/support/support_record_failure.c
index 7e57fe97fb..b00387ff80 100644
--- a/support/support_record_failure.c
+++ b/support/support_record_failure.c
@@ -112,3 +112,13 @@ support_record_failure_is_failed (void)
      synchronization for reliable test error reporting anyway.  */
   return __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
 }
+
+void
+support_record_failure_barrier (void)
+{
+  if (__atomic_load_n (&state->failed, __ATOMIC_RELAXED))
+    {
+      puts ("error: exiting due to previous errors");
+      exit (1);
+    }
+}
diff --git a/support/test-container.c b/support/test-container.c
index b6a1158ae1..2033985a67 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -16,8 +16,6 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#define _FILE_OFFSET_BITS 64
-
 #include <array_length.h>
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/support/timespec.h b/support/timespec.h
index 4d2ac2737d..1bba3a6837 100644
--- a/support/timespec.h
+++ b/support/timespec.h
@@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected,
 				     struct timespec observed,
 				     double lower_bound, double upper_bound);
 
+struct timespec dtotimespec (double sec) __attribute__((const));
+
 #else
 struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec),
 			    timespec_add_time64);
@@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected,
 						  double lower_bound,
 						  double upper_bound),
 		support_timespec_check_in_range_time64);
+
+struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64);
 #endif
 
 /* Check that the timespec on the left represents a time before the
diff --git a/support/xpthread_cond_signal.c b/support/xpthread_cond_signal.c
new file mode 100644
index 0000000000..ed0be1a8ab
--- /dev/null
+++ b/support/xpthread_cond_signal.c
@@ -0,0 +1,26 @@
+/* pthread_cond_signal with error checking.
+   Copyright (C) 2022 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 <support/xthread.h>
+
+void
+xpthread_cond_signal (pthread_cond_t *cond)
+{
+  xpthread_check_return
+    ("pthread_cond_signal", pthread_cond_signal (cond));
+}
diff --git a/support/xstdlib.h b/support/xstdlib.h
new file mode 100644
index 0000000000..db5a5b9d4f
--- /dev/null
+++ b/support/xstdlib.h
@@ -0,0 +1,31 @@
+/* Error-checking wrappers for stdlib functions.
+   Copyright (C) 2023 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/>.  */
+
+#ifndef SUPPORT_XSTDLIB_H
+#define SUPPORT_XSTDLIB_H
+
+#include <stdlib.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void xsystem (const char *cmd);
+
+__END_DECLS
+
+#endif /* SUPPORT_XSTDLIB_H */
diff --git a/support/xsystem.c b/support/xsystem.c
new file mode 100644
index 0000000000..1f558953bc
--- /dev/null
+++ b/support/xsystem.c
@@ -0,0 +1,37 @@
+/* Error-checking replacement for "system".
+   Copyright (C) 2023 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 <support/support.h>
+#include <support/check.h>
+
+#include <support/xstdlib.h>
+
+void
+xsystem (const char *cmd)
+{
+  int ret = system (cmd);
+
+  if (ret == 0 && cmd == NULL)
+    FAIL_EXIT1 ("Unable to spawn a shell for NULL command");
+
+  if (ret == 127)
+    FAIL_EXIT1 ("Child terminated with status 127");
+
+  if (ret < 0)
+    FAIL_EXIT1 ("system (\"%s\")", cmd);
+}
diff --git a/support/xthread.h b/support/xthread.h
index af06715f46..ae09649325 100644
--- a/support/xthread.h
+++ b/support/xthread.h
@@ -62,6 +62,7 @@ void xpthread_mutex_consistent (pthread_mutex_t *);
 void xpthread_spin_lock (pthread_spinlock_t *lock);
 void xpthread_spin_unlock (pthread_spinlock_t *lock);
 void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex);
+void xpthread_cond_signal (pthread_cond_t *cond);
 pthread_t xpthread_create (pthread_attr_t *attr,
                            void *(*thread_func) (void *), void *closure);
 void xpthread_detach (pthread_t thr);
diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure
old mode 100644
new mode 100755
index bf972122b1..19d2b46cbf
--- a/sysdeps/aarch64/configure
+++ b/sysdeps/aarch64/configure
@@ -303,13 +303,14 @@ aarch64-variant-pcs = $libc_cv_aarch64_variant_pcs"
 # Check if asm support armv8.2-a+sve
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVE support in assembler" >&5
 $as_echo_n "checking for SVE support in assembler... " >&6; }
-if ${libc_cv_asm_sve+:} false; then :
+if ${libc_cv_aarch64_sve_asm+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   cat > conftest.s <<\EOF
-        ptrue p0.b
+	.arch armv8.2-a+sve
+	ptrue p0.b
 EOF
-if { ac_try='${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&5'
+if { ac_try='${CC-cc} -c conftest.s 1>&5'
   { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -321,8 +322,8 @@ else
 fi
 rm -f conftest*
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_sve" >&5
-$as_echo "$libc_cv_asm_sve" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_sve_asm" >&5
+$as_echo "$libc_cv_aarch64_sve_asm" >&6; }
 if test $libc_cv_aarch64_sve_asm = yes; then
   $as_echo "#define HAVE_AARCH64_SVE_ASM 1" >>confdefs.h
 
diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac
index 51253d9802..bb5adb1782 100644
--- a/sysdeps/aarch64/configure.ac
+++ b/sysdeps/aarch64/configure.ac
@@ -88,11 +88,12 @@ EOF
 LIBC_CONFIG_VAR([aarch64-variant-pcs], [$libc_cv_aarch64_variant_pcs])
 
 # Check if asm support armv8.2-a+sve
-AC_CACHE_CHECK(for SVE support in assembler, libc_cv_asm_sve, [dnl
+AC_CACHE_CHECK([for SVE support in assembler], [libc_cv_aarch64_sve_asm], [dnl
 cat > conftest.s <<\EOF
-        ptrue p0.b
+	.arch armv8.2-a+sve
+	ptrue p0.b
 EOF
-if AC_TRY_COMMAND(${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&AS_MESSAGE_LOG_FD); then
+if AC_TRY_COMMAND(${CC-cc} -c conftest.s 1>&AS_MESSAGE_LOG_FD); then
   libc_cv_aarch64_sve_asm=yes
 else
   libc_cv_aarch64_sve_asm=no
diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S
index 909b208578..d66f0b9c45 100644
--- a/sysdeps/aarch64/dl-trampoline.S
+++ b/sysdeps/aarch64/dl-trampoline.S
@@ -298,12 +298,11 @@ _dl_runtime_profile:
 	stp	x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
 	stp	x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
 	stp	x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
-	str	x8,     [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4]
 	stp	q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
 	stp	q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
 	stp	q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
 	stp	q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3]
-	str	xzr,    [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS]
+	str	xzr,    [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS]
 
 	/* Setup call to pltexit  */
 	ldp	x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
@@ -315,7 +314,6 @@ _dl_runtime_profile:
 	ldp	x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
 	ldp	x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
 	ldp	x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
-	ldr	x8,     [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4]
 	ldp	q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
 	ldp	q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
 	ldp	q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
diff --git a/sysdeps/aarch64/memchr.S b/sysdeps/aarch64/memchr.S
index 2053a977b6..79aa910da4 100644
--- a/sysdeps/aarch64/memchr.S
+++ b/sysdeps/aarch64/memchr.S
@@ -30,7 +30,6 @@
 # define MEMCHR __memchr
 #endif
 
-/* Arguments and results.  */
 #define srcin		x0
 #define chrin		w1
 #define cntin		x2
@@ -73,42 +72,44 @@ ENTRY (MEMCHR)
 
 	rbit	synd, synd
 	clz	synd, synd
-	add	result, srcin, synd, lsr 2
 	cmp	cntin, synd, lsr 2
+	add	result, srcin, synd, lsr 2
 	csel	result, result, xzr, hi
 	ret
 
+	.p2align 3
 L(start_loop):
 	sub	tmp, src, srcin
-	add	tmp, tmp, 16
+	add	tmp, tmp, 17
 	subs	cntrem, cntin, tmp
-	b.ls	L(nomatch)
+	b.lo	L(nomatch)
 
 	/* Make sure that it won't overread by a 16-byte chunk */
-	add	tmp, cntrem, 15
-	tbnz	tmp, 4, L(loop32_2)
-
+	tbz	cntrem, 4, L(loop32_2)
+	sub	src, src, 16
 	.p2align 4
 L(loop32):
-	ldr	qdata, [src, 16]!
+	ldr	qdata, [src, 32]!
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
 	fmov	synd, dend
 	cbnz	synd, L(end)
 
 L(loop32_2):
-	ldr	qdata, [src, 16]!
-	subs	cntrem, cntrem, 32
+	ldr	qdata, [src, 16]
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
-	b.ls	L(end)
+	subs	cntrem, cntrem, 32
+	b.lo	L(end_2)
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
 	fmov	synd, dend
 	cbz	synd, L(loop32)
+L(end_2):
+	add	src, src, 16
 L(end):
 	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
+	sub	cntrem, src, srcin
 	fmov	synd, dend
-	add	tmp, srcin, cntin
-	sub	cntrem, tmp, src
+	sub	cntrem, cntin, cntrem
 #ifndef __AARCH64EB__
 	rbit	synd, synd
 #endif
diff --git a/sysdeps/aarch64/memcpy.S b/sysdeps/aarch64/memcpy.S
index 98d4e2c0e2..7b396b202f 100644
--- a/sysdeps/aarch64/memcpy.S
+++ b/sysdeps/aarch64/memcpy.S
@@ -1,4 +1,5 @@
-/* Copyright (C) 2012-2022 Free Software Foundation, Inc.
+/* Generic optimized memcpy using SIMD.
+   Copyright (C) 2012-2022 Free Software Foundation, Inc.
 
    This file is part of the GNU C Library.
 
@@ -20,7 +21,7 @@
 
 /* Assumptions:
  *
- * ARMv8-a, AArch64, unaligned accesses.
+ * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
  *
  */
 
@@ -36,21 +37,18 @@
 #define B_l	x8
 #define B_lw	w8
 #define B_h	x9
-#define C_l	x10
 #define C_lw	w10
-#define C_h	x11
-#define D_l	x12
-#define D_h	x13
-#define E_l	x14
-#define E_h	x15
-#define F_l	x16
-#define F_h	x17
-#define G_l	count
-#define G_h	dst
-#define H_l	src
-#define H_h	srcend
 #define tmp1	x14
 
+#define A_q	q0
+#define B_q	q1
+#define C_q	q2
+#define D_q	q3
+#define E_q	q4
+#define F_q	q5
+#define G_q	q6
+#define H_q	q7
+
 #ifndef MEMMOVE
 # define MEMMOVE memmove
 #endif
@@ -69,10 +67,9 @@
    Large copies use a software pipelined loop processing 64 bytes per
    iteration.  The destination pointer is 16-byte aligned to minimize
    unaligned accesses.  The loop tail is handled by always copying 64 bytes
-   from the end.
-*/
+   from the end.  */
 
-ENTRY_ALIGN (MEMCPY, 6)
+ENTRY (MEMCPY)
 	PTR_ARG (0)
 	PTR_ARG (1)
 	SIZE_ARG (2)
@@ -87,10 +84,10 @@ ENTRY_ALIGN (MEMCPY, 6)
 	/* Small copies: 0..32 bytes.  */
 	cmp	count, 16
 	b.lo	L(copy16)
-	ldp	A_l, A_h, [src]
-	ldp	D_l, D_h, [srcend, -16]
-	stp	A_l, A_h, [dstin]
-	stp	D_l, D_h, [dstend, -16]
+	ldr	A_q, [src]
+	ldr	B_q, [srcend, -16]
+	str	A_q, [dstin]
+	str	B_q, [dstend, -16]
 	ret
 
 	/* Copy 8-15 bytes.  */
@@ -102,7 +99,6 @@ L(copy16):
 	str	A_h, [dstend, -8]
 	ret
 
-	.p2align 3
 	/* Copy 4-7 bytes.  */
 L(copy8):
 	tbz	count, 2, L(copy4)
@@ -128,87 +124,69 @@ L(copy0):
 	.p2align 4
 	/* Medium copies: 33..128 bytes.  */
 L(copy32_128):
-	ldp	A_l, A_h, [src]
-	ldp	B_l, B_h, [src, 16]
-	ldp	C_l, C_h, [srcend, -32]
-	ldp	D_l, D_h, [srcend, -16]
+	ldp	A_q, B_q, [src]
+	ldp	C_q, D_q, [srcend, -32]
 	cmp	count, 64
 	b.hi	L(copy128)
-	stp	A_l, A_h, [dstin]
-	stp	B_l, B_h, [dstin, 16]
-	stp	C_l, C_h, [dstend, -32]
-	stp	D_l, D_h, [dstend, -16]
+	stp	A_q, B_q, [dstin]
+	stp	C_q, D_q, [dstend, -32]
 	ret
 
 	.p2align 4
 	/* Copy 65..128 bytes.  */
 L(copy128):
-	ldp	E_l, E_h, [src, 32]
-	ldp	F_l, F_h, [src, 48]
+	ldp	E_q, F_q, [src, 32]
 	cmp	count, 96
 	b.ls	L(copy96)
-	ldp	G_l, G_h, [srcend, -64]
-	ldp	H_l, H_h, [srcend, -48]
-	stp	G_l, G_h, [dstend, -64]
-	stp	H_l, H_h, [dstend, -48]
+	ldp	G_q, H_q, [srcend, -64]
+	stp	G_q, H_q, [dstend, -64]
 L(copy96):
-	stp	A_l, A_h, [dstin]
-	stp	B_l, B_h, [dstin, 16]
-	stp	E_l, E_h, [dstin, 32]
-	stp	F_l, F_h, [dstin, 48]
-	stp	C_l, C_h, [dstend, -32]
-	stp	D_l, D_h, [dstend, -16]
+	stp	A_q, B_q, [dstin]
+	stp	E_q, F_q, [dstin, 32]
+	stp	C_q, D_q, [dstend, -32]
 	ret
 
-	.p2align 4
+	/* Align loop64 below to 16 bytes.  */
+	nop
+
 	/* Copy more than 128 bytes.  */
 L(copy_long):
-	/* Copy 16 bytes and then align dst to 16-byte alignment.  */
-	ldp	D_l, D_h, [src]
-	and	tmp1, dstin, 15
-	bic	dst, dstin, 15
-	sub	src, src, tmp1
+	/* Copy 16 bytes and then align src to 16-byte alignment.  */
+	ldr	D_q, [src]
+	and	tmp1, src, 15
+	bic	src, src, 15
+	sub	dst, dstin, tmp1
 	add	count, count, tmp1	/* Count is now 16 too large.  */
-	ldp	A_l, A_h, [src, 16]
-	stp	D_l, D_h, [dstin]
-	ldp	B_l, B_h, [src, 32]
-	ldp	C_l, C_h, [src, 48]
-	ldp	D_l, D_h, [src, 64]!
+	ldp	A_q, B_q, [src, 16]
+	str	D_q, [dstin]
+	ldp	C_q, D_q, [src, 48]
 	subs	count, count, 128 + 16	/* Test and readjust count.  */
 	b.ls	L(copy64_from_end)
-
 L(loop64):
-	stp	A_l, A_h, [dst, 16]
-	ldp	A_l, A_h, [src, 16]
-	stp	B_l, B_h, [dst, 32]
-	ldp	B_l, B_h, [src, 32]
-	stp	C_l, C_h, [dst, 48]
-	ldp	C_l, C_h, [src, 48]
-	stp	D_l, D_h, [dst, 64]!
-	ldp	D_l, D_h, [src, 64]!
+	stp	A_q, B_q, [dst, 16]
+	ldp	A_q, B_q, [src, 80]
+	stp	C_q, D_q, [dst, 48]
+	ldp	C_q, D_q, [src, 112]
+	add	src, src, 64
+	add	dst, dst, 64
 	subs	count, count, 64
 	b.hi	L(loop64)
 
 	/* Write the last iteration and copy 64 bytes from the end.  */
 L(copy64_from_end):
-	ldp	E_l, E_h, [srcend, -64]
-	stp	A_l, A_h, [dst, 16]
-	ldp	A_l, A_h, [srcend, -48]
-	stp	B_l, B_h, [dst, 32]
-	ldp	B_l, B_h, [srcend, -32]
-	stp	C_l, C_h, [dst, 48]
-	ldp	C_l, C_h, [srcend, -16]
-	stp	D_l, D_h, [dst, 64]
-	stp	E_l, E_h, [dstend, -64]
-	stp	A_l, A_h, [dstend, -48]
-	stp	B_l, B_h, [dstend, -32]
-	stp	C_l, C_h, [dstend, -16]
+	ldp	E_q, F_q, [srcend, -64]
+	stp	A_q, B_q, [dst, 16]
+	ldp	A_q, B_q, [srcend, -32]
+	stp	C_q, D_q, [dst, 48]
+	stp	E_q, F_q, [dstend, -64]
+	stp	A_q, B_q, [dstend, -32]
 	ret
 
 END (MEMCPY)
 libc_hidden_builtin_def (MEMCPY)
 
-ENTRY_ALIGN (MEMMOVE, 4)
+
+ENTRY (MEMMOVE)
 	PTR_ARG (0)
 	PTR_ARG (1)
 	SIZE_ARG (2)
@@ -220,64 +198,56 @@ ENTRY_ALIGN (MEMMOVE, 4)
 	cmp	count, 32
 	b.hi	L(copy32_128)
 
-	/* Small copies: 0..32 bytes.  */
+	/* Small moves: 0..32 bytes.  */
 	cmp	count, 16
 	b.lo	L(copy16)
-	ldp	A_l, A_h, [src]
-	ldp	D_l, D_h, [srcend, -16]
-	stp	A_l, A_h, [dstin]
-	stp	D_l, D_h, [dstend, -16]
+	ldr	A_q, [src]
+	ldr	B_q, [srcend, -16]
+	str	A_q, [dstin]
+	str	B_q, [dstend, -16]
 	ret
 
-	.p2align 4
 L(move_long):
 	/* Only use backward copy if there is an overlap.  */
 	sub	tmp1, dstin, src
-	cbz	tmp1, L(copy0)
+	cbz	tmp1, L(move0)
 	cmp	tmp1, count
 	b.hs	L(copy_long)
 
 	/* Large backwards copy for overlapping copies.
-	   Copy 16 bytes and then align dst to 16-byte alignment.  */
-	ldp	D_l, D_h, [srcend, -16]
-	and	tmp1, dstend, 15
-	sub	srcend, srcend, tmp1
+	   Copy 16 bytes and then align srcend to 16-byte alignment.  */
+L(copy_long_backwards):
+	ldr	D_q, [srcend, -16]
+	and	tmp1, srcend, 15
+	bic	srcend, srcend, 15
 	sub	count, count, tmp1
-	ldp	A_l, A_h, [srcend, -16]
-	stp	D_l, D_h, [dstend, -16]
-	ldp	B_l, B_h, [srcend, -32]
-	ldp	C_l, C_h, [srcend, -48]
-	ldp	D_l, D_h, [srcend, -64]!
+	ldp	A_q, B_q, [srcend, -32]
+	str	D_q, [dstend, -16]
+	ldp	C_q, D_q, [srcend, -64]
 	sub	dstend, dstend, tmp1
 	subs	count, count, 128
 	b.ls	L(copy64_from_start)
 
 L(loop64_backwards):
-	stp	A_l, A_h, [dstend, -16]
-	ldp	A_l, A_h, [srcend, -16]
-	stp	B_l, B_h, [dstend, -32]
-	ldp	B_l, B_h, [srcend, -32]
-	stp	C_l, C_h, [dstend, -48]
-	ldp	C_l, C_h, [srcend, -48]
-	stp	D_l, D_h, [dstend, -64]!
-	ldp	D_l, D_h, [srcend, -64]!
+	str	B_q, [dstend, -16]
+	str	A_q, [dstend, -32]
+	ldp	A_q, B_q, [srcend, -96]
+	str	D_q, [dstend, -48]
+	str	C_q, [dstend, -64]!
+	ldp	C_q, D_q, [srcend, -128]
+	sub	srcend, srcend, 64
 	subs	count, count, 64
 	b.hi	L(loop64_backwards)
 
 	/* Write the last iteration and copy 64 bytes from the start.  */
 L(copy64_from_start):
-	ldp	G_l, G_h, [src, 48]
-	stp	A_l, A_h, [dstend, -16]
-	ldp	A_l, A_h, [src, 32]
-	stp	B_l, B_h, [dstend, -32]
-	ldp	B_l, B_h, [src, 16]
-	stp	C_l, C_h, [dstend, -48]
-	ldp	C_l, C_h, [src]
-	stp	D_l, D_h, [dstend, -64]
-	stp	G_l, G_h, [dstin, 48]
-	stp	A_l, A_h, [dstin, 32]
-	stp	B_l, B_h, [dstin, 16]
-	stp	C_l, C_h, [dstin]
+	ldp	E_q, F_q, [src, 32]
+	stp	A_q, B_q, [dstend, -32]
+	ldp	A_q, B_q, [src]
+	stp	C_q, D_q, [dstend, -64]
+	stp	E_q, F_q, [dstin, 32]
+	stp	A_q, B_q, [dstin]
+L(move0):
 	ret
 
 END (MEMMOVE)
diff --git a/sysdeps/aarch64/memrchr.S b/sysdeps/aarch64/memrchr.S
index 5179320720..428af51f70 100644
--- a/sysdeps/aarch64/memrchr.S
+++ b/sysdeps/aarch64/memrchr.S
@@ -26,7 +26,6 @@
  * MTE compatible.
  */
 
-/* Arguments and results.  */
 #define srcin		x0
 #define chrin		w1
 #define cntin		x2
@@ -77,31 +76,34 @@ ENTRY (__memrchr)
 	csel	result, result, xzr, hi
 	ret
 
+	nop
 L(start_loop):
-	sub	tmp, end, src
-	subs	cntrem, cntin, tmp
+	subs	cntrem, src, srcin
 	b.ls	L(nomatch)
 
 	/* Make sure that it won't overread by a 16-byte chunk */
-	add	tmp, cntrem, 15
-	tbnz	tmp, 4, L(loop32_2)
+	sub	cntrem, cntrem, 1
+	tbz	cntrem, 4, L(loop32_2)
+	add	src, src, 16
 
-	.p2align 4
+	.p2align 5
 L(loop32):
-	ldr	qdata, [src, -16]!
+	ldr	qdata, [src, -32]!
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
 	fmov	synd, dend
 	cbnz	synd, L(end)
 
 L(loop32_2):
-	ldr	qdata, [src, -16]!
+	ldr	qdata, [src, -16]
 	subs	cntrem, cntrem, 32
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
-	b.ls	L(end)
+	b.lo	L(end_2)
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
 	fmov	synd, dend
 	cbz	synd, L(loop32)
+L(end_2):
+	sub	src, src, 16
 L(end):
 	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
 	fmov	synd, dend
diff --git a/sysdeps/aarch64/memset.S b/sysdeps/aarch64/memset.S
index 957996bd19..71814d0b2f 100644
--- a/sysdeps/aarch64/memset.S
+++ b/sysdeps/aarch64/memset.S
@@ -1,4 +1,5 @@
-/* Copyright (C) 2012-2022 Free Software Foundation, Inc.
+/* Generic optimized memset using SIMD.
+   Copyright (C) 2012-2024 Free Software Foundation, Inc.
 
    This file is part of the GNU C Library.
 
@@ -17,7 +18,6 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
-#include "memset-reg.h"
 
 #ifndef MEMSET
 # define MEMSET memset
@@ -25,167 +25,117 @@
 
 /* Assumptions:
  *
- * ARMv8-a, AArch64, unaligned accesses
+ * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
  *
  */
 
-ENTRY_ALIGN (MEMSET, 6)
-
+#define dstin	x0
+#define val	x1
+#define valw	w1
+#define count	x2
+#define dst	x3
+#define dstend	x4
+#define zva_val	x5
+#define off	x3
+#define dstend2	x5
+
+ENTRY (MEMSET)
 	PTR_ARG (0)
 	SIZE_ARG (2)
 
 	dup	v0.16B, valw
+	cmp	count, 16
+	b.lo	L(set_small)
+
 	add	dstend, dstin, count
+	cmp	count, 64
+	b.hs	L(set_128)
 
-	cmp	count, 96
-	b.hi	L(set_long)
-	cmp	count, 16
-	b.hs	L(set_medium)
-	mov	val, v0.D[0]
+	/* Set 16..63 bytes.  */
+	mov	off, 16
+	and	off, off, count, lsr 1
+	sub	dstend2, dstend, off
+	str	q0, [dstin]
+	str	q0, [dstin, off]
+	str	q0, [dstend2, -16]
+	str	q0, [dstend, -16]
+	ret
 
+	.p2align 4
 	/* Set 0..15 bytes.  */
-	tbz	count, 3, 1f
-	str	val, [dstin]
-	str	val, [dstend, -8]
-	ret
-	nop
-1:	tbz	count, 2, 2f
-	str	valw, [dstin]
-	str	valw, [dstend, -4]
+L(set_small):
+	add	dstend, dstin, count
+	cmp	count, 4
+	b.lo	2f
+	lsr	off, count, 3
+	sub	dstend2, dstend, off, lsl 2
+	str	s0, [dstin]
+	str	s0, [dstin, off, lsl 2]
+	str	s0, [dstend2, -4]
+	str	s0, [dstend, -4]
 	ret
+
+	/* Set 0..3 bytes.  */
 2:	cbz	count, 3f
+	lsr	off, count, 1
 	strb	valw, [dstin]
-	tbz	count, 1, 3f
-	strh	valw, [dstend, -2]
+	strb	valw, [dstin, off]
+	strb	valw, [dstend, -1]
 3:	ret
 
-	/* Set 17..96 bytes.  */
-L(set_medium):
-	str	q0, [dstin]
-	tbnz	count, 6, L(set96)
-	str	q0, [dstend, -16]
-	tbz	count, 5, 1f
-	str	q0, [dstin, 16]
-	str	q0, [dstend, -32]
-1:	ret
-
 	.p2align 4
-	/* Set 64..96 bytes.  Write 64 bytes from the start and
-	   32 bytes from the end.  */
-L(set96):
-	str	q0, [dstin, 16]
+L(set_128):
+	bic	dst, dstin, 15
+	cmp	count, 128
+	b.hi	L(set_long)
+	stp	q0, q0, [dstin]
 	stp	q0, q0, [dstin, 32]
+	stp	q0, q0, [dstend, -64]
 	stp	q0, q0, [dstend, -32]
 	ret
 
-	.p2align 3
-	nop
+	.p2align 4
 L(set_long):
-	and	valw, valw, 255
-	bic	dst, dstin, 15
 	str	q0, [dstin]
-	cmp	count, 256
-	ccmp	valw, 0, 0, cs
-	b.eq	L(try_zva)
-L(no_zva):
-	sub	count, dstend, dst	/* Count is 16 too large.  */
-	sub	dst, dst, 16		/* Dst is biased by -32.  */
-	sub	count, count, 64 + 16	/* Adjust count and bias for loop.  */
-1:	stp	q0, q0, [dst, 32]
-	stp	q0, q0, [dst, 64]!
-L(tail64):
-	subs	count, count, 64
-	b.hi	1b
-2:	stp	q0, q0, [dstend, -64]
-	stp	q0, q0, [dstend, -32]
-	ret
-
-L(try_zva):
-#ifdef ZVA_MACRO
-	zva_macro
-#else
-	.p2align 3
-	mrs	tmp1, dczid_el0
-	tbnz	tmp1w, 4, L(no_zva)
-	and	tmp1w, tmp1w, 15
-	cmp	tmp1w, 4	/* ZVA size is 64 bytes.  */
-	b.ne	 L(zva_128)
-
-	/* Write the first and last 64 byte aligned block using stp rather
-	   than using DC ZVA.  This is faster on some cores.
-	 */
-L(zva_64):
 	str	q0, [dst, 16]
+	tst	valw, 255
+	b.ne	L(no_zva)
+#ifndef ZVA64_ONLY
+	mrs	zva_val, dczid_el0
+	and	zva_val, zva_val, 31
+	cmp	zva_val, 4		/* ZVA size is 64 bytes.  */
+	b.ne	L(no_zva)
+#endif
 	stp	q0, q0, [dst, 32]
-	bic	dst, dst, 63
-	stp	q0, q0, [dst, 64]
-	stp	q0, q0, [dst, 96]
-	sub	count, dstend, dst	/* Count is now 128 too large.	*/
-	sub	count, count, 128+64+64	/* Adjust count and bias for loop.  */
-	add	dst, dst, 128
-	nop
-1:	dc	zva, dst
-	add	dst, dst, 64
-	subs	count, count, 64
-	b.hi	1b
-	stp	q0, q0, [dst, 0]
-	stp	q0, q0, [dst, 32]
+	bic	dst, dstin, 63
+	sub	count, dstend, dst	/* Count is now 64 too large.  */
+	sub	count, count, 64 + 64	/* Adjust count and bias for loop.  */
+
+	/* Write last bytes before ZVA loop.  */
 	stp	q0, q0, [dstend, -64]
 	stp	q0, q0, [dstend, -32]
+
+	.p2align 4
+L(zva64_loop):
+	add	dst, dst, 64
+	dc	zva, dst
+	subs	count, count, 64
+	b.hi	L(zva64_loop)
 	ret
 
 	.p2align 3
-L(zva_128):
-	cmp	tmp1w, 5	/* ZVA size is 128 bytes.  */
-	b.ne	L(zva_other)
-
-	str	q0, [dst, 16]
+L(no_zva):
+	sub	count, dstend, dst	/* Count is 32 too large.  */
+	sub	count, count, 64 + 32	/* Adjust count and bias for loop.  */
+L(no_zva_loop):
 	stp	q0, q0, [dst, 32]
 	stp	q0, q0, [dst, 64]
-	stp	q0, q0, [dst, 96]
-	bic	dst, dst, 127
-	sub	count, dstend, dst	/* Count is now 128 too large.	*/
-	sub	count, count, 128+128	/* Adjust count and bias for loop.  */
-	add	dst, dst, 128
-1:	dc	zva, dst
-	add	dst, dst, 128
-	subs	count, count, 128
-	b.hi	1b
-	stp	q0, q0, [dstend, -128]
-	stp	q0, q0, [dstend, -96]
+	add	dst, dst, 64
+	subs	count, count, 64
+	b.hi	L(no_zva_loop)
 	stp	q0, q0, [dstend, -64]
 	stp	q0, q0, [dstend, -32]
 	ret
 
-L(zva_other):
-	mov	tmp2w, 4
-	lsl	zva_lenw, tmp2w, tmp1w
-	add	tmp1, zva_len, 64	/* Max alignment bytes written.	 */
-	cmp	count, tmp1
-	blo	L(no_zva)
-
-	sub	tmp2, zva_len, 1
-	add	tmp1, dst, zva_len
-	add	dst, dst, 16
-	subs	count, tmp1, dst	/* Actual alignment bytes to write.  */
-	bic	tmp1, tmp1, tmp2	/* Aligned dc zva start address.  */
-	beq	2f
-1:	stp	q0, q0, [dst], 64
-	stp	q0, q0, [dst, -32]
-	subs	count, count, 64
-	b.hi	1b
-2:	mov	dst, tmp1
-	sub	count, dstend, tmp1	/* Remaining bytes to write.  */
-	subs	count, count, zva_len
-	b.lo	4f
-3:	dc	zva, dst
-	add	dst, dst, zva_len
-	subs	count, count, zva_len
-	b.hs	3b
-4:	add	count, count, zva_len
-	sub	dst, dst, 32		/* Bias dst for tail loop.  */
-	b	L(tail64)
-#endif
-
 END (MEMSET)
 libc_hidden_builtin_def (MEMSET)
diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
index 16297192ee..214b6137b0 100644
--- a/sysdeps/aarch64/multiarch/Makefile
+++ b/sysdeps/aarch64/multiarch/Makefile
@@ -3,18 +3,20 @@ sysdep_routines += \
   memchr_generic \
   memchr_nosimd \
   memcpy_a64fx \
-  memcpy_advsimd \
-  memcpy_falkor \
   memcpy_generic \
+  memcpy_mops \
   memcpy_sve \
   memcpy_thunderx \
   memcpy_thunderx2 \
+  memmove_mops \
   memset_a64fx \
   memset_emag \
-  memset_falkor \
   memset_generic \
   memset_kunpeng \
+  memset_mops \
+  memset_sve_zva64 \
+  memset_zva64 \
   strlen_asimd \
-  strlen_mte \
+  strlen_generic \
 # sysdep_routines
 endif
diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
index 4144615ab2..7ec82150ca 100644
--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
@@ -36,32 +36,30 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, memcpy,
 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
 	      IFUNC_IMPL_ADD (array, i, memcpy, !bti, __memcpy_thunderx2)
-	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor)
-	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_simd)
 #if HAVE_AARCH64_SVE_ASM
 	      IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx)
 	      IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve)
 #endif
+	      IFUNC_IMPL_ADD (array, i, memcpy, mops, __memcpy_mops)
 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
   IFUNC_IMPL (i, name, memmove,
 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
 	      IFUNC_IMPL_ADD (array, i, memmove, !bti, __memmove_thunderx2)
-	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
-	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_simd)
 #if HAVE_AARCH64_SVE_ASM
 	      IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx)
 	      IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_sve)
 #endif
+	      IFUNC_IMPL_ADD (array, i, memmove, mops, __memmove_mops)
 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
   IFUNC_IMPL (i, name, memset,
-	      /* Enable this on non-falkor processors too so that other cores
-		 can do a comparative analysis with __memset_generic.  */
-	      IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_falkor)
-	      IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_emag)
+	      IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_zva64)
+	      IFUNC_IMPL_ADD (array, i, memset, 1, __memset_emag)
 	      IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng)
 #if HAVE_AARCH64_SVE_ASM
-	      IFUNC_IMPL_ADD (array, i, memset, sve, __memset_a64fx)
+	      IFUNC_IMPL_ADD (array, i, memset, sve && !bti && zva_size == 256, __memset_a64fx)
+	      IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 64, __memset_sve_zva64)
 #endif
+	      IFUNC_IMPL_ADD (array, i, memset, mops, __memset_mops)
 	      IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic))
   IFUNC_IMPL (i, name, memchr,
 	      IFUNC_IMPL_ADD (array, i, memchr, !mte, __memchr_nosimd)
@@ -69,7 +67,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 
   IFUNC_IMPL (i, name, strlen,
 	      IFUNC_IMPL_ADD (array, i, strlen, !mte, __strlen_asimd)
-	      IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_mte))
+	      IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic))
 
   return 0;
 }
diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h
index a4dcac0019..5b2cf5cb12 100644
--- a/sysdeps/aarch64/multiarch/init-arch.h
+++ b/sysdeps/aarch64/multiarch/init-arch.h
@@ -35,4 +35,8 @@
   bool __attribute__((unused)) mte =					      \
     MTE_ENABLED ();							      \
   bool __attribute__((unused)) sve =					      \
-    GLRO(dl_aarch64_cpu_features).sve;
+    GLRO(dl_aarch64_cpu_features).sve;					      \
+  bool __attribute__((unused)) prefer_sve_ifuncs =			      \
+    GLRO(dl_aarch64_cpu_features).prefer_sve_ifuncs;			      \
+  bool __attribute__((unused)) mops =					      \
+    GLRO(dl_aarch64_cpu_features).mops;
diff --git a/sysdeps/aarch64/multiarch/memchr_nosimd.S b/sysdeps/aarch64/multiarch/memchr_nosimd.S
index ddf7533943..e39f39e6b3 100644
--- a/sysdeps/aarch64/multiarch/memchr_nosimd.S
+++ b/sysdeps/aarch64/multiarch/memchr_nosimd.S
@@ -26,10 +26,6 @@
  * Use base integer registers.
  */
 
-#ifndef MEMCHR
-# define MEMCHR __memchr_nosimd
-#endif
-
 /* Arguments and results.  */
 #define srcin		x0
 #define chrin		x1
@@ -62,7 +58,7 @@
 #define REP8_7f		0x7f7f7f7f7f7f7f7f
 
 
-ENTRY_ALIGN (MEMCHR, 6)
+ENTRY (__memchr_nosimd)
 
 	PTR_ARG (0)
 	SIZE_ARG (2)
@@ -219,5 +215,4 @@ L(none_chr):
 	mov	result, 0
 	ret
 
-END (MEMCHR)
-libc_hidden_builtin_def (MEMCHR)
+END (__memchr_nosimd)
diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
index 0486213f08..3de66c14d4 100644
--- a/sysdeps/aarch64/multiarch/memcpy.c
+++ b/sysdeps/aarch64/multiarch/memcpy.c
@@ -29,26 +29,25 @@
 extern __typeof (__redirect_memcpy) __libc_memcpy;
 
 extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
-extern __typeof (__redirect_memcpy) __memcpy_simd attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden;
-extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_sve attribute_hidden;
+extern __typeof (__redirect_memcpy) __memcpy_mops attribute_hidden;
 
 static inline __typeof (__redirect_memcpy) *
 select_memcpy_ifunc (void)
 {
   INIT_ARCH ();
 
-  if (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr))
-    return __memcpy_simd;
+  if (mops)
+    return __memcpy_mops;
 
   if (sve && HAVE_AARCH64_SVE_ASM)
     {
       if (IS_A64FX (midr))
 	return __memcpy_a64fx;
-      return __memcpy_sve;
+      return prefer_sve_ifuncs ? __memcpy_sve : __memcpy_generic;
     }
 
   if (IS_THUNDERX (midr))
@@ -57,9 +56,6 @@ select_memcpy_ifunc (void)
   if (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr))
     return __memcpy_thunderx2;
 
-  if (IS_FALKOR (midr) || IS_PHECDA (midr))
-    return __memcpy_falkor;
-
   return __memcpy_generic;
 }
 
diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
index c4eab06176..c254dc8b9f 100644
--- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S
+++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S
@@ -39,9 +39,6 @@
 #define vlen8	x8
 
 #if HAVE_AARCH64_SVE_ASM
-# if IS_IN (libc)
-#  define MEMCPY __memcpy_a64fx
-#  define MEMMOVE __memmove_a64fx
 
 	.arch armv8.2-a+sve
 
@@ -97,7 +94,7 @@
 #undef BTI_C
 #define BTI_C
 
-ENTRY (MEMCPY)
+ENTRY (__memcpy_a64fx)
 
 	PTR_ARG (0)
 	PTR_ARG (1)
@@ -234,11 +231,10 @@ L(last_bytes):
 	st1b	z3.b, p0, [dstend, -1, mul vl]
 	ret
 
-END (MEMCPY)
-libc_hidden_builtin_def (MEMCPY)
+END (__memcpy_a64fx)
 
 
-ENTRY_ALIGN (MEMMOVE, 4)
+ENTRY_ALIGN (__memmove_a64fx, 4)
 
 	PTR_ARG (0)
 	PTR_ARG (1)
@@ -307,7 +303,5 @@ L(full_overlap):
 	mov	dst, dstin
 	b	L(last_bytes)
 
-END (MEMMOVE)
-libc_hidden_builtin_def (MEMMOVE)
-# endif /* IS_IN (libc) */
+END (__memmove_a64fx)
 #endif /* HAVE_AARCH64_SVE_ASM */
diff --git a/sysdeps/aarch64/multiarch/memcpy_advsimd.S b/sysdeps/aarch64/multiarch/memcpy_advsimd.S
deleted file mode 100644
index fe9beaf5ea..0000000000
--- a/sysdeps/aarch64/multiarch/memcpy_advsimd.S
+++ /dev/null
@@ -1,248 +0,0 @@
-/* Generic optimized memcpy using SIMD.
-   Copyright (C) 2020-2022 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>
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
- *
- */
-
-#define dstin	x0
-#define src	x1
-#define count	x2
-#define dst	x3
-#define srcend	x4
-#define dstend	x5
-#define A_l	x6
-#define A_lw	w6
-#define A_h	x7
-#define B_l	x8
-#define B_lw	w8
-#define B_h	x9
-#define C_lw	w10
-#define tmp1	x14
-
-#define A_q	q0
-#define B_q	q1
-#define C_q	q2
-#define D_q	q3
-#define E_q	q4
-#define F_q	q5
-#define G_q	q6
-#define H_q	q7
-
-
-/* This implementation supports both memcpy and memmove and shares most code.
-   It uses unaligned accesses and branchless sequences to keep the code small,
-   simple and improve performance.
-
-   Copies are split into 3 main cases: small copies of up to 32 bytes, medium
-   copies of up to 128 bytes, and large copies.  The overhead of the overlap
-   check in memmove is negligible since it is only required for large copies.
-
-   Large copies use a software pipelined loop processing 64 bytes per
-   iteration.  The destination pointer is 16-byte aligned to minimize
-   unaligned accesses.  The loop tail is handled by always copying 64 bytes
-   from the end.  */
-
-ENTRY (__memcpy_simd)
-	PTR_ARG (0)
-	PTR_ARG (1)
-	SIZE_ARG (2)
-
-	add	srcend, src, count
-	add	dstend, dstin, count
-	cmp	count, 128
-	b.hi	L(copy_long)
-	cmp	count, 32
-	b.hi	L(copy32_128)
-
-	/* Small copies: 0..32 bytes.  */
-	cmp	count, 16
-	b.lo	L(copy16)
-	ldr	A_q, [src]
-	ldr	B_q, [srcend, -16]
-	str	A_q, [dstin]
-	str	B_q, [dstend, -16]
-	ret
-
-	/* Copy 8-15 bytes.  */
-L(copy16):
-	tbz	count, 3, L(copy8)
-	ldr	A_l, [src]
-	ldr	A_h, [srcend, -8]
-	str	A_l, [dstin]
-	str	A_h, [dstend, -8]
-	ret
-
-	/* Copy 4-7 bytes.  */
-L(copy8):
-	tbz	count, 2, L(copy4)
-	ldr	A_lw, [src]
-	ldr	B_lw, [srcend, -4]
-	str	A_lw, [dstin]
-	str	B_lw, [dstend, -4]
-	ret
-
-	/* Copy 0..3 bytes using a branchless sequence.  */
-L(copy4):
-	cbz	count, L(copy0)
-	lsr	tmp1, count, 1
-	ldrb	A_lw, [src]
-	ldrb	C_lw, [srcend, -1]
-	ldrb	B_lw, [src, tmp1]
-	strb	A_lw, [dstin]
-	strb	B_lw, [dstin, tmp1]
-	strb	C_lw, [dstend, -1]
-L(copy0):
-	ret
-
-	.p2align 4
-	/* Medium copies: 33..128 bytes.  */
-L(copy32_128):
-	ldp	A_q, B_q, [src]
-	ldp	C_q, D_q, [srcend, -32]
-	cmp	count, 64
-	b.hi	L(copy128)
-	stp	A_q, B_q, [dstin]
-	stp	C_q, D_q, [dstend, -32]
-	ret
-
-	.p2align 4
-	/* Copy 65..128 bytes.  */
-L(copy128):
-	ldp	E_q, F_q, [src, 32]
-	cmp	count, 96
-	b.ls	L(copy96)
-	ldp	G_q, H_q, [srcend, -64]
-	stp	G_q, H_q, [dstend, -64]
-L(copy96):
-	stp	A_q, B_q, [dstin]
-	stp	E_q, F_q, [dstin, 32]
-	stp	C_q, D_q, [dstend, -32]
-	ret
-
-	/* Align loop64 below to 16 bytes.  */
-	nop
-
-	/* Copy more than 128 bytes.  */
-L(copy_long):
-	/* Copy 16 bytes and then align src to 16-byte alignment.  */
-	ldr	D_q, [src]
-	and	tmp1, src, 15
-	bic	src, src, 15
-	sub	dst, dstin, tmp1
-	add	count, count, tmp1	/* Count is now 16 too large.  */
-	ldp	A_q, B_q, [src, 16]
-	str	D_q, [dstin]
-	ldp	C_q, D_q, [src, 48]
-	subs	count, count, 128 + 16	/* Test and readjust count.  */
-	b.ls	L(copy64_from_end)
-L(loop64):
-	stp	A_q, B_q, [dst, 16]
-	ldp	A_q, B_q, [src, 80]
-	stp	C_q, D_q, [dst, 48]
-	ldp	C_q, D_q, [src, 112]
-	add	src, src, 64
-	add	dst, dst, 64
-	subs	count, count, 64
-	b.hi	L(loop64)
-
-	/* Write the last iteration and copy 64 bytes from the end.  */
-L(copy64_from_end):
-	ldp	E_q, F_q, [srcend, -64]
-	stp	A_q, B_q, [dst, 16]
-	ldp	A_q, B_q, [srcend, -32]
-	stp	C_q, D_q, [dst, 48]
-	stp	E_q, F_q, [dstend, -64]
-	stp	A_q, B_q, [dstend, -32]
-	ret
-
-END (__memcpy_simd)
-libc_hidden_builtin_def (__memcpy_simd)
-
-
-ENTRY (__memmove_simd)
-	PTR_ARG (0)
-	PTR_ARG (1)
-	SIZE_ARG (2)
-
-	add	srcend, src, count
-	add	dstend, dstin, count
-	cmp	count, 128
-	b.hi	L(move_long)
-	cmp	count, 32
-	b.hi	L(copy32_128)
-
-	/* Small moves: 0..32 bytes.  */
-	cmp	count, 16
-	b.lo	L(copy16)
-	ldr	A_q, [src]
-	ldr	B_q, [srcend, -16]
-	str	A_q, [dstin]
-	str	B_q, [dstend, -16]
-	ret
-
-L(move_long):
-	/* Only use backward copy if there is an overlap.  */
-	sub	tmp1, dstin, src
-	cbz	tmp1, L(move0)
-	cmp	tmp1, count
-	b.hs	L(copy_long)
-
-	/* Large backwards copy for overlapping copies.
-	   Copy 16 bytes and then align srcend to 16-byte alignment.  */
-L(copy_long_backwards):
-	ldr	D_q, [srcend, -16]
-	and	tmp1, srcend, 15
-	bic	srcend, srcend, 15
-	sub	count, count, tmp1
-	ldp	A_q, B_q, [srcend, -32]
-	str	D_q, [dstend, -16]
-	ldp	C_q, D_q, [srcend, -64]
-	sub	dstend, dstend, tmp1
-	subs	count, count, 128
-	b.ls	L(copy64_from_start)
-
-L(loop64_backwards):
-	str	B_q, [dstend, -16]
-	str	A_q, [dstend, -32]
-	ldp	A_q, B_q, [srcend, -96]
-	str	D_q, [dstend, -48]
-	str	C_q, [dstend, -64]!
-	ldp	C_q, D_q, [srcend, -128]
-	sub	srcend, srcend, 64
-	subs	count, count, 64
-	b.hi	L(loop64_backwards)
-
-	/* Write the last iteration and copy 64 bytes from the start.  */
-L(copy64_from_start):
-	ldp	E_q, F_q, [src, 32]
-	stp	A_q, B_q, [dstend, -32]
-	ldp	A_q, B_q, [src]
-	stp	C_q, D_q, [dstend, -64]
-	stp	E_q, F_q, [dstin, 32]
-	stp	A_q, B_q, [dstin]
-L(move0):
-	ret
-
-END (__memmove_simd)
-libc_hidden_builtin_def (__memmove_simd)
diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S
deleted file mode 100644
index 117edd9cfc..0000000000
--- a/sysdeps/aarch64/multiarch/memcpy_falkor.S
+++ /dev/null
@@ -1,315 +0,0 @@
-/* Optimized memcpy for Qualcomm Falkor processor.
-   Copyright (C) 2017-2022 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>
-
-/* Assumptions:
-
-   ARMv8-a, AArch64, falkor, unaligned accesses.  */
-
-#define dstin	x0
-#define src	x1
-#define count	x2
-#define dst	x3
-#define srcend	x4
-#define dstend	x5
-#define tmp1	x14
-#define A_x	x6
-#define B_x	x7
-#define A_w	w6
-#define B_w	w7
-
-#define A_q	q0
-#define B_q	q1
-#define C_q	q2
-#define D_q	q3
-#define E_q	q4
-#define F_q	q5
-#define G_q	q6
-#define H_q	q7
-#define Q_q	q6
-#define S_q	q22
-
-/* Copies are split into 3 main cases:
-
-   1. Small copies of up to 32 bytes
-   2. Medium copies of 33..128 bytes which are fully unrolled
-   3. Large copies of more than 128 bytes.
-
-   Large copies align the source to a quad word and use an unrolled loop
-   processing 64 bytes per iteration.
-
-   FALKOR-SPECIFIC DESIGN:
-
-   The smallest copies (32 bytes or less) focus on optimal pipeline usage,
-   which is why the redundant copies of 0-3 bytes have been replaced with
-   conditionals, since the former would unnecessarily break across multiple
-   issue groups.  The medium copy group has been enlarged to 128 bytes since
-   bumping up the small copies up to 32 bytes allows us to do that without
-   cost and also allows us to reduce the size of the prep code before loop64.
-
-   The copy loop uses only one register q0.  This is to ensure that all loads
-   hit a single hardware prefetcher which can get correctly trained to prefetch
-   a single stream.
-
-   The non-temporal stores help optimize cache utilization.  */
-
-#if IS_IN (libc)
-ENTRY_ALIGN (__memcpy_falkor, 6)
-
-	PTR_ARG (0)
-	PTR_ARG (1)
-	SIZE_ARG (2)
-
-	cmp	count, 32
-	add	srcend, src, count
-	add	dstend, dstin, count
-	b.ls	L(copy32)
-	cmp	count, 128
-	b.hi	L(copy_long)
-
-	/* Medium copies: 33..128 bytes.  */
-L(copy128):
-	sub	tmp1, count, 1
-	ldr	A_q, [src]
-	ldr	B_q, [src, 16]
-	ldr	C_q, [srcend, -32]
-	ldr	D_q, [srcend, -16]
-	tbz	tmp1, 6, 1f
-	ldr	E_q, [src, 32]
-	ldr	F_q, [src, 48]
-	ldr	G_q, [srcend, -64]
-	ldr	H_q, [srcend, -48]
-	str	G_q, [dstend, -64]
-	str	H_q, [dstend, -48]
-	str	E_q, [dstin, 32]
-	str	F_q, [dstin, 48]
-1:
-	str	A_q, [dstin]
-	str	B_q, [dstin, 16]
-	str	C_q, [dstend, -32]
-	str	D_q, [dstend, -16]
-	ret
-
-	.p2align 4
-	/* Small copies: 0..32 bytes.  */
-L(copy32):
-	/* 16-32 */
-	cmp	count, 16
-	b.lo	1f
-	ldr	A_q, [src]
-	ldr	B_q, [srcend, -16]
-	str	A_q, [dstin]
-	str	B_q, [dstend, -16]
-	ret
-	.p2align 4
-1:
-	/* 8-15 */
-	tbz	count, 3, 1f
-	ldr	A_x, [src]
-	ldr	B_x, [srcend, -8]
-	str	A_x, [dstin]
-	str	B_x, [dstend, -8]
-	ret
-	.p2align 4
-1:
-	/* 4-7 */
-	tbz	count, 2, 1f
-	ldr	A_w, [src]
-	ldr	B_w, [srcend, -4]
-	str	A_w, [dstin]
-	str	B_w, [dstend, -4]
-	ret
-	.p2align 4
-1:
-	/* 2-3 */
-	tbz	count, 1, 1f
-	ldrh	A_w, [src]
-	ldrh	B_w, [srcend, -2]
-	strh	A_w, [dstin]
-	strh	B_w, [dstend, -2]
-	ret
-	.p2align 4
-1:
-	/* 0-1 */
-	tbz	count, 0, 1f
-	ldrb	A_w, [src]
-	strb	A_w, [dstin]
-1:
-	ret
-
-	/* Align SRC to 16 bytes and copy; that way at least one of the
-	   accesses is aligned throughout the copy sequence.
-
-	   The count is off by 0 to 15 bytes, but this is OK because we trim
-	   off the last 64 bytes to copy off from the end.  Due to this the
-	   loop never runs out of bounds.  */
-
-	.p2align 4
-	nop		/* Align loop64 below.  */
-L(copy_long):
-	ldr	A_q, [src]
-	sub	count, count, 64 + 16
-	and	tmp1, src, 15
-	str	A_q, [dstin]
-	bic	src, src, 15
-	sub	dst, dstin, tmp1
-	add	count, count, tmp1
-
-L(loop64):
-	ldr	A_q, [src, 16]!
-	str	A_q, [dst, 16]
-	ldr	A_q, [src, 16]!
-	subs	count, count, 64
-	str	A_q, [dst, 32]
-	ldr	A_q, [src, 16]!
-	str	A_q, [dst, 48]
-	ldr	A_q, [src, 16]!
-	str	A_q, [dst, 64]!
-	b.hi	L(loop64)
-
-	/* Write the last full set of 64 bytes.  The remainder is at most 64
-	   bytes, so it is safe to always copy 64 bytes from the end even if
-	   there is just 1 byte left.  */
-	ldr	E_q, [srcend, -64]
-	str	E_q, [dstend, -64]
-	ldr	D_q, [srcend, -48]
-	str	D_q, [dstend, -48]
-	ldr	C_q, [srcend, -32]
-	str	C_q, [dstend, -32]
-	ldr	B_q, [srcend, -16]
-	str	B_q, [dstend, -16]
-	ret
-
-END (__memcpy_falkor)
-libc_hidden_builtin_def (__memcpy_falkor)
-
-
-/* RATIONALE:
-
-   The move has 4 distinct parts:
-   * Small moves of 32 bytes and under.
-   * Medium sized moves of 33-128 bytes (fully unrolled).
-   * Large moves where the source address is higher than the destination
-     (forward copies)
-   * Large moves where the destination address is higher than the source
-     (copy backward, or move).
-
-   We use only two registers q6 and q22 for the moves and move 32 bytes at a
-   time to correctly train the hardware prefetcher for better throughput.
-
-   For small and medium cases memcpy is used.  */
-
-ENTRY_ALIGN (__memmove_falkor, 6)
-
-	PTR_ARG (0)
-	PTR_ARG (1)
-	SIZE_ARG (2)
-
-	cmp	count, 32
-	add	srcend, src, count
-	add	dstend, dstin, count
-	b.ls	L(copy32)
-	cmp	count, 128
-	b.ls	L(copy128)
-	sub	tmp1, dstin, src
-	ccmp	tmp1, count, 2, hi
-	b.lo	L(move_long)
-
-	/* CASE: Copy Forwards
-
-	   Align src to 16 byte alignment so that we don't cross cache line
-	   boundaries on both loads and stores.  There are at least 128 bytes
-	   to copy, so copy 16 bytes unaligned and then align.  The loop
-	   copies 32 bytes per iteration and prefetches one iteration ahead.  */
-
-	ldr	S_q, [src]
-	and	tmp1, src, 15
-	bic	src, src, 15
-	sub	dst, dstin, tmp1
-	add	count, count, tmp1	/* Count is now 16 too large.  */
-	ldr	Q_q, [src, 16]!
-	str	S_q, [dstin]
-	ldr	S_q, [src, 16]!
-	sub	count, count, 32 + 32 + 16	/* Test and readjust count.  */
-
-	.p2align 4
-1:
-	subs	count, count, 32
-	str	Q_q, [dst, 16]
-	ldr	Q_q, [src, 16]!
-	str	S_q, [dst, 32]!
-	ldr	S_q, [src, 16]!
-	b.hi	1b
-
-	/* Copy 32 bytes from the end before writing the data prefetched in the
-	   last loop iteration.  */
-2:
-	ldr	B_q, [srcend, -32]
-	ldr	C_q, [srcend, -16]
-	str	Q_q, [dst, 16]
-	str	S_q, [dst, 32]
-	str	B_q, [dstend, -32]
-	str	C_q, [dstend, -16]
-	ret
-
-	/* CASE: Copy Backwards
-
-	   Align srcend to 16 byte alignment so that we don't cross cache line
-	   boundaries on both loads and stores.  There are at least 128 bytes
-	   to copy, so copy 16 bytes unaligned and then align.  The loop
-	   copies 32 bytes per iteration and prefetches one iteration ahead.  */
-
-	.p2align 4
-	nop
-	nop
-L(move_long):
-	cbz	tmp1, 3f  /* Return early if src == dstin */
-	ldr	S_q, [srcend, -16]
-	and	tmp1, srcend, 15
-	sub	srcend, srcend, tmp1
-	ldr	Q_q, [srcend, -16]!
-	str	S_q, [dstend, -16]
-	sub	count, count, tmp1
-	ldr	S_q, [srcend, -16]!
-	sub	dstend, dstend, tmp1
-	sub	count, count, 32 + 32
-
-1:
-	subs	count, count, 32
-	str	Q_q, [dstend, -16]
-	ldr	Q_q, [srcend, -16]!
-	str	S_q, [dstend, -32]!
-	ldr	S_q, [srcend, -16]!
-	b.hi	1b
-
-	/* Copy 32 bytes from the start before writing the data prefetched in the
-	   last loop iteration.  */
-
-	ldr	B_q, [src, 16]
-	ldr	C_q, [src]
-	str	Q_q, [dstend, -16]
-	str	S_q, [dstend, -32]
-	str	B_q, [dstin, 16]
-	str	C_q, [dstin]
-3:	ret
-
-END (__memmove_falkor)
-libc_hidden_builtin_def (__memmove_falkor)
-#endif
diff --git a/sysdeps/aarch64/multiarch/memcpy_mops.S b/sysdeps/aarch64/multiarch/memcpy_mops.S
new file mode 100644
index 0000000000..4685629664
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memcpy_mops.S
@@ -0,0 +1,39 @@
+/* Optimized memcpy for MOPS.
+   Copyright (C) 2023 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>
+
+/* Assumptions:
+ *
+ * AArch64, MOPS.
+ *
+ */
+
+ENTRY (__memcpy_mops)
+	PTR_ARG (0)
+	PTR_ARG (1)
+	SIZE_ARG (2)
+
+	mov	x3, x0
+	.inst	0x19010443	/* cpyfp   [x3]!, [x1]!, x2!  */
+	.inst	0x19410443	/* cpyfm   [x3]!, [x1]!, x2!  */
+	.inst	0x19810443	/* cpyfe   [x3]!, [x1]!, x2!  */
+	ret
+
+END (__memcpy_mops)
diff --git a/sysdeps/aarch64/multiarch/memcpy_sve.S b/sysdeps/aarch64/multiarch/memcpy_sve.S
index a70907ec55..71d2f84f63 100644
--- a/sysdeps/aarch64/multiarch/memcpy_sve.S
+++ b/sysdeps/aarch64/multiarch/memcpy_sve.S
@@ -67,14 +67,15 @@ ENTRY (__memcpy_sve)
 
 	cmp	count, 128
 	b.hi	L(copy_long)
-	cmp	count, 32
+	cntb	vlen
+	cmp	count, vlen, lsl 1
 	b.hi	L(copy32_128)
-
 	whilelo p0.b, xzr, count
-	cntb	vlen
-	tbnz	vlen, 4, L(vlen128)
-	ld1b	z0.b, p0/z, [src]
-	st1b	z0.b, p0, [dstin]
+	whilelo p1.b, vlen, count
+	ld1b	z0.b, p0/z, [src, 0, mul vl]
+	ld1b	z1.b, p1/z, [src, 1, mul vl]
+	st1b	z0.b, p0, [dstin, 0, mul vl]
+	st1b	z1.b, p1, [dstin, 1, mul vl]
 	ret
 
 	/* Medium copies: 33..128 bytes.  */
@@ -102,14 +103,6 @@ L(copy96):
 	stp	C_q, D_q, [dstend, -32]
 	ret
 
-L(vlen128):
-	whilelo p1.b, vlen, count
-	ld1b	z0.b, p0/z, [src, 0, mul vl]
-	ld1b	z1.b, p1/z, [src, 1, mul vl]
-	st1b	z0.b, p0, [dstin, 0, mul vl]
-	st1b	z1.b, p1, [dstin, 1, mul vl]
-	ret
-
 	.p2align 4
 	/* Copy more than 128 bytes.  */
 L(copy_long):
@@ -148,7 +141,6 @@ L(copy64_from_end):
 	ret
 
 END (__memcpy_sve)
-libc_hidden_builtin_def (__memcpy_sve)
 
 
 ENTRY (__memmove_sve)
@@ -158,14 +150,15 @@ ENTRY (__memmove_sve)
 
 	cmp	count, 128
 	b.hi	L(move_long)
-	cmp	count, 32
+	cntb	vlen
+	cmp	count, vlen, lsl 1
 	b.hi	L(copy32_128)
-
 	whilelo p0.b, xzr, count
-	cntb	vlen
-	tbnz	vlen, 4, L(vlen128)
-	ld1b	z0.b, p0/z, [src]
-	st1b	z0.b, p0, [dstin]
+	whilelo p1.b, vlen, count
+	ld1b	z0.b, p0/z, [src, 0, mul vl]
+	ld1b	z1.b, p1/z, [src, 1, mul vl]
+	st1b	z0.b, p0, [dstin, 0, mul vl]
+	st1b	z1.b, p1, [dstin, 1, mul vl]
 	ret
 
 	.p2align 4
@@ -214,5 +207,4 @@ L(return):
 	ret
 
 END (__memmove_sve)
-libc_hidden_builtin_def (__memmove_sve)
 #endif
diff --git a/sysdeps/aarch64/multiarch/memcpy_thunderx.S b/sysdeps/aarch64/multiarch/memcpy_thunderx.S
index 21e703dddd..2fb6be5c78 100644
--- a/sysdeps/aarch64/multiarch/memcpy_thunderx.S
+++ b/sysdeps/aarch64/multiarch/memcpy_thunderx.S
@@ -65,21 +65,7 @@
    Overlapping large forward memmoves use a loop that copies backwards.
 */
 
-#ifndef MEMMOVE
-# define MEMMOVE memmove
-#endif
-#ifndef MEMCPY
-# define MEMCPY memcpy
-#endif
-
-#if IS_IN (libc)
-
-#  undef MEMCPY
-#  define MEMCPY __memcpy_thunderx
-#  undef MEMMOVE
-#  define MEMMOVE __memmove_thunderx
-
-ENTRY_ALIGN (MEMMOVE, 6)
+ENTRY (__memmove_thunderx)
 
 	PTR_ARG (0)
 	PTR_ARG (1)
@@ -91,9 +77,9 @@ ENTRY_ALIGN (MEMMOVE, 6)
 	b.lo	L(move_long)
 
 	/* Common case falls through into memcpy.  */
-END (MEMMOVE)
-libc_hidden_builtin_def (MEMMOVE)
-ENTRY (MEMCPY)
+END (__memmove_thunderx)
+
+ENTRY (__memcpy_thunderx)
 
 	PTR_ARG (0)
 	PTR_ARG (1)
@@ -316,7 +302,4 @@ L(move_long):
 	stp	C_l, C_h, [dstin]
 3:	ret
 
-END (MEMCPY)
-libc_hidden_builtin_def (MEMCPY)
-
-#endif
+END (__memcpy_thunderx)
diff --git a/sysdeps/aarch64/multiarch/memcpy_thunderx2.S b/sysdeps/aarch64/multiarch/memcpy_thunderx2.S
index 5e0a59ee5d..3fceb1036d 100644
--- a/sysdeps/aarch64/multiarch/memcpy_thunderx2.S
+++ b/sysdeps/aarch64/multiarch/memcpy_thunderx2.S
@@ -75,27 +75,12 @@
 #define I_v	v16
 #define J_v	v17
 
-#ifndef MEMMOVE
-# define MEMMOVE memmove
-#endif
-#ifndef MEMCPY
-# define MEMCPY memcpy
-#endif
-
-#if IS_IN (libc)
-
-#undef MEMCPY
-#define MEMCPY __memcpy_thunderx2
-#undef MEMMOVE
-#define MEMMOVE __memmove_thunderx2
-
-
 /* Overlapping large forward memmoves use a loop that copies backwards.
    Otherwise memcpy is used. Small moves branch to memcopy16 directly.
    The longer memcpy cases fall through to the memcpy head.
 */
 
-ENTRY_ALIGN (MEMMOVE, 6)
+ENTRY (__memmove_thunderx2)
 
 	PTR_ARG (0)
 	PTR_ARG (1)
@@ -109,8 +94,7 @@ ENTRY_ALIGN (MEMMOVE, 6)
 	ccmp	tmp1, count, 2, hi
 	b.lo	L(move_long)
 
-END (MEMMOVE)
-libc_hidden_builtin_def (MEMMOVE)
+END (__memmove_thunderx2)
 
 
 /* Copies are split into 3 main cases: small copies of up to 16 bytes,
@@ -124,8 +108,7 @@ libc_hidden_builtin_def (MEMMOVE)
 
 #define MEMCPY_PREFETCH_LDR 640
 
-	.p2align 4
-ENTRY (MEMCPY)
+ENTRY (__memcpy_thunderx2)
 
 	PTR_ARG (0)
 	PTR_ARG (1)
@@ -449,7 +432,7 @@ L(move_long):
 3:	ret
 
 
-END (MEMCPY)
+END (__memcpy_thunderx2)
 	.section	.rodata
 	.p2align	4
 
@@ -472,6 +455,3 @@ L(ext_table):
 	.word	L(ext_size_13) -.
 	.word	L(ext_size_14) -.
 	.word	L(ext_size_15) -.
-
-libc_hidden_builtin_def (MEMCPY)
-#endif
diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c
index 261996ecc4..fdcf418820 100644
--- a/sysdeps/aarch64/multiarch/memmove.c
+++ b/sysdeps/aarch64/multiarch/memmove.c
@@ -29,26 +29,25 @@
 extern __typeof (__redirect_memmove) __libc_memmove;
 
 extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
-extern __typeof (__redirect_memmove) __memmove_simd attribute_hidden;
 extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
 extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden;
-extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
 extern __typeof (__redirect_memmove) __memmove_a64fx attribute_hidden;
 extern __typeof (__redirect_memmove) __memmove_sve attribute_hidden;
+extern __typeof (__redirect_memmove) __memmove_mops attribute_hidden;
 
 static inline __typeof (__redirect_memmove) *
 select_memmove_ifunc (void)
 {
   INIT_ARCH ();
 
-  if (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr))
-    return __memmove_simd;
+  if (mops)
+    return __memmove_mops;
 
   if (sve && HAVE_AARCH64_SVE_ASM)
     {
       if (IS_A64FX (midr))
 	return __memmove_a64fx;
-      return __memmove_sve;
+      return prefer_sve_ifuncs ? __memmove_sve : __memmove_generic;
     }
 
   if (IS_THUNDERX (midr))
@@ -57,9 +56,6 @@ select_memmove_ifunc (void)
   if (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr))
     return __memmove_thunderx2;
 
-  if (IS_FALKOR (midr) || IS_PHECDA (midr))
-    return __memmove_falkor;
-
   return __memmove_generic;
 }
 
diff --git a/sysdeps/aarch64/multiarch/memmove_mops.S b/sysdeps/aarch64/multiarch/memmove_mops.S
new file mode 100644
index 0000000000..c5ea66be3a
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memmove_mops.S
@@ -0,0 +1,39 @@
+/* Optimized memmove for MOPS.
+   Copyright (C) 2023 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>
+
+/* Assumptions:
+ *
+ * AArch64, MOPS.
+ *
+ */
+
+ENTRY (__memmove_mops)
+	PTR_ARG (0)
+	PTR_ARG (1)
+	SIZE_ARG (2)
+
+	mov	x3, x0
+	.inst	0x1d010443	/* cpyp    [x3]!, [x1]!, x2!  */
+	.inst	0x1d410443	/* cpym    [x3]!, [x1]!, x2!  */
+	.inst	0x1d810443	/* cpye    [x3]!, [x1]!, x2!  */
+	ret
+
+END (__memmove_mops)
diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c
index c4008f346b..6c9bb910c6 100644
--- a/sysdeps/aarch64/multiarch/memset.c
+++ b/sysdeps/aarch64/multiarch/memset.c
@@ -28,28 +28,44 @@
 
 extern __typeof (__redirect_memset) __libc_memset;
 
-extern __typeof (__redirect_memset) __memset_falkor attribute_hidden;
+extern __typeof (__redirect_memset) __memset_zva64 attribute_hidden;
 extern __typeof (__redirect_memset) __memset_emag attribute_hidden;
 extern __typeof (__redirect_memset) __memset_kunpeng attribute_hidden;
-# if HAVE_AARCH64_SVE_ASM
 extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden;
-# endif
 extern __typeof (__redirect_memset) __memset_generic attribute_hidden;
+extern __typeof (__redirect_memset) __memset_mops attribute_hidden;
+extern __typeof (__redirect_memset) __memset_sve_zva64 attribute_hidden;
 
-libc_ifunc (__libc_memset,
-	    IS_KUNPENG920 (midr)
-	    ?__memset_kunpeng
-	    : ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64
-	      ? __memset_falkor
-	      : (IS_EMAG (midr) && zva_size == 64
-		? __memset_emag
-# if HAVE_AARCH64_SVE_ASM
-		: (IS_A64FX (midr) && sve
-		  ? __memset_a64fx
-		  : __memset_generic))));
-# else
-		  : __memset_generic)));
-# endif
+static inline __typeof (__redirect_memset) *
+select_memset_ifunc (void)
+{
+  INIT_ARCH ();
+
+  if (mops)
+    return __memset_mops;
+
+  if (sve && HAVE_AARCH64_SVE_ASM)
+    {
+      if (IS_A64FX (midr) && zva_size == 256)
+	return __memset_a64fx;
+
+      if (prefer_sve_ifuncs && zva_size == 64)
+	return __memset_sve_zva64;
+    }
+
+  if (IS_KUNPENG920 (midr))
+    return __memset_kunpeng;
+
+  if (IS_EMAG (midr))
+    return __memset_emag;
+
+  if (zva_size == 64)
+    return __memset_zva64;
+
+  return __memset_generic;
+}
+
+libc_ifunc (__libc_memset, select_memset_ifunc ());
 
 # undef memset
 strong_alias (__libc_memset, memset);
diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S
index dc87190724..4a4d4ed504 100644
--- a/sysdeps/aarch64/multiarch/memset_a64fx.S
+++ b/sysdeps/aarch64/multiarch/memset_a64fx.S
@@ -33,8 +33,6 @@
 #define vector_length	x9
 
 #if HAVE_AARCH64_SVE_ASM
-# if IS_IN (libc)
-#  define MEMSET __memset_a64fx
 
 	.arch armv8.2-a+sve
 
@@ -49,7 +47,7 @@
 #undef BTI_C
 #define BTI_C
 
-ENTRY (MEMSET)
+ENTRY (__memset_a64fx)
 	PTR_ARG (0)
 	SIZE_ARG (2)
 
@@ -166,8 +164,6 @@ L(L2):
 	add	count, count, CACHE_LINE_SIZE
 	b	L(last)
 
-END (MEMSET)
-libc_hidden_builtin_def (MEMSET)
+END (__memset_a64fx)
 
-#endif /* IS_IN (libc) */
 #endif /* HAVE_AARCH64_SVE_ASM */
diff --git a/sysdeps/aarch64/multiarch/memset_base64.S b/sysdeps/aarch64/multiarch/memset_base64.S
deleted file mode 100644
index 32d20d739e..0000000000
--- a/sysdeps/aarch64/multiarch/memset_base64.S
+++ /dev/null
@@ -1,186 +0,0 @@
-/* Copyright (C) 2018-2022 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 "memset-reg.h"
-
-#ifndef MEMSET
-# define MEMSET __memset_base64
-#endif
-
-/* To disable DC ZVA, set this threshold to 0. */
-#ifndef DC_ZVA_THRESHOLD
-# define DC_ZVA_THRESHOLD 512
-#endif
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64, unaligned accesses
- *
- */
-
-ENTRY_ALIGN (MEMSET, 6)
-
-	PTR_ARG (0)
-	SIZE_ARG (2)
-
-	bfi	valw, valw, 8, 8
-	bfi	valw, valw, 16, 16
-	bfi	val, val, 32, 32
-
-	add	dstend, dstin, count
-
-	cmp	count, 96
-	b.hi	L(set_long)
-	cmp	count, 16
-	b.hs	L(set_medium)
-
-	/* Set 0..15 bytes.  */
-	tbz	count, 3, 1f
-	str	val, [dstin]
-	str	val, [dstend, -8]
-	ret
-
-	.p2align 3
-1:	tbz	count, 2, 2f
-	str	valw, [dstin]
-	str	valw, [dstend, -4]
-	ret
-2:	cbz	count, 3f
-	strb	valw, [dstin]
-	tbz	count, 1, 3f
-	strh	valw, [dstend, -2]
-3:	ret
-
-	.p2align 3
-	/* Set 16..96 bytes.  */
-L(set_medium):
-	stp	val, val, [dstin]
-	tbnz	count, 6, L(set96)
-	stp	val, val, [dstend, -16]
-	tbz	count, 5, 1f
-	stp	val, val, [dstin, 16]
-	stp	val, val, [dstend, -32]
-1:	ret
-
-	.p2align 4
-	/* Set 64..96 bytes.  Write 64 bytes from the start and
-	   32 bytes from the end.  */
-L(set96):
-	stp	val, val, [dstin, 16]
-	stp	val, val, [dstin, 32]
-	stp	val, val, [dstin, 48]
-	stp	val, val, [dstend, -32]
-	stp	val, val, [dstend, -16]
-	ret
-
-	.p2align 4
-L(set_long):
-	stp	val, val, [dstin]
-	bic	dst, dstin, 15
-#if DC_ZVA_THRESHOLD
-	cmp	count, DC_ZVA_THRESHOLD
-	ccmp	val, 0, 0, cs
-	b.eq	L(zva_64)
-#endif
-	/* Small-size or non-zero memset does not use DC ZVA. */
-	sub	count, dstend, dst
-
-	/*
-	 * Adjust count and bias for loop. By substracting extra 1 from count,
-	 * it is easy to use tbz instruction to check whether loop tailing
-	 * count is less than 33 bytes, so as to bypass 2 unneccesary stps.
-	 */
-	sub	count, count, 64+16+1
-
-#if DC_ZVA_THRESHOLD
-	/* Align loop on 16-byte boundary, this might be friendly to i-cache. */
-	nop
-#endif
-
-1:	stp	val, val, [dst, 16]
-	stp	val, val, [dst, 32]
-	stp	val, val, [dst, 48]
-	stp	val, val, [dst, 64]!
-	subs	count, count, 64
-	b.hs	1b
-
-	tbz	count, 5, 1f	/* Remaining count is less than 33 bytes? */
-	stp	val, val, [dst, 16]
-	stp	val, val, [dst, 32]
-1:	stp	val, val, [dstend, -32]
-	stp	val, val, [dstend, -16]
-	ret
-
-#if DC_ZVA_THRESHOLD
-	.p2align 3
-L(zva_64):
-	stp	val, val, [dst, 16]
-	stp	val, val, [dst, 32]
-	stp	val, val, [dst, 48]
-	bic	dst, dst, 63
-
-	/*
-	 * Previous memory writes might cross cache line boundary, and cause
-	 * cache line partially dirty. Zeroing this kind of cache line using
-	 * DC ZVA will incur extra cost, for it requires loading untouched
-	 * part of the line from memory before zeoring.
-	 *
-	 * So, write the first 64 byte aligned block using stp to force
-	 * fully dirty cache line.
-	 */
-	stp	val, val, [dst, 64]
-	stp	val, val, [dst, 80]
-	stp	val, val, [dst, 96]
-	stp	val, val, [dst, 112]
-
-	sub	count, dstend, dst
-	/*
-	 * Adjust count and bias for loop. By substracting extra 1 from count,
-	 * it is easy to use tbz instruction to check whether loop tailing
-	 * count is less than 33 bytes, so as to bypass 2 unneccesary stps.
-	 */
-	sub	count, count, 128+64+64+1
-	add	dst, dst, 128
-	nop
-
-	/* DC ZVA sets 64 bytes each time. */
-1:	dc	zva, dst
-	add	dst, dst, 64
-	subs	count, count, 64
-	b.hs	1b
-
-	/*
-	 * Write the last 64 byte aligned block using stp to force fully
-	 * dirty cache line.
-	 */
-	stp	val, val, [dst, 0]
-	stp	val, val, [dst, 16]
-	stp	val, val, [dst, 32]
-	stp	val, val, [dst, 48]
-
-	tbz	count, 5, 1f	/* Remaining count is less than 33 bytes? */
-	stp	val, val, [dst, 64]
-	stp	val, val, [dst, 80]
-1:	stp	val, val, [dstend, -32]
-	stp	val, val, [dstend, -16]
-	ret
-#endif
-
-END (MEMSET)
-libc_hidden_builtin_def (MEMSET)
diff --git a/sysdeps/aarch64/multiarch/memset_emag.S b/sysdeps/aarch64/multiarch/memset_emag.S
index 922c1ed57d..7ecf61dc59 100644
--- a/sysdeps/aarch64/multiarch/memset_emag.S
+++ b/sysdeps/aarch64/multiarch/memset_emag.S
@@ -18,19 +18,95 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
+#include "memset-reg.h"
 
-#if IS_IN (libc)
-# define MEMSET __memset_emag
-
-/*
- * Using DC ZVA to zero memory does not produce better performance if
- * memory size is not very large, especially when there are multiple
- * processes/threads contending memory/cache. Here we set threshold to
- * zero to disable using DC ZVA, which is good for multi-process/thread
- * workloads.
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses
+ *
  */
 
-# define DC_ZVA_THRESHOLD 0
+ENTRY (__memset_emag)
+
+	PTR_ARG (0)
+	SIZE_ARG (2)
+
+	bfi	valw, valw, 8, 8
+	bfi	valw, valw, 16, 16
+	bfi	val, val, 32, 32
+
+	add	dstend, dstin, count
+
+	cmp	count, 96
+	b.hi	L(set_long)
+	cmp	count, 16
+	b.hs	L(set_medium)
+
+	/* Set 0..15 bytes.  */
+	tbz	count, 3, 1f
+	str	val, [dstin]
+	str	val, [dstend, -8]
+	ret
+
+	.p2align 3
+1:	tbz	count, 2, 2f
+	str	valw, [dstin]
+	str	valw, [dstend, -4]
+	ret
+2:	cbz	count, 3f
+	strb	valw, [dstin]
+	tbz	count, 1, 3f
+	strh	valw, [dstend, -2]
+3:	ret
+
+	.p2align 3
+	/* Set 16..96 bytes.  */
+L(set_medium):
+	stp	val, val, [dstin]
+	tbnz	count, 6, L(set96)
+	stp	val, val, [dstend, -16]
+	tbz	count, 5, 1f
+	stp	val, val, [dstin, 16]
+	stp	val, val, [dstend, -32]
+1:	ret
+
+	.p2align 4
+	/* Set 64..96 bytes.  Write 64 bytes from the start and
+	   32 bytes from the end.  */
+L(set96):
+	stp	val, val, [dstin, 16]
+	stp	val, val, [dstin, 32]
+	stp	val, val, [dstin, 48]
+	stp	val, val, [dstend, -32]
+	stp	val, val, [dstend, -16]
+	ret
+
+	.p2align 4
+L(set_long):
+	stp	val, val, [dstin]
+	bic	dst, dstin, 15
+	/* Small-size or non-zero memset does not use DC ZVA. */
+	sub	count, dstend, dst
+
+	/*
+	 * Adjust count and bias for loop. By subtracting extra 1 from count,
+	 * it is easy to use tbz instruction to check whether loop tailing
+	 * count is less than 33 bytes, so as to bypass 2 unnecessary stps.
+	 */
+	sub	count, count, 64+16+1
+
+1:	stp	val, val, [dst, 16]
+	stp	val, val, [dst, 32]
+	stp	val, val, [dst, 48]
+	stp	val, val, [dst, 64]!
+	subs	count, count, 64
+	b.hs	1b
+
+	tbz	count, 5, 1f	/* Remaining count is less than 33 bytes? */
+	stp	val, val, [dst, 16]
+	stp	val, val, [dst, 32]
+1:	stp	val, val, [dstend, -32]
+	stp	val, val, [dstend, -16]
+	ret
 
-# include "./memset_base64.S"
-#endif
+END (__memset_emag)
diff --git a/sysdeps/aarch64/multiarch/memset_falkor.S b/sysdeps/aarch64/multiarch/memset_falkor.S
deleted file mode 100644
index 657f4c60b4..0000000000
--- a/sysdeps/aarch64/multiarch/memset_falkor.S
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Memset for falkor.
-   Copyright (C) 2017-2022 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 <memset-reg.h>
-
-/* Reading dczid_el0 is expensive on falkor so move it into the ifunc
-   resolver and assume ZVA size of 64 bytes.  The IFUNC resolver takes care to
-   use this function only when ZVA is enabled.  */
-
-#if IS_IN (libc)
-.macro zva_macro
-	.p2align 4
-	/* Write the first and last 64 byte aligned block using stp rather
-	   than using DC ZVA.  This is faster on some cores.  */
-	str	q0, [dst, 16]
-	stp	q0, q0, [dst, 32]
-	bic	dst, dst, 63
-	stp	q0, q0, [dst, 64]
-	stp	q0, q0, [dst, 96]
-	sub	count, dstend, dst	/* Count is now 128 too large.	*/
-	sub	count, count, 128+64+64	/* Adjust count and bias for loop.  */
-	add	dst, dst, 128
-1:	dc	zva, dst
-	add	dst, dst, 64
-	subs	count, count, 64
-	b.hi	1b
-	stp	q0, q0, [dst, 0]
-	stp	q0, q0, [dst, 32]
-	stp	q0, q0, [dstend, -64]
-	stp	q0, q0, [dstend, -32]
-	ret
-.endm
-
-# define ZVA_MACRO zva_macro
-# define MEMSET __memset_falkor
-# include <sysdeps/aarch64/memset.S>
-#endif
diff --git a/sysdeps/aarch64/multiarch/memset_generic.S b/sysdeps/aarch64/multiarch/memset_generic.S
index c879be93d5..6efcb5f00d 100644
--- a/sysdeps/aarch64/multiarch/memset_generic.S
+++ b/sysdeps/aarch64/multiarch/memset_generic.S
@@ -21,9 +21,15 @@
 
 #if IS_IN (libc)
 # define MEMSET __memset_generic
+
+/* Do not hide the generic version of memset, we use it internally.  */
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(name)
+
 /* Add a hidden definition for use within libc.so.  */
 # ifdef SHARED
 	.globl __GI_memset; __GI_memset = __memset_generic
 # endif
-# include <sysdeps/aarch64/memset.S>
 #endif
+
+#include <../memset.S>
diff --git a/sysdeps/aarch64/multiarch/memset_kunpeng.S b/sysdeps/aarch64/multiarch/memset_kunpeng.S
index a6d2c8c3bb..8f2deddb74 100644
--- a/sysdeps/aarch64/multiarch/memset_kunpeng.S
+++ b/sysdeps/aarch64/multiarch/memset_kunpeng.S
@@ -20,16 +20,13 @@
 #include <sysdep.h>
 #include <sysdeps/aarch64/memset-reg.h>
 
-#if IS_IN (libc)
-# define MEMSET __memset_kunpeng
-
 /* Assumptions:
  *
  * ARMv8-a, AArch64, unaligned accesses
  *
  */
 
-ENTRY_ALIGN (MEMSET, 6)
+ENTRY (__memset_kunpeng)
 
 	PTR_ARG (0)
 	SIZE_ARG (2)
@@ -108,6 +105,4 @@ L(set_long):
 	stp	q0, q0, [dstend, -32]
 	ret
 
-END (MEMSET)
-libc_hidden_builtin_def (MEMSET)
-#endif
+END (__memset_kunpeng)
diff --git a/sysdeps/aarch64/multiarch/memset_mops.S b/sysdeps/aarch64/multiarch/memset_mops.S
new file mode 100644
index 0000000000..ca820b8636
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memset_mops.S
@@ -0,0 +1,38 @@
+/* Optimized memset for MOPS.
+   Copyright (C) 2023 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>
+
+/* Assumptions:
+ *
+ * AArch64, MOPS.
+ *
+ */
+
+ENTRY (__memset_mops)
+	PTR_ARG (0)
+	SIZE_ARG (2)
+
+	mov     x3, x0
+	.inst   0x19c10443	/* setp    [x3]!, x2!, x1  */
+	.inst   0x19c14443	/* setm    [x3]!, x2!, x1  */
+	.inst   0x19c18443	/* sete    [x3]!, x2!, x1  */
+	ret
+
+END (__memset_mops)
diff --git a/sysdeps/aarch64/multiarch/memset_sve_zva64.S b/sysdeps/aarch64/multiarch/memset_sve_zva64.S
new file mode 100644
index 0000000000..7fb40fdd9e
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memset_sve_zva64.S
@@ -0,0 +1,123 @@
+/* Optimized memset for SVE.
+   Copyright (C) 2025 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>
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, Advanced SIMD, SVE, unaligned accesses.
+ * ZVA size is 64.
+ */
+
+#if HAVE_AARCH64_SVE_ASM
+
+.arch armv8.2-a+sve
+
+#define dstin	x0
+#define val	x1
+#define valw	w1
+#define count	x2
+#define dst	x3
+#define dstend	x4
+#define zva_val	x5
+#define vlen	x5
+#define off	x3
+#define dstend2 x5
+
+ENTRY (__memset_sve_zva64)
+	dup	v0.16B, valw
+	cmp	count, 16
+	b.lo	L(set_16)
+
+	add	dstend, dstin, count
+	cmp	count, 64
+	b.hs	L(set_128)
+
+	/* Set 16..63 bytes.  */
+	mov	off, 16
+	and	off, off, count, lsr 1
+	sub	dstend2, dstend, off
+	str	q0, [dstin]
+	str	q0, [dstin, off]
+	str	q0, [dstend2, -16]
+	str	q0, [dstend, -16]
+	ret
+
+	.p2align 4
+L(set_16):
+	whilelo p0.b, xzr, count
+	st1b	z0.b, p0, [dstin]
+	ret
+
+	.p2align 4
+L(set_128):
+	bic	dst, dstin, 15
+	cmp	count, 128
+	b.hi	L(set_long)
+	stp	q0, q0, [dstin]
+	stp	q0, q0, [dstin, 32]
+	stp	q0, q0, [dstend, -64]
+	stp	q0, q0, [dstend, -32]
+	ret
+
+	.p2align 4
+L(set_long):
+	cmp	count, 256
+	b.lo	L(no_zva)
+	tst	valw, 255
+	b.ne	L(no_zva)
+
+	str	q0, [dstin]
+	str	q0, [dst, 16]
+	bic	dst, dstin, 31
+	stp	q0, q0, [dst, 32]
+	bic	dst, dstin, 63
+	sub	count, dstend, dst	/* Count is now 64 too large.  */
+	sub	count, count, 128	/* Adjust count and bias for loop.  */
+
+	sub	x8, dstend, 1		/* Write last bytes before ZVA loop.  */
+	bic	x8, x8, 15
+	stp	q0, q0, [x8, -48]
+	str	q0, [x8, -16]
+	str	q0, [dstend, -16]
+
+	.p2align 4
+L(zva64_loop):
+	add	dst, dst, 64
+	dc	zva, dst
+	subs	count, count, 64
+	b.hi	L(zva64_loop)
+	ret
+
+L(no_zva):
+	str	q0, [dstin]
+	sub	count, dstend, dst	/* Count is 16 too large.  */
+	sub	count, count, 64 + 16	/* Adjust count and bias for loop.  */
+L(no_zva_loop):
+	stp	q0, q0, [dst, 16]
+	stp	q0, q0, [dst, 48]
+	add	dst, dst, 64
+	subs	count, count, 64
+	b.hi	L(no_zva_loop)
+	stp	q0, q0, [dstend, -64]
+	stp	q0, q0, [dstend, -32]
+	ret
+
+END (__memset_sve_zva64)
+#endif
diff --git a/sysdeps/aarch64/multiarch/memset_zva64.S b/sysdeps/aarch64/multiarch/memset_zva64.S
new file mode 100644
index 0000000000..13f45fd3d8
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memset_zva64.S
@@ -0,0 +1,27 @@
+/* Optimized memset for zva size = 64.
+   Copyright (C) 2023 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>
+
+#define ZVA64_ONLY 1
+#define MEMSET __memset_zva64
+#undef libc_hidden_builtin_def
+#define libc_hidden_builtin_def(X)
+
+#include "../memset.S"
diff --git a/sysdeps/aarch64/multiarch/rtld-memset.S b/sysdeps/aarch64/multiarch/rtld-memset.S
deleted file mode 100644
index 7968d25e48..0000000000
--- a/sysdeps/aarch64/multiarch/rtld-memset.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Memset for aarch64, for the dynamic linker.
-   Copyright (C) 2017-2022 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>
-
-#if IS_IN (rtld)
-# define MEMSET memset
-# include <sysdeps/aarch64/memset.S>
-#endif
diff --git a/sysdeps/aarch64/multiarch/strlen.c b/sysdeps/aarch64/multiarch/strlen.c
index 6d27c126b0..a951967fcd 100644
--- a/sysdeps/aarch64/multiarch/strlen.c
+++ b/sysdeps/aarch64/multiarch/strlen.c
@@ -28,10 +28,10 @@
 
 extern __typeof (__redirect_strlen) __strlen;
 
-extern __typeof (__redirect_strlen) __strlen_mte attribute_hidden;
+extern __typeof (__redirect_strlen) __strlen_generic attribute_hidden;
 extern __typeof (__redirect_strlen) __strlen_asimd attribute_hidden;
 
-libc_ifunc (__strlen, (mte ? __strlen_mte : __strlen_asimd));
+libc_ifunc (__strlen, (mte ? __strlen_generic : __strlen_asimd));
 
 # undef strlen
 strong_alias (__strlen, strlen);
diff --git a/sysdeps/aarch64/multiarch/strlen_asimd.S b/sysdeps/aarch64/multiarch/strlen_asimd.S
index 6faeb91361..dcd4589d10 100644
--- a/sysdeps/aarch64/multiarch/strlen_asimd.S
+++ b/sysdeps/aarch64/multiarch/strlen_asimd.S
@@ -48,6 +48,7 @@
 #define tmp	x2
 #define tmpw	w2
 #define synd	x3
+#define syndw	w3
 #define shift	x4
 
 /* For the first 32 bytes, NUL detection works on the principle that
@@ -87,7 +88,6 @@
 
 ENTRY (__strlen_asimd)
 	PTR_ARG (0)
-
 	and	tmp1, srcin, MIN_PAGE_SIZE - 1
 	cmp	tmp1, MIN_PAGE_SIZE - 32
 	b.hi	L(page_cross)
@@ -123,7 +123,6 @@ ENTRY (__strlen_asimd)
 	add	len, len, tmp1, lsr 3
 	ret
 
-	.p2align 3
 	/* Look for a NUL byte at offset 16..31 in the string.  */
 L(bytes16_31):
 	ldp	data1, data2, [srcin, 16]
@@ -151,6 +150,7 @@ L(bytes16_31):
 	add	len, len, tmp1, lsr 3
 	ret
 
+	nop
 L(loop_entry):
 	bic	src, srcin, 31
 
@@ -166,18 +166,12 @@ L(loop):
 	/* Low 32 bits of synd are non-zero if a NUL was found in datav1.  */
 	cmeq	maskv.16b, datav1.16b, 0
 	sub	len, src, srcin
-	tst	synd, 0xffffffff
-	b.ne	1f
+	cbnz	syndw, 1f
 	cmeq	maskv.16b, datav2.16b, 0
 	add	len, len, 16
 1:
 	/* Generate a bitmask and compute correct byte offset.  */
-#ifdef __AARCH64EB__
-	bic	maskv.8h, 0xf0
-#else
-	bic	maskv.8h, 0x0f, lsl 8
-#endif
-	umaxp	maskv.16b, maskv.16b, maskv.16b
+	shrn	maskv.8b, maskv.8h, 4
 	fmov	synd, maskd
 #ifndef __AARCH64EB__
 	rbit	synd, synd
@@ -186,8 +180,6 @@ L(loop):
 	add	len, len, tmp, lsr 2
 	ret
 
-        .p2align 4
-
 L(page_cross):
 	bic	src, srcin, 31
 	mov	tmpw, 0x0c03
@@ -211,4 +203,3 @@ L(page_cross):
 	ret
 
 END (__strlen_asimd)
-libc_hidden_builtin_def (__strlen_asimd)
diff --git a/sysdeps/aarch64/multiarch/strlen_generic.S b/sysdeps/aarch64/multiarch/strlen_generic.S
new file mode 100644
index 0000000000..014e376ec1
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/strlen_generic.S
@@ -0,0 +1,39 @@
+/* A Generic Optimized strlen implementation for AARCH64.
+   Copyright (C) 2018-2022 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/>.  */
+
+/* The actual strlen code is in ../strlen.S.  If we are building libc this file
+   defines __strlen_generic.  Otherwise the include of ../strlen.S will define
+   the normal __strlen entry points.  */
+
+#include <sysdep.h>
+
+#if IS_IN (libc)
+
+# define STRLEN __strlen_generic
+
+/* Do not hide the generic version of strlen, we use it internally.  */
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(name)
+
+# ifdef SHARED
+/* It doesn't make sense to send libc-internal strlen calls through a PLT. */
+	.globl __GI_strlen; __GI_strlen = __strlen_generic
+# endif
+#endif
+
+#include "../strlen.S"
diff --git a/sysdeps/aarch64/multiarch/strlen_mte.S b/sysdeps/aarch64/multiarch/strlen_mte.S
deleted file mode 100644
index bf03ac53eb..0000000000
--- a/sysdeps/aarch64/multiarch/strlen_mte.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/* A Generic Optimized strlen implementation for AARCH64.
-   Copyright (C) 2018-2022 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/>.  */
-
-/* The actual strlen code is in ../strlen.S.  If we are building libc this file
-   defines __strlen_mte.  Otherwise the include of ../strlen.S will define
-   the normal __strlen  entry points.  */
-
-#include <sysdep.h>
-
-#if IS_IN (libc)
-
-# define STRLEN __strlen_mte
-
-/* Do not hide the generic version of strlen, we use it internally.  */
-# undef libc_hidden_builtin_def
-# define libc_hidden_builtin_def(name)
-
-# ifdef SHARED
-/* It doesn't make sense to send libc-internal strlen calls through a PLT. */
-	.globl __GI_strlen; __GI_strlen = __strlen_mte
-# endif
-#endif
-
-#include "../strlen.S"
diff --git a/sysdeps/aarch64/rawmemchr.S b/sysdeps/aarch64/rawmemchr.S
index 55d9e34d4f..f90ce2bf86 100644
--- a/sysdeps/aarch64/rawmemchr.S
+++ b/sysdeps/aarch64/rawmemchr.S
@@ -31,7 +31,7 @@ ENTRY (__rawmemchr)
 
 L(do_strlen):
 	mov	x15, x30
-	cfi_return_column (x15)
+	cfi_register (x30, x15)
 	mov	x14, x0
 	bl	__strlen
 	add	x0, x14, x0
diff --git a/sysdeps/aarch64/strchr.S b/sysdeps/aarch64/strchr.S
index 003bf4a478..4781d45bd9 100644
--- a/sysdeps/aarch64/strchr.S
+++ b/sysdeps/aarch64/strchr.S
@@ -32,8 +32,7 @@
 
 #define src		x2
 #define tmp1		x1
-#define wtmp2		w3
-#define tmp3		x3
+#define tmp2		x3
 
 #define vrepchr		v0
 #define vdata		v1
@@ -41,39 +40,30 @@
 #define vhas_nul	v2
 #define vhas_chr	v3
 #define vrepmask	v4
-#define vrepmask2	v5
-#define vend		v6
-#define dend		d6
+#define vend		v5
+#define dend		d5
 
 /* Core algorithm.
 
    For each 16-byte chunk we calculate a 64-bit syndrome value with four bits
-   per byte. For even bytes, bits 0-1 are set if the relevant byte matched the
-   requested character, bits 2-3 are set if the byte is NUL (or matched), and
-   bits 4-7 are not used and must be zero if none of bits 0-3 are set). Odd
-   bytes set bits 4-7 so that adjacent bytes can be merged. Since the bits
-   in the syndrome reflect the order in which things occur in the original
-   string, counting trailing zeros identifies exactly which byte matched.  */
+   per byte. Bits 0-1 are set if the relevant byte matched the requested
+   character, bits 2-3 are set if the byte is NUL or matched. Count trailing
+   zeroes gives the position of the matching byte if it is a multiple of 4.
+   If it is not a multiple of 4, there was no match.  */
 
 ENTRY (strchr)
 	PTR_ARG (0)
 	bic	src, srcin, 15
 	dup	vrepchr.16b, chrin
 	ld1	{vdata.16b}, [src]
-	mov	wtmp2, 0x3003
-	dup	vrepmask.8h, wtmp2
+	movi	vrepmask.16b, 0x33
 	cmeq	vhas_nul.16b, vdata.16b, 0
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
-	mov	wtmp2, 0xf00f
-	dup	vrepmask2.8h, wtmp2
-
 	bit	vhas_nul.16b, vhas_chr.16b, vrepmask.16b
-	and	vhas_nul.16b, vhas_nul.16b, vrepmask2.16b
-	lsl	tmp3, srcin, 2
-	addp	vend.16b, vhas_nul.16b, vhas_nul.16b		/* 128->64 */
-
+	lsl	tmp2, srcin, 2
+	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
 	fmov	tmp1, dend
-	lsr	tmp1, tmp1, tmp3
+	lsr	tmp1, tmp1, tmp2
 	cbz	tmp1, L(loop)
 
 	rbit	tmp1, tmp1
@@ -87,28 +77,34 @@ ENTRY (strchr)
 
 	.p2align 4
 L(loop):
-	ldr	qdata, [src, 16]!
+	ldr	qdata, [src, 16]
+	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
+	cmhs	vhas_nul.16b, vhas_chr.16b, vdata.16b
+	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
+	fmov	tmp1, dend
+	cbnz	tmp1, L(end)
+	ldr	qdata, [src, 32]!
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
 	cmhs	vhas_nul.16b, vhas_chr.16b, vdata.16b
 	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
 	fmov	tmp1, dend
 	cbz	tmp1, L(loop)
+	sub	src, src, 16
+L(end):
 
 #ifdef __AARCH64EB__
 	bif	vhas_nul.16b, vhas_chr.16b, vrepmask.16b
-	and	vhas_nul.16b, vhas_nul.16b, vrepmask2.16b
-	addp	vend.16b, vhas_nul.16b, vhas_nul.16b		/* 128->64 */
+	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
 	fmov	tmp1, dend
 #else
 	bit	vhas_nul.16b, vhas_chr.16b, vrepmask.16b
-	and	vhas_nul.16b, vhas_nul.16b, vrepmask2.16b
-	addp	vend.16b, vhas_nul.16b, vhas_nul.16b		/* 128->64 */
+	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
 	fmov	tmp1, dend
 	rbit	tmp1, tmp1
 #endif
+	add	src, src, 16
 	clz	tmp1, tmp1
-	/* Tmp1 is an even multiple of 2 if the target character was
-	   found first. Otherwise we've found the end of string.  */
+	/* Tmp1 is a multiple of 4 if the target character was found.  */
 	tst	tmp1, 2
 	add	result, src, tmp1, lsr 2
 	csel	result, result, xzr, eq
diff --git a/sysdeps/aarch64/strchrnul.S b/sysdeps/aarch64/strchrnul.S
index ee154ab74b..94465fc088 100644
--- a/sysdeps/aarch64/strchrnul.S
+++ b/sysdeps/aarch64/strchrnul.S
@@ -70,14 +70,22 @@ ENTRY (__strchrnul)
 
 	.p2align 4
 L(loop):
-	ldr	qdata, [src, 16]!
+	ldr	qdata, [src, 16]
+	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
+	cmhs	vhas_chr.16b, vhas_chr.16b, vdata.16b
+	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b
+	fmov	tmp1, dend
+	cbnz	tmp1, L(end)
+	ldr	qdata, [src, 32]!
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
 	cmhs	vhas_chr.16b, vhas_chr.16b, vdata.16b
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b
 	fmov	tmp1, dend
 	cbz	tmp1, L(loop)
-
+	sub	src, src, 16
+L(end):
 	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
+	add	src, src, 16
 	fmov	tmp1, dend
 #ifndef __AARCH64EB__
 	rbit	tmp1, tmp1
diff --git a/sysdeps/aarch64/strcpy.S b/sysdeps/aarch64/strcpy.S
index 78d27b4aa6..6eeda12df6 100644
--- a/sysdeps/aarch64/strcpy.S
+++ b/sysdeps/aarch64/strcpy.S
@@ -30,7 +30,6 @@
  * MTE compatible.
  */
 
-/* Arguments and results.  */
 #define dstin		x0
 #define srcin		x1
 #define result		x0
@@ -76,14 +75,14 @@ ENTRY (STRCPY)
 	ld1	{vdata.16b}, [src]
 	cmeq	vhas_nul.16b, vdata.16b, 0
 	lsl	shift, srcin, 2
-	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
+	shrn	vend.8b, vhas_nul.8h, 4
 	fmov	synd, dend
 	lsr	synd, synd, shift
 	cbnz	synd, L(tail)
 
 	ldr	dataq, [src, 16]!
 	cmeq	vhas_nul.16b, vdata.16b, 0
-	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
+	shrn	vend.8b, vhas_nul.8h, 4
 	fmov	synd, dend
 	cbz	synd, L(start_loop)
 
@@ -102,13 +101,10 @@ ENTRY (STRCPY)
 	IFSTPCPY (add result, dstin, len)
 	ret
 
-	.p2align 4,,8
 L(tail):
 	rbit	synd, synd
 	clz	len, synd
 	lsr	len, len, 2
-
-	.p2align 4
 L(less16):
 	tbz	len, 3, L(less8)
 	sub	tmp, len, 7
@@ -141,31 +137,37 @@ L(zerobyte):
 
 	.p2align 4
 L(start_loop):
-	sub	len, src, srcin
+	sub	tmp, srcin, dstin
 	ldr	dataq2, [srcin]
-	add	dst, dstin, len
+	sub	dst, src, tmp
 	str	dataq2, [dstin]
-
-	.p2align 5
 L(loop):
-	str	dataq, [dst], 16
-	ldr	dataq, [src, 16]!
+	str	dataq, [dst], 32
+	ldr	dataq, [src, 16]
+	cmeq	vhas_nul.16b, vdata.16b, 0
+	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
+	fmov	synd, dend
+	cbnz	synd, L(loopend)
+	str	dataq, [dst, -16]
+	ldr	dataq, [src, 32]!
 	cmeq	vhas_nul.16b, vdata.16b, 0
 	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
 	fmov	synd, dend
 	cbz	synd, L(loop)
-
+	add	dst, dst, 16
+L(loopend):
 	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
 	fmov	synd, dend
+	sub	dst, dst, 31
 #ifndef __AARCH64EB__
 	rbit	synd, synd
 #endif
 	clz	len, synd
 	lsr	len, len, 2
-	sub	tmp, len, 15
-	ldr	dataq, [src, tmp]
-	str	dataq, [dst, tmp]
-	IFSTPCPY (add result, dst, len)
+	add	dst, dst, len
+	ldr	dataq, [dst, tmp]
+	str	dataq, [dst]
+	IFSTPCPY (add result, dst, 15)
 	ret
 
 END (STRCPY)
diff --git a/sysdeps/aarch64/strlen.S b/sysdeps/aarch64/strlen.S
index 3a5d088407..352fb40d3a 100644
--- a/sysdeps/aarch64/strlen.S
+++ b/sysdeps/aarch64/strlen.S
@@ -1,4 +1,5 @@
-/* Copyright (C) 2012-2022 Free Software Foundation, Inc.
+/* Generic optimized strlen using SIMD.
+   Copyright (C) 2012-2024 Free Software Foundation, Inc.
 
    This file is part of the GNU C Library.
 
@@ -43,12 +44,9 @@
 #define dend		d2
 
 /* Core algorithm:
-
-   For each 16-byte chunk we calculate a 64-bit nibble mask value with four bits
-   per byte. We take 4 bits of every comparison byte with shift right and narrow
-   by 4 instruction. Since the bits in the nibble mask reflect the order in
-   which things occur in the original string, counting trailing zeros identifies
-   exactly which byte matched.  */
+   Process the string in 16-byte aligned chunks. Compute a 64-bit mask with
+   four bits per byte using the shrn instruction. A count trailing zeros then
+   identifies the first zero byte.  */
 
 ENTRY (STRLEN)
 	PTR_ARG (0)
@@ -59,29 +57,50 @@ ENTRY (STRLEN)
 	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
 	fmov	synd, dend
 	lsr	synd, synd, shift
-	cbz	synd, L(loop)
+	cbz	synd, L(next16)
 
 	rbit	synd, synd
 	clz	result, synd
 	lsr	result, result, 2
 	ret
 
-	.p2align 5
-L(loop):
-	ldr	data, [src, 16]!
+L(next16):
+	ldr	data, [src, 16]
 	cmeq	vhas_nul.16b, vdata.16b, 0
-	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
+	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
 	fmov	synd, dend
 	cbz	synd, L(loop)
-
-	shrn	vend.8b, vhas_nul.8h, 4		/* 128->64 */
+	add	src, src, 16
+#ifndef __AARCH64EB__
+	rbit	synd, synd
+#endif
 	sub	result, src, srcin
+	clz	tmp, synd
+	add	result, result, tmp, lsr 2
+	ret
+
+	.p2align 5
+L(loop):
+	ldr	data, [src, 32]!
+	cmeq	vhas_nul.16b, vdata.16b, 0
+	addhn	vend.8b, vhas_nul.8h, vhas_nul.8h
 	fmov	synd, dend
+	cbnz	synd, L(loop_end)
+	ldr	data, [src, 16]
+	cmeq	vhas_nul.16b, vdata.16b, 0
+	addhn	vend.8b, vhas_nul.8h, vhas_nul.8h
+	fmov	synd, dend
+	cbz	synd, L(loop)
+	add	src, src, 16
+L(loop_end):
+	sub	result, shift, src, lsl 2	/* (srcin - src) << 2.  */
 #ifndef __AARCH64EB__
 	rbit	synd, synd
+	sub	result, result, 3
 #endif
 	clz	tmp, synd
-	add	result, result, tmp, lsr 2
+	sub	result, tmp, result
+	lsr	result, result, 2
 	ret
 
 END (STRLEN)
diff --git a/sysdeps/aarch64/strnlen.S b/sysdeps/aarch64/strnlen.S
index 282bddc9aa..a44a49a920 100644
--- a/sysdeps/aarch64/strnlen.S
+++ b/sysdeps/aarch64/strnlen.S
@@ -44,19 +44,16 @@
 
 /*
    Core algorithm:
-
-   For each 16-byte chunk we calculate a 64-bit nibble mask value with four bits
-   per byte. We take 4 bits of every comparison byte with shift right and narrow
-   by 4 instruction. Since the bits in the nibble mask reflect the order in
-   which things occur in the original string, counting trailing zeros identifies
-   exactly which byte matched.  */
+   Process the string in 16-byte aligned chunks. Compute a 64-bit mask with
+   four bits per byte using the shrn instruction. A count trailing zeros then
+   identifies the first zero byte.  */
 
 ENTRY (__strnlen)
 	PTR_ARG (0)
 	SIZE_ARG (1)
 	bic	src, srcin, 15
 	cbz	cntin, L(nomatch)
-	ld1	{vdata.16b}, [src], 16
+	ld1	{vdata.16b}, [src]
 	cmeq	vhas_chr.16b, vdata.16b, 0
 	lsl	shift, srcin, 2
 	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
@@ -71,36 +68,40 @@ L(finish):
 	csel	result, cntin, result, ls
 	ret
 
+L(nomatch):
+	mov	result, cntin
+	ret
+
 L(start_loop):
 	sub	tmp, src, srcin
+	add	tmp, tmp, 17
 	subs	cntrem, cntin, tmp
-	b.ls	L(nomatch)
+	b.lo	L(nomatch)
 
 	/* Make sure that it won't overread by a 16-byte chunk */
-	add	tmp, cntrem, 15
-	tbnz	tmp, 4, L(loop32_2)
-
+	tbz	cntrem, 4, L(loop32_2)
+	sub	src, src, 16
 	.p2align 5
 L(loop32):
-	ldr	qdata, [src], 16
+	ldr	qdata, [src, 32]!
 	cmeq	vhas_chr.16b, vdata.16b, 0
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
 	fmov	synd, dend
 	cbnz	synd, L(end)
 L(loop32_2):
-	ldr	qdata, [src], 16
+	ldr	qdata, [src, 16]
 	subs	cntrem, cntrem, 32
 	cmeq	vhas_chr.16b, vdata.16b, 0
-	b.ls	L(end)
+	b.lo	L(end_2)
 	umaxp	vend.16b, vhas_chr.16b, vhas_chr.16b		/* 128->64 */
 	fmov	synd, dend
 	cbz	synd, L(loop32)
-
+L(end_2):
+	add	src, src, 16
 L(end):
 	shrn	vend.8b, vhas_chr.8h, 4		/* 128->64 */
-	sub	src, src, 16
-	mov	synd, vend.d[0]
 	sub	result, src, srcin
+	fmov	synd, dend
 #ifndef __AARCH64EB__
 	rbit	synd, synd
 #endif
@@ -110,10 +111,6 @@ L(end):
 	csel	result, cntin, result, ls
 	ret
 
-L(nomatch):
-	mov	result, cntin
-	ret
-
 END (__strnlen)
 libc_hidden_def (__strnlen)
 weak_alias (__strnlen, strnlen)
diff --git a/sysdeps/aarch64/strrchr.S b/sysdeps/aarch64/strrchr.S
index 596e77c43b..eda6fefb99 100644
--- a/sysdeps/aarch64/strrchr.S
+++ b/sysdeps/aarch64/strrchr.S
@@ -22,19 +22,16 @@
 
 /* Assumptions:
  *
- * ARMv8-a, AArch64
- * Neon Available.
+ * ARMv8-a, AArch64, Advanced SIMD.
  * MTE compatible.
  */
 
-/* Arguments and results.  */
 #define srcin		x0
 #define chrin		w1
 #define result		x0
 
 #define src		x2
 #define tmp		x3
-#define wtmp		w3
 #define synd		x3
 #define shift		x4
 #define src_match	x4
@@ -46,7 +43,6 @@
 #define vhas_nul	v2
 #define vhas_chr	v3
 #define vrepmask	v4
-#define vrepmask2	v5
 #define vend		v5
 #define dend		d5
 
@@ -58,59 +54,71 @@
    the relevant byte matched the requested character; bits 2-3 are set
    if the relevant byte matched the NUL end of string.  */
 
-ENTRY(strrchr)
+ENTRY (strrchr)
 	PTR_ARG (0)
 	bic	src, srcin, 15
 	dup	vrepchr.16b, chrin
-	mov	wtmp, 0x3003
-	dup	vrepmask.8h, wtmp
-	tst	srcin, 15
-	beq	L(loop1)
-
-	ld1	{vdata.16b}, [src], 16
+	movi	vrepmask.16b, 0x33
+	ld1	{vdata.16b}, [src]
 	cmeq	vhas_nul.16b, vdata.16b, 0
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
-	mov	wtmp, 0xf00f
-	dup	vrepmask2.8h, wtmp
 	bit	vhas_nul.16b, vhas_chr.16b, vrepmask.16b
-	and	vhas_nul.16b, vhas_nul.16b, vrepmask2.16b
-	addp	vend.16b, vhas_nul.16b, vhas_nul.16b
+	shrn	vend.8b, vhas_nul.8h, 4
 	lsl	shift, srcin, 2
 	fmov	synd, dend
 	lsr	synd, synd, shift
 	lsl	synd, synd, shift
 	ands	nul_match, synd, 0xcccccccccccccccc
 	bne	L(tail)
-	cbnz	synd, L(loop2)
+	cbnz	synd, L(loop2_start)
 
-	.p2align 5
+	.p2align 4
 L(loop1):
-	ld1	{vdata.16b}, [src], 16
+	ldr	q1, [src, 16]
+	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
+	cmhs	vhas_nul.16b, vhas_chr.16b, vdata.16b
+	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
+	fmov	synd, dend
+	cbnz	synd, L(loop1_end)
+	ldr	q1, [src, 32]!
 	cmeq	vhas_chr.16b, vdata.16b, vrepchr.16b
 	cmhs	vhas_nul.16b, vhas_chr.16b, vdata.16b
 	umaxp	vend.16b, vhas_nul.16b, vhas_nul.16b
 	fmov	synd, dend
 	cbz	synd, L(loop1)
-
+	sub	src, src, 16
+L(loop1_end):
+	add	src, src, 16
 	cmeq	vhas_nul.16b, vdata.16b, 0
+#ifdef __AARCH64EB__
+	bif	vhas_nul.16b, vhas_chr.16b, vrepmask.16b
+	shrn	vend.8b, vhas_nul.8h, 4
+	fmov	synd, dend
+	rbit	synd, synd
+#else
 	bit	vhas_nul.16b, vhas_chr.16b, vrepmask.16b
-	bic	vhas_nul.8h, 0x0f, lsl 8
-	addp	vend.16b, vhas_nul.16b, vhas_nul.16b
+	shrn	vend.8b, vhas_nul.8h, 4
 	fmov	synd, dend
+#endif
 	ands	nul_match, synd, 0xcccccccccccccccc
-	beq	L(loop2)
-
+	beq	L(loop2_start)
 L(tail):
 	sub	nul_match, nul_match, 1
 	and	chr_match, synd, 0x3333333333333333
 	ands	chr_match, chr_match, nul_match
-	sub	result, src, 1
+	add	result, src, 15
 	clz	tmp, chr_match
 	sub	result, result, tmp, lsr 2
 	csel	result, result, xzr, ne
 	ret
 
 	.p2align 4
+	nop
+	nop
+L(loop2_start):
+	add	src, src, 16
+	bic	vrepmask.8h, 0xf0
+
 L(loop2):
 	cmp	synd, 0
 	csel	src_match, src, src_match, ne
diff --git a/sysdeps/arc/utmp-size.h b/sysdeps/arc/utmp-size.h
new file mode 100644
index 0000000000..a247fcd3da
--- /dev/null
+++ b/sysdeps/arc/utmp-size.h
@@ -0,0 +1,3 @@
+/* arc has less padding than other architectures with 64-bit time_t.  */
+#define UTMP_SIZE 392
+#define LASTLOG_SIZE 296
diff --git a/sysdeps/arm/bits/wordsize.h b/sysdeps/arm/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/arm/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
index 6a422713bd..659c6f16da 100644
--- a/sysdeps/arm/dl-machine.h
+++ b/sysdeps/arm/dl-machine.h
@@ -137,7 +137,6 @@ _start:\n\
 _dl_start_user:\n\
 	adr	r6, .L_GET_GOT\n\
 	add	sl, sl, r6\n\
-	ldr	r4, [sl, r4]\n\
 	@ save the entry point in another register\n\
 	mov	r6, r0\n\
 	@ get the original arg count\n\
diff --git a/sysdeps/arm/utmp-size.h b/sysdeps/arm/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/arm/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/csky/bits/wordsize.h b/sysdeps/csky/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/csky/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/csky/utmp-size.h b/sysdeps/csky/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/csky/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 050a3032de..17bd399888 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -105,6 +105,9 @@ typedef struct link_map *lookup_t;
    DT_PREINIT_ARRAY.  */
 typedef void (*dl_init_t) (int, char **, char **);
 
+/* Type of a constructor function, in DT_FINI, DT_FINI_ARRAY.  */
+typedef void (*fini_t) (void);
+
 /* On some architectures a pointer to a function is not just a pointer
    to the actual code of the function but rather an architecture
    specific descriptor. */
@@ -1048,9 +1051,16 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
    initializer functions have completed.  */
 extern void _dl_fini (void) attribute_hidden;
 
-/* Sort array MAPS according to dependencies of the contained objects.  */
+/* Invoke the DT_FINI_ARRAY and DT_FINI destructors for MAP, which
+   must be a struct link_map *.  Can be used as an argument to
+   _dl_catch_exception.  */
+void _dl_call_fini (void *map) attribute_hidden;
+
+/* Sort array MAPS according to dependencies of the contained objects.
+   If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
+   say otherwise.  */
 extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
-			   unsigned int skip, bool for_fini) attribute_hidden;
+			   bool force_first, bool for_fini) attribute_hidden;
 
 /* The dynamic linker calls this function before and having changing
    any shared object mappings.  The `r_state' member of `struct r_debug'
@@ -1257,9 +1267,24 @@ extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add)
 
 /* Update slot information data for at least the generation of the
    module with the given index.  */
-extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid)
+extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid,
+					     size_t gen)
      attribute_hidden;
 
+/* The last TLS module ID that is initially loaded, plus 1.  TLS
+   addresses for modules with IDs lower than that can be obtained from
+   the DTV even if its generation is outdated.  */
+extern size_t _dl_tls_initial_modid_limit attribute_hidden attribute_relro;
+
+/* Compute _dl_tls_initial_modid_limit.  To be called after initial
+   relocation.  */
+void _dl_tls_initial_modid_limit_setup (void) attribute_hidden;
+
+/* Number of threads currently in a TLS update.  This is used to
+   detect reentrant __tls_get_addr calls without a per-thread
+   flag.  */
+extern unsigned int _dl_tls_threads_in_update attribute_hidden;
+
 /* Look up the module's TLS block as for __tls_get_addr,
    but never touch anything.  Return null if it's not allocated yet.  */
 extern void *_dl_tls_get_addr_soft (struct link_map *l) attribute_hidden;
diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h
new file mode 100644
index 0000000000..4713b30a8a
--- /dev/null
+++ b/sysdeps/generic/libc-lock-arch.h
@@ -0,0 +1,25 @@
+/* Private libc-internal arch-specific definitions.  Generic version.
+   Copyright (C) 2022 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC_LOCK_ARCH_H
+#define _LIBC_LOCK_ARCH_H
+
+/* The default definition uses the natural alignment from the lock type.  */
+#define __LIBC_LOCK_ALIGNMENT
+
+#endif
diff --git a/sysdeps/generic/mremap-failure.h b/sysdeps/generic/mremap-failure.h
new file mode 100644
index 0000000000..bc0d476368
--- /dev/null
+++ b/sysdeps/generic/mremap-failure.h
@@ -0,0 +1,25 @@
+/* mremap failure handling.  Generic version.
+   Copyright (C) 2024 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/>.  */
+
+/* Return exit value on mremap failure with errno ERR.  */
+
+static int
+mremap_failure_exit (int err)
+{
+  return EXIT_FAILURE;
+}
diff --git a/sysdeps/generic/utmp-size.h b/sysdeps/generic/utmp-size.h
new file mode 100644
index 0000000000..89dbe878b0
--- /dev/null
+++ b/sysdeps/generic/utmp-size.h
@@ -0,0 +1,23 @@
+/* Expected sizes of utmp-related structures stored in files.  64-bit version.
+   Copyright (C) 2024 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/>.  */
+
+/* Expected size, in bytes, of struct utmp and struct utmpx.  */
+#define UTMP_SIZE 400
+
+/* Expected size, in bytes, of struct lastlog.  */
+#define LASTLOG_SIZE 296
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
index c865713be1..1d51948566 100644
--- a/sysdeps/hppa/dl-machine.h
+++ b/sysdeps/hppa/dl-machine.h
@@ -347,6 +347,16 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
    its return value is the user program's entry point.  */
 
 #define RTLD_START \
+/* Set up dp for any non-PIC lib constructors that may be called.  */	\
+static struct link_map * __attribute__((used))				\
+set_dp (struct link_map *map)						\
+{									\
+  register Elf32_Addr dp asm ("%r27");					\
+  dp = D_PTR (map, l_info[DT_PLTGOT]);					\
+  asm volatile ("" : : "r" (dp));					\
+  return map;								\
+}									\
+									\
 asm (									\
 "	.text\n"							\
 "	.globl _start\n"						\
@@ -426,6 +436,13 @@ asm (									\
 	   direct loader invocation.  Thus, argc and argv must be	\
 	   reloaded from from _dl_argc and _dl_argv.  */		\
 									\
+	/* Load main_map from _rtld_local and setup dp. */		\
+"	addil	LT'_rtld_local,%r19\n"					\
+"	ldw	RT'_rtld_local(%r1),%r26\n"				\
+"	bl	set_dp, %r2\n"						\
+"	ldw	0(%r26),%r26\n"						\
+"	copy	%ret0,%r26\n"						\
+									\
 	/* Load argc from _dl_argc.  */					\
 "	addil	LT'_dl_argc,%r19\n"					\
 "	ldw	RT'_dl_argc(%r1),%r20\n"				\
@@ -438,13 +455,10 @@ asm (									\
 "	ldw	0(%r20),%r24\n"						\
 "	stw	%r24,-44(%sp)\n"					\
 									\
-	/* Call _dl_init(main_map, argc, argv, envp). */		\
-"	addil	LT'_rtld_local,%r19\n"					\
-"	ldw	RT'_rtld_local(%r1),%r26\n"				\
-"	ldw	0(%r26),%r26\n"						\
-									\
 	/* envp = argv + argc + 1 */					\
 "	sh2add	%r25,%r24,%r23\n"					\
+									\
+	/* Call _dl_init(main_map, argc, argv, envp). */		\
 "	bl	_dl_init,%r2\n"						\
 "	ldo	4(%r23),%r23\n"	/* delay slot */			\
 									\
diff --git a/sysdeps/hppa/utmp-size.h b/sysdeps/hppa/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/hppa/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/ieee754/dbl-64/math_config.h b/sysdeps/ieee754/dbl-64/math_config.h
index a346fdca58..6c6cee511f 100644
--- a/sysdeps/ieee754/dbl-64/math_config.h
+++ b/sysdeps/ieee754/dbl-64/math_config.h
@@ -134,10 +134,11 @@ check_uflow (double x)
 extern const struct exp_data
 {
   double invln2N;
-  double shift;
   double negln2hiN;
   double negln2loN;
   double poly[4]; /* Last four coefficients.  */
+  double shift;
+
   double exp2_shift;
   double exp2_poly[EXP2_POLY_ORDER];
   uint64_t tab[2*(1 << EXP_TABLE_BITS)];
diff --git a/sysdeps/ieee754/dbl-64/s_expm1.c b/sysdeps/ieee754/dbl-64/s_expm1.c
index 8f1c95bd04..1cafeca9c0 100644
--- a/sysdeps/ieee754/dbl-64/s_expm1.c
+++ b/sysdeps/ieee754/dbl-64/s_expm1.c
@@ -130,6 +130,11 @@ static const double
 	  4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
 	  -2.01099218183624371326e-07 }; /* BE8AFDB7 6E09C32D */
 
+#ifndef SECTION
+# define SECTION
+#endif
+
+SECTION
 double
 __expm1 (double x)
 {
@@ -258,4 +263,6 @@ __expm1 (double x)
     }
   return y;
 }
+#ifndef __expm1
 libm_alias_double (__expm1, expm1)
+#endif
diff --git a/sysdeps/ieee754/dbl-64/s_log1p.c b/sysdeps/ieee754/dbl-64/s_log1p.c
index e6476a8260..eeb0af859f 100644
--- a/sysdeps/ieee754/dbl-64/s_log1p.c
+++ b/sysdeps/ieee754/dbl-64/s_log1p.c
@@ -99,6 +99,11 @@ static const double
 
 static const double zero = 0.0;
 
+#ifndef SECTION
+# define SECTION
+#endif
+
+SECTION
 double
 __log1p (double x)
 {
diff --git a/sysdeps/ieee754/flt-32/math_config.h b/sysdeps/ieee754/flt-32/math_config.h
index c7f71ca496..6a52d1d51b 100644
--- a/sysdeps/ieee754/flt-32/math_config.h
+++ b/sysdeps/ieee754/flt-32/math_config.h
@@ -126,9 +126,9 @@ extern const struct exp2f_data
   uint64_t tab[1 << EXP2F_TABLE_BITS];
   double shift_scaled;
   double poly[EXP2F_POLY_ORDER];
-  double shift;
   double invln2_scaled;
   double poly_scaled[EXP2F_POLY_ORDER];
+  double shift;
 } __exp2f_data attribute_hidden;
 
 #define LOGF_TABLE_BITS 4
diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c
index 54c457681a..9a9c5c6f00 100644
--- a/sysdeps/ieee754/ldbl-128/e_j1l.c
+++ b/sysdeps/ieee754/ldbl-128/e_j1l.c
@@ -869,10 +869,13 @@ __ieee754_y1l (_Float128 x)
     {
       /* 0 <= x <= 2 */
       SET_RESTORE_ROUNDL (FE_TONEAREST);
+      xx = math_opt_barrier (xx);
+      x = math_opt_barrier (x);
       z = xx * xx;
       p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D);
       p = -TWOOPI / xx + p;
       p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p;
+      math_force_eval (p);
       return p;
     }
 
diff --git a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c
index f85ba94466..0a5fe68342 100644
--- a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c
+++ b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c
@@ -792,10 +792,13 @@ __ieee754_y1l (long double x)
     {
       /* 0 <= x <= 2 */
       SET_RESTORE_ROUNDL (FE_TONEAREST);
+      xx = math_opt_barrier (xx);
+      x = math_opt_barrier (x);
       z = xx * xx;
       p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D);
       p = -TWOOPI / xx + p;
       p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p;
+      math_force_eval (p);
       return p;
     }
 
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
index d85154e73a..d8c0de1faf 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
@@ -66,38 +66,35 @@ __llroundl (long double x)
       /* Peg at max/min values, assuming that the above conversions do so.
          Strictly speaking, we can return anything for values that overflow,
          but this is more useful.  */
-      res = hi + lo;
-
-      /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi).  */
-      if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0)))
+      if (__glibc_unlikely (__builtin_add_overflow (hi, lo, &res)))
 	goto overflow;
 
       xh -= lo;
       ldbl_canonicalize (&xh, &xl);
 
-      hi = res;
       if (xh > 0.5)
 	{
-	  res += 1;
+	  if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res)))
+	    goto overflow;
 	}
       else if (xh == 0.5)
 	{
 	  if (xl > 0.0 || (xl == 0.0 && res >= 0))
-	    res += 1;
+	    if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res)))
+	      goto overflow;
 	}
       else if (-xh > 0.5)
 	{
-	  res -= 1;
+	  if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res)))
+	    goto overflow;
 	}
       else if (-xh == 0.5)
 	{
 	  if (xl < 0.0 || (xl == 0.0 && res <= 0))
-	    res -= 1;
+	    if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res)))
+	      goto overflow;
 	}
 
-      if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0)))
-	goto overflow;
-
       return res;
     }
   else
diff --git a/sysdeps/m68k/bits/wordsize.h b/sysdeps/m68k/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/m68k/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/m68k/utmp-size.h b/sysdeps/m68k/utmp-size.h
new file mode 100644
index 0000000000..5946685819
--- /dev/null
+++ b/sysdeps/m68k/utmp-size.h
@@ -0,0 +1,3 @@
+/* m68k has 2-byte alignment.  */
+#define UTMP_SIZE 382
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c
index 37ea5e6a7a..80ea7e17cb 100644
--- a/sysdeps/mach/getsysstats.c
+++ b/sysdeps/mach/getsysstats.c
@@ -62,12 +62,6 @@ __get_nprocs (void)
 libc_hidden_def (__get_nprocs)
 weak_alias (__get_nprocs, get_nprocs)
 
-int
-__get_nprocs_sched (void)
-{
-  return __get_nprocs ();
-}
-
 /* Return the number of physical pages on the system. */
 long int
 __get_phys_pages (void)
diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
index 5b35ea81ec..70fce4fb27 100644
--- a/sysdeps/mach/hurd/bits/socket.h
+++ b/sysdeps/mach/hurd/bits/socket.h
@@ -249,6 +249,12 @@ struct cmsghdr
 			 + CMSG_ALIGN (sizeof (struct cmsghdr)))
 #define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
 
+/* Given a length, return the additional padding necessary such that
+   len + __CMSG_PADDING(len) == CMSG_ALIGN (len).  */
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
+                              - ((len) & (sizeof (size_t) - 1))) \
+                             & (sizeof (size_t) - 1))
+
 extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
 				      struct cmsghdr *__cmsg) __THROW;
 #ifdef __USE_EXTERN_INLINES
@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
 _EXTERN_INLINE struct cmsghdr *
 __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
 {
+  /* We may safely assume that __cmsg lies between __mhdr->msg_control and
+     __mhdr->msg_controllen because the user is required to obtain the first
+     cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
+     via CMSG_NXTHDR, setting lengths along the way.  However, we don't yet
+     trust the value of __cmsg->cmsg_len and therefore do not use it in any
+     pointer arithmetic until we check its value.  */
+
+  unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
+  unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
+
+  size_t __size_needed = sizeof (struct cmsghdr)
+                         + __CMSG_PADDING (__cmsg->cmsg_len);
+
+  /* The current header is malformed, too small to be a full header.  */
   if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-    /* The kernel header does this so there may be a reason.  */
     return (struct cmsghdr *) 0;
 
+  /* There isn't enough space between __cmsg and the end of the buffer to
+  hold the current cmsg *and* the next one.  */
+  if (((size_t)
+         (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
+       < __size_needed)
+      || ((size_t)
+            (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
+             - __size_needed)
+          < __cmsg->cmsg_len))
+
+    return (struct cmsghdr *) 0;
+
+  /* Now, we trust cmsg_len and can use it to find the next header.  */
   __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
 			       + CMSG_ALIGN (__cmsg->cmsg_len));
-  if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-					+ __mhdr->msg_controllen)
-      || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-	  > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-    /* No more entries.  */
-    return (struct cmsghdr *) 0;
   return __cmsg;
 }
 #endif	/* Use `extern inline'.  */
diff --git a/sysdeps/microblaze/bits/wordsize.h b/sysdeps/microblaze/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/microblaze/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/microblaze/utmp-size.h b/sysdeps/microblaze/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/microblaze/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/mips/bits/wordsize.h b/sysdeps/mips/bits/wordsize.h
index e521dc589c..c6a4a4270b 100644
--- a/sysdeps/mips/bits/wordsize.h
+++ b/sysdeps/mips/bits/wordsize.h
@@ -19,11 +19,7 @@
 
 #define __WORDSIZE			_MIPS_SZPTR
 
-#if _MIPS_SIM == _ABI64
-# define __WORDSIZE_TIME64_COMPAT32	1
-#else
-# define __WORDSIZE_TIME64_COMPAT32	0
-#endif
+#define __WORDSIZE_TIME64_COMPAT32	1
 
 #if __WORDSIZE == 32
 #define __WORDSIZE32_SIZE_ULONG		0
diff --git a/sysdeps/mips/utmp-size.h b/sysdeps/mips/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/mips/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/nios2/bits/wordsize.h b/sysdeps/nios2/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/nios2/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/nios2/utmp-size.h b/sysdeps/nios2/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/nios2/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c
index 53fba774a5..662bc0158d 100644
--- a/sysdeps/nptl/dl-tls_init_tp.c
+++ b/sysdeps/nptl/dl-tls_init_tp.c
@@ -45,8 +45,6 @@ rtld_mutex_dummy (pthread_mutex_t *lock)
 #endif
 
 const unsigned int __rseq_flags;
-const unsigned int __rseq_size attribute_relro;
-const ptrdiff_t __rseq_offset attribute_relro;
 
 void
 __tls_pre_init_tp (void)
@@ -106,12 +104,7 @@ __tls_init_tp (void)
     do_rseq = TUNABLE_GET (rseq, int, NULL);
 #endif
     if (rseq_register_current_thread (pd, do_rseq))
-      {
-        /* We need a writable view of the variables.  They are in
-           .data.relro and are not yet write-protected.  */
-        extern unsigned int size __asm__ ("__rseq_size");
-        size = sizeof (pd->rseq_area);
-      }
+      _rseq_size = RSEQ_AREA_SIZE_INITIAL_USED;
 
 #ifdef RSEQ_SIG
     /* This should be a compile-time constant, but the current
@@ -119,8 +112,7 @@ __tls_init_tp (void)
        all targets support __thread_pointer, so set __rseq_offset only
        if thre rseq registration may have happened because RSEQ_SIG is
        defined.  */
-    extern ptrdiff_t offset __asm__ ("__rseq_offset");
-    offset = (char *) &pd->rseq_area - (char *) __thread_pointer ();
+    _rseq_offset = (char *) &pd->rseq_area - (char *) __thread_pointer ();
 #endif
   }
 
diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h
index 5af476c48b..63b3f3d75c 100644
--- a/sysdeps/nptl/libc-lock.h
+++ b/sysdeps/nptl/libc-lock.h
@@ -22,6 +22,7 @@
 #include <pthread.h>
 #define __need_NULL
 #include <stddef.h>
+#include <libc-lock-arch.h>
 
 
 /* Mutex type.  */
@@ -29,7 +30,12 @@
 # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC
 typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
 # else
-typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t;
+typedef struct
+{
+  int lock __LIBC_LOCK_ALIGNMENT;
+  int cnt;
+  void *owner;
+} __libc_lock_recursive_t;
 # endif
 #else
 typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h
index d3a6837fd2..425f514c5c 100644
--- a/sysdeps/nptl/libc-lockP.h
+++ b/sysdeps/nptl/libc-lockP.h
@@ -32,9 +32,10 @@
    ld.so might be used on old kernels with a different libc.so.  */
 #include <lowlevellock.h>
 #include <tls.h>
+#include <libc-lock-arch.h>
 
 /* Mutex type.  */
-typedef int __libc_lock_t;
+typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT;
 typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
 typedef pthread_rwlock_t __libc_rwlock_t;
 
diff --git a/sysdeps/or1k/utmp-size.h b/sysdeps/or1k/utmp-size.h
new file mode 100644
index 0000000000..6b3653aa4d
--- /dev/null
+++ b/sysdeps/or1k/utmp-size.h
@@ -0,0 +1,3 @@
+/* or1k has less padding than other architectures with 64-bit time_t.  */
+#define UTMP_SIZE 392
+#define LASTLOG_SIZE 296
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index bcff909b2f..f975dcd2bc 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
 {
   struct gaih_addrtuple *at;
   char *canon;
+  char *h_name;
   bool free_at;
   bool got_ipv6;
 };
@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res)
   if (res->free_at)
     free (res->at);
   free (res->canon);
+  free (res->h_name);
   memset (res, 0, sizeof (*res));
 }
 
@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
   return 0;
 }
 
-/* Convert struct hostent to a list of struct gaih_addrtuple objects.  h_name
-   is not copied, and the struct hostent object must not be deallocated
-   prematurely.  The new addresses are appended to the tuple array in RES.  */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects.  The new
+   addresses are appended to the tuple array in RES.  */
 static bool
 convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
 				   struct hostent *h, struct gaih_result *res)
@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
   res->at = array;
   res->free_at = true;
 
+  /* Duplicate h_name because it may get reclaimed when the underlying storage
+     is freed.  */
+  if (res->h_name == NULL)
+    {
+      res->h_name = __strdup (h->h_name);
+      if (res->h_name == NULL)
+	return false;
+    }
+
   /* Update the next pointers on reallocation.  */
   for (size_t i = 0; i < old; i++)
     array[i].next = array + i + 1;
@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
 	}
       array[i].next = array + i + 1;
     }
-  array[0].name = h->h_name;
   array[count - 1].next = NULL;
 
   return true;
@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
    memory allocation failure.  The returned string is allocated on the
    heap; the caller has to free it.  */
 static char *
-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
+getcanonname (nss_action_list nip, const char *hname, const char *name)
 {
   nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r");
   char *s = (char *) name;
   if (cfct != NULL)
     {
       char buf[256];
-      if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf),
-			      &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
+      if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno,
+			      &h_errno)) != NSS_STATUS_SUCCESS)
 	/* If the canonical name cannot be determined, use the passed
 	   string.  */
 	s = (char *) name;
@@ -540,11 +549,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req,
 	  at[count].addr[2] = htonl (0xffff);
 	}
       else if (req->ai_family == AF_UNSPEC
-	       || air->family[count] == req->ai_family)
+	       || air->family[i] == req->ai_family)
 	{
-	  at[count].family = air->family[count];
+	  at[count].family = air->family[i];
 	  memcpy (at[count].addr, addrs, size);
-	  if (air->family[count] == AF_INET6)
+	  if (air->family[i] == AF_INET6)
 	    res->got_ipv6 = true;
 	}
       at[count].next = at + count + 1;
@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
 		  if ((req->ai_flags & AI_CANONNAME) != 0
 		      && res->canon == NULL)
 		    {
-		      char *canonbuf = getcanonname (nip, res->at, name);
+		      char *canonbuf = getcanonname (nip, res->h_name, name);
 		      if (canonbuf == NULL)
 			{
 			  __resolv_context_put (res_ctx);
@@ -1187,9 +1196,7 @@ free_and_return:
   if (malloc_name)
     free ((char *) name);
   free (addrmem);
-  if (res.free_at)
-    free (res.at);
-  free (res.canon);
+  gaih_result_reset (&res);
 
   return result;
 }
diff --git a/sysdeps/posix/libc_fatal.c b/sysdeps/posix/libc_fatal.c
index 2ee0010b8d..dfa0780514 100644
--- a/sysdeps/posix/libc_fatal.c
+++ b/sysdeps/posix/libc_fatal.c
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <ldsodefs.h>
+#include <libc-pointer-arith.h>
 #include <paths.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -125,8 +126,8 @@ __libc_message (enum __libc_message_action action, const char *fmt, ...)
 
       if ((action & do_abort))
 	{
-	  total = ((total + 1 + GLRO(dl_pagesize) - 1)
-		   & ~(GLRO(dl_pagesize) - 1));
+	  total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+			    GLRO(dl_pagesize));
 	  struct abort_msg_s *buf = __mmap (NULL, total,
 					    PROT_READ | PROT_WRITE,
 					    MAP_ANON | MAP_PRIVATE, -1, 0);
diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c
index 8014f63355..20c9420dd4 100644
--- a/sysdeps/posix/system.c
+++ b/sysdeps/posix/system.c
@@ -179,16 +179,16 @@ do_system (const char *line)
       as if the shell had terminated using _exit(127).  */
    status = W_EXITCODE (127, 0);
 
+  /* sigaction can not fail with SIGINT/SIGQUIT used with old
+     disposition.  Same applies for sigprocmask.  */
   DO_LOCK ();
   if (SUB_REF () == 0)
     {
-      /* sigaction can not fail with SIGINT/SIGQUIT used with old
-	 disposition.  Same applies for sigprocmask.  */
       __sigaction (SIGINT, &intr, NULL);
       __sigaction (SIGQUIT, &quit, NULL);
-      __sigprocmask (SIG_SETMASK, &omask, NULL);
     }
   DO_UNLOCK ();
+  __sigprocmask (SIG_SETMASK, &omask, NULL);
 
   if (ret != 0)
     __set_errno (ret);
diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c
index 2a82e53baf..d941024963 100644
--- a/sysdeps/powerpc/mod-tlsopt-powerpc.c
+++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c
@@ -22,7 +22,11 @@ tls_get_addr_opt_test (void)
   tls_index *tls_arg;
 #ifdef __powerpc64__
   register unsigned long thread_pointer __asm__ ("r13");
-  asm ("addi %0,2,foo@got@tlsgd" : "=r" (tls_arg));
+# ifdef __PCREL__
+  asm ("paddi %0,0,foo@got@tlsgd@pcrel,1" : "=b" (tls_arg));
+# else
+  asm ("addi %0,2,foo@got@tlsgd" : "=b" (tls_arg));
+# endif
 #else
   register unsigned long thread_pointer __asm__ ("r2");
   asm ("bcl 20,31,1f\n1:\t"
diff --git a/sysdeps/powerpc/powerpc32/bits/wordsize.h b/sysdeps/powerpc/powerpc32/bits/wordsize.h
index 04ca9debf0..6993fb6b29 100644
--- a/sysdeps/powerpc/powerpc32/bits/wordsize.h
+++ b/sysdeps/powerpc/powerpc32/bits/wordsize.h
@@ -2,10 +2,9 @@
 
 #if defined __powerpc64__
 # define __WORDSIZE	64
-# define __WORDSIZE_TIME64_COMPAT32	1
 #else
 # define __WORDSIZE	32
-# define __WORDSIZE_TIME64_COMPAT32	0
 # define __WORDSIZE32_SIZE_ULONG	0
 # define __WORDSIZE32_PTRDIFF_LONG	0
 #endif
+#define __WORDSIZE_TIME64_COMPAT32	1
diff --git a/sysdeps/powerpc/powerpc64/bits/wordsize.h b/sysdeps/powerpc/powerpc64/bits/wordsize.h
index 04ca9debf0..6993fb6b29 100644
--- a/sysdeps/powerpc/powerpc64/bits/wordsize.h
+++ b/sysdeps/powerpc/powerpc64/bits/wordsize.h
@@ -2,10 +2,9 @@
 
 #if defined __powerpc64__
 # define __WORDSIZE	64
-# define __WORDSIZE_TIME64_COMPAT32	1
 #else
 # define __WORDSIZE	32
-# define __WORDSIZE_TIME64_COMPAT32	0
 # define __WORDSIZE32_SIZE_ULONG	0
 # define __WORDSIZE32_PTRDIFF_LONG	0
 #endif
+#define __WORDSIZE_TIME64_COMPAT32	1
diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
index bb0ccd0811..3868bcc2f7 100644
--- a/sysdeps/powerpc/powerpc64/dl-machine.h
+++ b/sysdeps/powerpc/powerpc64/dl-machine.h
@@ -79,6 +79,7 @@ elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
 static inline Elf64_Addr
 elf_machine_load_address (void) __attribute__ ((const));
 
+#ifndef __PCREL__
 static inline Elf64_Addr
 elf_machine_load_address (void)
 {
@@ -106,6 +107,24 @@ elf_machine_dynamic (void)
   /* Then subtract off the load address offset.  */
   return runtime_dynamic - elf_machine_load_address() ;
 }
+#else /* __PCREL__ */
+/* In PCREL mode, r2 may have been clobbered.  Rely on relative
+   relocations instead.  */
+
+static inline ElfW(Addr)
+elf_machine_load_address (void)
+{
+  extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
+  return (ElfW(Addr)) &__ehdr_start;
+}
+
+static inline ElfW(Addr)
+elf_machine_dynamic (void)
+{
+  extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
+  return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
+}
+#endif /* __PCREL__ */
 
 /* The PLT uses Elf64_Rela relocs.  */
 #define elf_machine_relplt elf_machine_rela
diff --git a/sysdeps/powerpc/utmp-size.h b/sysdeps/powerpc/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/powerpc/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/pthread/tst-setuid3.c b/sysdeps/pthread/tst-setuid3.c
index 7dd360e325..4a77791253 100644
--- a/sysdeps/pthread/tst-setuid3.c
+++ b/sysdeps/pthread/tst-setuid3.c
@@ -15,24 +15,19 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdio.h>
 #include <errno.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <unistd.h>
 
+#include <support/check.h>
+
 /* The test must run under a non-privileged user ID.  */
 static const uid_t test_uid = 1;
 
 static pthread_barrier_t barrier1;
 static pthread_barrier_t barrier2;
 
-#define FAIL(fmt, ...) \
-  do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
-
-#define FAIL_ERR(fmt, ...) \
-  do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0)
-
 /* True if x is not a successful return code from pthread_barrier_wait.  */
 static inline bool
 is_invalid_barrier_ret (int x)
@@ -45,10 +40,10 @@ thread_func (void *ctx __attribute__ ((unused)))
 {
   int ret = pthread_barrier_wait (&barrier1);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
   ret = pthread_barrier_wait (&barrier2);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
   return NULL;
 }
 
@@ -59,13 +54,13 @@ setuid_failure (int phase)
   switch (ret)
     {
     case 0:
-      FAIL ("setuid succeeded unexpectedly in phase %d", phase);
+      FAIL_EXIT1 ("setuid succeeded unexpectedly in phase %d", phase);
     case -1:
       if (errno != EPERM)
-	FAIL_ERR ("setuid phase %d", phase);
+	FAIL_EXIT1 ("setuid phase %d: %m", phase);
       break;
     default:
-      FAIL ("invalid setuid return value in phase %d: %d", phase, ret);
+      FAIL_EXIT1 ("invalid setuid return value in phase %d: %d", phase, ret);
     }
 }
 
@@ -74,42 +69,42 @@ do_test (void)
 {
   if (getuid () == 0)
     if (setuid (test_uid) != 0)
-      FAIL_ERR ("setuid (%u)", (unsigned) test_uid);
+      FAIL_EXIT1 ("setuid (%u): %m", (unsigned) test_uid);
   if (setuid (getuid ()))
-    FAIL_ERR ("setuid (%s)", "getuid ()");
+    FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
   setuid_failure (1);
 
   int ret = pthread_barrier_init (&barrier1, NULL, 2);
   if (ret != 0)
-    FAIL ("pthread_barrier_init (barrier1): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_init (barrier1): %d", ret);
   ret = pthread_barrier_init (&barrier2, NULL, 2);
   if (ret != 0)
-    FAIL ("pthread_barrier_init (barrier2): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_init (barrier2): %d", ret);
 
   pthread_t thread;
   ret = pthread_create (&thread, NULL, thread_func, NULL);
   if (ret != 0)
-    FAIL ("pthread_create: %d", ret);
+    FAIL_EXIT1 ("pthread_create: %d", ret);
 
   /* Ensure that the thread is running properly.  */
   ret = pthread_barrier_wait (&barrier1);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier1): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier1): %d", ret);
 
   setuid_failure (2);
 
   /* Check success case. */
   if (setuid (getuid ()) != 0)
-    FAIL_ERR ("setuid (%s)", "getuid ()");
+    FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
 
   /* Shutdown.  */
   ret = pthread_barrier_wait (&barrier2);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier2): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier2): %d", ret);
 
   ret = pthread_join (thread, NULL);
   if (ret != 0)
-    FAIL ("pthread_join: %d", ret);
+    FAIL_EXIT1 ("pthread_join: %d", ret);
 
   return 0;
 }
diff --git a/sysdeps/riscv/utmp-size.h b/sysdeps/riscv/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/riscv/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/s390/wcsncmp-vx.S b/sysdeps/s390/wcsncmp-vx.S
index c518539bfa..5db0c707a1 100644
--- a/sysdeps/s390/wcsncmp-vx.S
+++ b/sysdeps/s390/wcsncmp-vx.S
@@ -59,14 +59,7 @@ ENTRY(WCSNCMP_Z13)
 	sllg	%r4,%r4,2	/* Convert character-count to byte-count.  */
 	locgrne	%r4,%r1		/* Use max byte-count, if bit 0/1 was one.  */
 
-	/* Check first character without vector load.  */
-	lghi	%r5,4		/* current_len = 4 bytes.  */
-	/* Check s1/2[0].  */
-	lt	%r0,0(%r2)
-	l	%r1,0(%r3)
-	je	.Lend_cmp_one_char
-	crjne	%r0,%r1,.Lend_cmp_one_char
-
+	lghi	%r5,0		/* current_len = 0 bytes.  */
 .Lloop:
 	vlbb	%v17,0(%r5,%r3),6 /* Load s2 to block boundary.  */
 	vlbb	%v16,0(%r5,%r2),6 /* Load s1 to block boundary.  */
@@ -167,7 +160,6 @@ ENTRY(WCSNCMP_Z13)
 	srl	%r4,2		/* And convert it to character-index.  */
 	vlgvf	%r0,%v16,0(%r4)	/* Load character-values.  */
 	vlgvf	%r1,%v17,0(%r4)
-.Lend_cmp_one_char:
 	cr	%r0,%r1
 	je	.Lend_equal
 	lghi	%r2,1
diff --git a/sysdeps/sh/bits/wordsize.h b/sysdeps/sh/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/sh/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/sh/utmp-size.h b/sysdeps/sh/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/sh/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/sparc/sparc32/bits/wordsize.h b/sysdeps/sparc/sparc32/bits/wordsize.h
index 2f66f10d72..a2e79e0fa9 100644
--- a/sysdeps/sparc/sparc32/bits/wordsize.h
+++ b/sysdeps/sparc/sparc32/bits/wordsize.h
@@ -1,11 +1,6 @@
 /* Determine the wordsize from the preprocessor defines.  */
 
-#if defined __arch64__ || defined __sparcv9
-# define __WORDSIZE	64
-# define __WORDSIZE_TIME64_COMPAT32	1
-#else
-# define __WORDSIZE	32
-# define __WORDSIZE_TIME64_COMPAT32	0
-# define __WORDSIZE32_SIZE_ULONG	0
-# define __WORDSIZE32_PTRDIFF_LONG	0
-#endif
+#define __WORDSIZE	32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG	0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/sparc/sparc32/memset.S b/sysdeps/sparc/sparc32/memset.S
index b1b67cb2d1..5154263317 100644
--- a/sysdeps/sparc/sparc32/memset.S
+++ b/sysdeps/sparc/sparc32/memset.S
@@ -55,7 +55,7 @@ ENTRY(memset)
 
 	andcc		%o0, 3, %o2
 	bne		3f
-4:	 andcc		%o0, 4, %g0
+5:	 andcc		%o0, 4, %g0
 
 	be		2f
 	 mov		%g3, %g2
@@ -139,7 +139,7 @@ ENTRY(memset)
 	stb		%g3, [%o0 + 0x02]
 2:	sub		%o2, 4, %o2
 	add		%o1, %o2, %o1
-	b		4b
+	b		5b
 	 sub		%o0, %o2, %o0
 END(memset)
 libc_hidden_builtin_def (memset)
diff --git a/sysdeps/sparc/sparc64/bits/wordsize.h b/sysdeps/sparc/sparc64/bits/wordsize.h
index 2f66f10d72..ea103e5970 100644
--- a/sysdeps/sparc/sparc64/bits/wordsize.h
+++ b/sysdeps/sparc/sparc64/bits/wordsize.h
@@ -2,10 +2,9 @@
 
 #if defined __arch64__ || defined __sparcv9
 # define __WORDSIZE	64
-# define __WORDSIZE_TIME64_COMPAT32	1
 #else
 # define __WORDSIZE	32
-# define __WORDSIZE_TIME64_COMPAT32	0
 # define __WORDSIZE32_SIZE_ULONG	0
 # define __WORDSIZE32_PTRDIFF_LONG	0
 #endif
+#define __WORDSIZE_TIME64_COMPAT32	1
diff --git a/sysdeps/sparc/sparc64/memmove.S b/sysdeps/sparc/sparc64/memmove.S
index 8d46f2cd4e..7746684160 100644
--- a/sysdeps/sparc/sparc64/memmove.S
+++ b/sysdeps/sparc/sparc64/memmove.S
@@ -38,7 +38,7 @@ ENTRY(memmove)
 /*
  * normal, copy forwards
  */
-2:	ble	%XCC, .Ldbytecp
+2:	bleu	%XCC, .Ldbytecp
 	 andcc	%o1, 3, %o5	/* is src word aligned  */
 	bz,pn	%icc, .Laldst
 	 cmp	%o5, 2		/* is src half-word aligned  */
diff --git a/sysdeps/sparc/sysdep.h b/sysdeps/sparc/sysdep.h
index 95068071cc..baab6817a6 100644
--- a/sysdeps/sparc/sysdep.h
+++ b/sysdeps/sparc/sysdep.h
@@ -76,6 +76,15 @@ C_LABEL(name)				\
 	cfi_endproc;			\
 	.size name, . - name
 
+#define ENTRY_NOCFI(name)			\
+	.align	4;			\
+	.global	C_SYMBOL_NAME(name);	\
+	.type	name, @function;	\
+C_LABEL(name)
+
+#define END_NOCFI(name)			\
+	.size name, . - name
+
 #undef LOC
 #define LOC(name)  .L##name
 
diff --git a/sysdeps/sparc/utmp-size.h b/sysdeps/sparc/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/sparc/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index a139a16532..d92ea7a1f3 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -131,6 +131,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
   tst-pidfd \
   tst-process_mrelease \
   tst-mount \
+  tst-linux-mremap1 \
   # tests
 
 # process_madvise requires CAP_SYS_ADMIN.
@@ -265,6 +266,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
 	  < /dev/null > $@ 2>&1; $(evaluate-test)
 $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
 
+tests-special += $(objpfx)tst-mount-compile.out
+$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py
+	$(sysdeps-linux-python) \
+	  ../sysdeps/unix/sysv/linux/tst-mount-compile.py \
+	    $(sysdeps-linux-python-cc) \
+	  < /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps)
+
 tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0
 
 endif # $(subdir) == misc
@@ -354,6 +363,8 @@ sysdep_headers += netinet/if_fddi.h netinet/if_tr.h \
 		  netrom/netrom.h netpacket/packet.h netrose/rose.h \
 		  neteconet/ec.h netiucv/iucv.h
 sysdep_routines += netlink_assert_response
+
+CFLAGS-check_pf.c += -fexceptions
 endif
 
 # Don't compile the ctype glue code, since there is no old non-GNU C library.
@@ -392,6 +403,7 @@ endif
 
 ifeq ($(subdir),elf)
 sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir
+dl-routines += dl-rseq-symbols
 
 libof-lddlibc4 = lddlibc4
 
diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
index 616239bb84..b7ffea84e5 100644
--- a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
+++ b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
@@ -78,3 +78,24 @@
 #define HWCAP2_AFP		(1 << 20)
 #define HWCAP2_RPRES		(1 << 21)
 #define HWCAP2_MTE3		(1 << 22)
+#define HWCAP2_SME		(1 << 23)
+#define HWCAP2_SME_I16I64	(1 << 24)
+#define HWCAP2_SME_F64F64	(1 << 25)
+#define HWCAP2_SME_I8I32	(1 << 26)
+#define HWCAP2_SME_F16F32	(1 << 27)
+#define HWCAP2_SME_B16F32	(1 << 28)
+#define HWCAP2_SME_F32F32	(1 << 29)
+#define HWCAP2_SME_FA64		(1 << 30)
+#define HWCAP2_WFXT		(1UL << 31)
+#define HWCAP2_EBF16		(1UL << 32)
+#define HWCAP2_SVE_EBF16	(1UL << 33)
+#define HWCAP2_CSSC		(1UL << 34)
+#define HWCAP2_RPRFM		(1UL << 35)
+#define HWCAP2_SVE2P1		(1UL << 36)
+#define HWCAP2_SME2		(1UL << 37)
+#define HWCAP2_SME2P1		(1UL << 38)
+#define HWCAP2_SME_I16I32	(1UL << 39)
+#define HWCAP2_SME_BI32I32	(1UL << 40)
+#define HWCAP2_SME_B16B16	(1UL << 41)
+#define HWCAP2_SME_F16F16	(1UL << 42)
+#define HWCAP2_MOPS		(1UL << 43)
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index d14c0f4e1f..2543128352 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -20,6 +20,7 @@
 #include <sys/auxv.h>
 #include <elf/dl-hwcaps.h>
 #include <sys/prctl.h>
+#include <sys/utsname.h>
 
 #define DCZID_DZP_MASK (1 << 4)
 #define DCZID_BS_MASK (0xf)
@@ -38,11 +39,9 @@ struct cpu_list
 };
 
 static struct cpu_list cpu_list[] = {
-      {"falkor",	 0x510FC000},
       {"thunderxt88",	 0x430F0A10},
       {"thunderx2t99",   0x431F0AF0},
       {"thunderx2t99p1", 0x420F5160},
-      {"phecda",	 0x680F0000},
       {"ares",		 0x411FD0C0},
       {"emag",		 0x503F0001},
       {"kunpeng920", 	 0x481FD010},
@@ -61,6 +60,46 @@ get_midr_from_mcpu (const char *mcpu)
 }
 #endif
 
+#if __LINUX_KERNEL_VERSION < 0x060200
+
+/* Return true if we prefer using SVE in string ifuncs.  Old kernels disable
+   SVE after every system call which results in unnecessary traps if memcpy
+   uses SVE.  This is true for kernels between 4.15.0 and before 6.2.0, except
+   for 5.14.0 which was patched.  For these versions return false to avoid using
+   SVE ifuncs.
+   Parse the kernel version into a 24-bit kernel.major.minor value without
+   calling any library functions.  If uname() is not supported or if the version
+   format is not recognized, assume the kernel is modern and return true.  */
+
+static inline bool
+prefer_sve_ifuncs (void)
+{
+  struct utsname buf;
+  const char *p = &buf.release[0];
+  int kernel = 0;
+  int val;
+
+  if (__uname (&buf) < 0)
+    return true;
+
+  for (int shift = 16; shift >= 0; shift -= 8)
+    {
+      for (val = 0; *p >= '0' && *p <= '9'; p++)
+	val = val * 10 + *p - '0';
+      kernel |= (val & 255) << shift;
+      if (*p++ != '.')
+	break;
+    }
+
+  if (kernel >= 0x060200 || kernel == 0x050e00)
+    return true;
+  if (kernel >= 0x040f00)
+    return false;
+  return true;
+}
+
+#endif
+
 static inline void
 init_cpu_features (struct cpu_features *cpu_features)
 {
@@ -126,4 +165,14 @@ init_cpu_features (struct cpu_features *cpu_features)
 
   /* Check if SVE is supported.  */
   cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE;
+
+  cpu_features->prefer_sve_ifuncs = cpu_features->sve;
+
+#if __LINUX_KERNEL_VERSION < 0x060200
+  if (cpu_features->sve)
+    cpu_features->prefer_sve_ifuncs = prefer_sve_ifuncs ();
+#endif
+
+  /* Check if MOPS is supported.  */
+  cpu_features->mops = GLRO (dl_hwcap2) & HWCAP2_MOPS;
 }
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
index 391165a99c..d51597b923 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
@@ -47,11 +47,6 @@
 #define IS_THUNDERX2(midr) (MIDR_IMPLEMENTOR(midr) == 'C'       \
 			   && MIDR_PARTNUM(midr) == 0xaf)
 
-#define IS_FALKOR(midr) (MIDR_IMPLEMENTOR(midr) == 'Q'			      \
-                        && MIDR_PARTNUM(midr) == 0xc00)
-
-#define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h'			      \
-                        && MIDR_PARTNUM(midr) == 0x000)
 #define IS_NEOVERSE_N1(midr) (MIDR_IMPLEMENTOR(midr) == 'A'		      \
 			      && MIDR_PARTNUM(midr) == 0xd0c)
 #define IS_NEOVERSE_N2(midr) (MIDR_IMPLEMENTOR(midr) == 'A'		      \
@@ -76,6 +71,8 @@ struct cpu_features
   /* Currently, the GLIBC memory tagging tunable only defines 8 bits.  */
   uint8_t mte_state;
   bool sve;
+  bool prefer_sve_ifuncs;
+  bool mops;
 };
 
 #endif /* _CPU_FEATURES_AARCH64_H  */
diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h
index b8088cf13f..0b851b6c86 100644
--- a/sysdeps/unix/sysv/linux/alpha/brk_call.h
+++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h
@@ -21,8 +21,7 @@ __brk_call (void *addr)
 {
   unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr);
   if (result == -ENOMEM)
-    /* Mimic the default error reporting behavior.  */
-    return addr;
-  else
-    return (void *) result;
+    /* Mimic the generic error reporting behavior.  */
+    result = INTERNAL_SYSCALL_CALL (brk, 0);
+  return (void *) result;
 }
diff --git a/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h
new file mode 100644
index 0000000000..30ee6279d2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h
@@ -0,0 +1,139 @@
+/* Definition for struct stat.  Linux/arm version.
+   Copyright (C) 2020-2022 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/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H	1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
+    __dev_t st_dev;			/* Device.  */
+    unsigned short int __pad1;
+# ifndef __USE_FILE_OFFSET64
+    __ino_t st_ino;			/* File serial number.	*/
+# else
+    __ino_t __st_ino;			/* 32bit file serial number.	*/
+# endif
+    __mode_t st_mode;			/* File mode.  */
+    __nlink_t st_nlink;			/* Link count.  */
+    __uid_t st_uid;			/* User ID of the file's owner.	*/
+    __gid_t st_gid;			/* Group ID of the file's group.*/
+    __dev_t st_rdev;			/* Device number, if device.  */
+    unsigned short int __pad2;
+# ifndef __USE_FILE_OFFSET64
+    __off_t st_size;			/* Size of file, in bytes.  */
+# else
+    __off64_t st_size;			/* Size of file, in bytes.  */
+# endif
+    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+
+# ifndef __USE_FILE_OFFSET64
+    __blkcnt_t st_blocks;		/* Number 512-byte blocks allocated. */
+# else
+    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
+# endif
+# ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#  define st_mtime st_mtim.tv_sec
+#  define st_ctime st_ctim.tv_sec
+# else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
+# ifndef __USE_FILE_OFFSET64
+    unsigned long int __glibc_reserved4;
+    unsigned long int __glibc_reserved5;
+# else
+    __ino64_t st_ino;			/* File serial number.	*/
+# endif
+#endif /* __USE_TIME_BITS64  */
+  };
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+  {
+# ifdef __USE_TIME_BITS64
+#  include <bits/struct_stat_time64_helper.h>
+# else
+    __dev_t st_dev;			/* Device.  */
+    unsigned int __pad1;
+
+    __ino_t __st_ino;			/* 32bit file serial number.	*/
+    __mode_t st_mode;			/* File mode.  */
+    __nlink_t st_nlink;			/* Link count.  */
+    __uid_t st_uid;			/* User ID of the file's owner.	*/
+    __gid_t st_gid;			/* Group ID of the file's group.*/
+    __dev_t st_rdev;			/* Device number, if device.  */
+    unsigned int __pad2;
+    __off64_t st_size;			/* Size of file, in bytes.  */
+    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+
+    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
+#  ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+#  endif
+    __ino64_t st_ino;			/* File serial number.		*/
+# endif /* __USE_TIME_BITS64  */
+  };
+#endif
+
+/* Tell code we have these members.  */
+#define	_STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported.  */
+#define _STATBUF_ST_NSEC
+
+
+#endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
index 33ff88ce59..bfc674235d 100644
--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
+++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
@@ -101,7 +101,7 @@
 #endif
 
 #ifndef F_GETLK
-# ifndef __USE_FILE_OFFSET64
+# if !defined __USE_FILE_OFFSET64 && __TIMESIZE != 64
 #  define F_GETLK	5	/* Get record locking info.  */
 #  define F_SETLK	6	/* Set record locking info (non-blocking).  */
 #  define F_SETLKW	7	/* Set record locking info (blocking).  */
diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
index 4f1f810ea1..539b8d7716 100644
--- a/sysdeps/unix/sysv/linux/bits/socket.h
+++ b/sysdeps/unix/sysv/linux/bits/socket.h
@@ -307,6 +307,12 @@ struct cmsghdr
 			 + CMSG_ALIGN (sizeof (struct cmsghdr)))
 #define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
 
+/* Given a length, return the additional padding necessary such that
+   len + __CMSG_PADDING(len) == CMSG_ALIGN (len).  */
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
+                              - ((len) & (sizeof (size_t) - 1))) \
+                             & (sizeof (size_t) - 1))
+
 extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
 				      struct cmsghdr *__cmsg) __THROW;
 #ifdef __USE_EXTERN_INLINES
@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
 _EXTERN_INLINE struct cmsghdr *
 __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
 {
+  /* We may safely assume that __cmsg lies between __mhdr->msg_control and
+     __mhdr->msg_controllen because the user is required to obtain the first
+     cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
+     via CMSG_NXTHDR, setting lengths along the way.  However, we don't yet
+     trust the value of __cmsg->cmsg_len and therefore do not use it in any
+     pointer arithmetic until we check its value.  */
+
+  unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
+  unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
+
+  size_t __size_needed = sizeof (struct cmsghdr)
+                         + __CMSG_PADDING (__cmsg->cmsg_len);
+
+  /* The current header is malformed, too small to be a full header.  */
   if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
-    /* The kernel header does this so there may be a reason.  */
     return (struct cmsghdr *) 0;
 
+  /* There isn't enough space between __cmsg and the end of the buffer to
+  hold the current cmsg *and* the next one.  */
+  if (((size_t)
+         (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
+       < __size_needed)
+      || ((size_t)
+            (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
+             - __size_needed)
+          < __cmsg->cmsg_len))
+
+    return (struct cmsghdr *) 0;
+
+  /* Now, we trust cmsg_len and can use it to find the next header.  */
   __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
 			       + CMSG_ALIGN (__cmsg->cmsg_len));
-  if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
-					+ __mhdr->msg_controllen)
-      || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
-	  > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
-    /* No more entries.  */
-    return (struct cmsghdr *) 0;
   return __cmsg;
 }
 #endif	/* Use `extern inline'.  */
diff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h
index 25bd6cb638..fb11a3fba4 100644
--- a/sysdeps/unix/sysv/linux/bits/struct_stat.h
+++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h
@@ -26,37 +26,36 @@
 #include <bits/endian.h>
 #include <bits/wordsize.h>
 
-struct stat
-  {
-#ifdef __USE_TIME_BITS64
-# include <bits/struct_stat_time64_helper.h>
-#else
-    __dev_t st_dev;			/* Device.  */
-    unsigned short int __pad1;
-# ifndef __USE_FILE_OFFSET64
-    __ino_t st_ino;			/* File serial number.	*/
-# else
-    __ino_t __st_ino;			/* 32bit file serial number.	*/
+#if defined __USE_FILE_OFFSET64
+# define __field64(type, type64, name) type64 name
+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
+#  error "ino_t and off_t must both be the same type"
 # endif
-    __mode_t st_mode;			/* File mode.  */
-    __nlink_t st_nlink;			/* Link count.  */
-    __uid_t st_uid;			/* User ID of the file's owner.	*/
-    __gid_t st_gid;			/* Group ID of the file's group.*/
-    __dev_t st_rdev;			/* Device number, if device.  */
-    unsigned short int __pad2;
-# ifndef __USE_FILE_OFFSET64
-    __off_t st_size;			/* Size of file, in bytes.  */
-# else
-    __off64_t st_size;			/* Size of file, in bytes.  */
-# endif
-    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+# define __field64(type, type64, name) type name
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define __field64(type, type64, name) \
+  type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
+#else
+# define __field64(type, type64, name) \
+  int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
+#endif
 
-# ifndef __USE_FILE_OFFSET64
-    __blkcnt_t st_blocks;		/* Number 512-byte blocks allocated. */
-# else
-    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
-# endif
-# ifdef __USE_XOPEN2K8
+struct stat
+  {
+    __dev_t st_dev;		/* Device.  */
+    __field64(__ino_t, __ino64_t, st_ino);  /* File serial number. */
+    __mode_t st_mode;		/* File mode.  */
+    __nlink_t st_nlink;		/* Link count.  */
+    __uid_t st_uid;		/* User ID of the file's owner.	*/
+    __gid_t st_gid;		/* Group ID of the file's group.*/
+    __dev_t st_rdev;		/* Device number, if device.  */
+    __dev_t __pad1;
+    __field64(__off_t, __off64_t, st_size);  /* Size of file, in bytes. */
+    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
+    int __pad2;
+    __field64(__blkcnt_t, __blkcnt64_t, st_blocks);  /* 512-byte blocks */
+#ifdef __USE_XOPEN2K8
     /* Nanosecond resolution timestamps are stored in a format
        equivalent to 'struct timespec'.  This is the type used
        whenever possible but the Unix namespace rules do not allow the
@@ -66,47 +65,38 @@ struct stat
     struct timespec st_atim;		/* Time of last access.  */
     struct timespec st_mtim;		/* Time of last modification.  */
     struct timespec st_ctim;		/* Time of last status change.  */
-#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
-#  define st_mtime st_mtim.tv_sec
-#  define st_ctime st_ctim.tv_sec
-# else
+# define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+# define st_mtime st_mtim.tv_sec
+# define st_ctime st_ctim.tv_sec
+#else
     __time_t st_atime;			/* Time of last access.  */
     unsigned long int st_atimensec;	/* Nscecs of last access.  */
     __time_t st_mtime;			/* Time of last modification.  */
     unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
     __time_t st_ctime;			/* Time of last status change.  */
     unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
-# endif
-# ifndef __USE_FILE_OFFSET64
-    unsigned long int __glibc_reserved4;
-    unsigned long int __glibc_reserved5;
-# else
-    __ino64_t st_ino;			/* File serial number.	*/
-# endif
-#endif /* __USE_TIME_BITS64  */
+#endif
+    int __glibc_reserved[2];
   };
 
+#undef __field64
+
 #ifdef __USE_LARGEFILE64
 struct stat64
   {
-# ifdef __USE_TIME_BITS64
-#  include <bits/struct_stat_time64_helper.h>
-# else
-    __dev_t st_dev;			/* Device.  */
-    unsigned int __pad1;
-
-    __ino_t __st_ino;			/* 32bit file serial number.	*/
-    __mode_t st_mode;			/* File mode.  */
-    __nlink_t st_nlink;			/* Link count.  */
-    __uid_t st_uid;			/* User ID of the file's owner.	*/
-    __gid_t st_gid;			/* Group ID of the file's group.*/
-    __dev_t st_rdev;			/* Device number, if device.  */
-    unsigned int __pad2;
-    __off64_t st_size;			/* Size of file, in bytes.  */
-    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
-
-    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
-#  ifdef __USE_XOPEN2K8
+    __dev_t st_dev;		/* Device.  */
+    __ino64_t st_ino;		/* File serial number.	*/
+    __mode_t st_mode;		/* File mode.  */
+    __nlink_t st_nlink;		/* Link count.  */
+    __uid_t st_uid;		/* User ID of the file's owner.	*/
+    __gid_t st_gid;		/* Group ID of the file's group.*/
+    __dev_t st_rdev;		/* Device number, if device.  */
+    __dev_t __pad1;
+    __off64_t st_size;		/* Size of file, in bytes.  */
+    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
+    int __pad2;
+    __blkcnt64_t st_blocks;	/* Nr. 512-byte blocks allocated.  */
+#ifdef __USE_XOPEN2K8
     /* Nanosecond resolution timestamps are stored in a format
        equivalent to 'struct timespec'.  This is the type used
        whenever possible but the Unix namespace rules do not allow the
@@ -116,16 +106,15 @@ struct stat64
     struct timespec st_atim;		/* Time of last access.  */
     struct timespec st_mtim;		/* Time of last modification.  */
     struct timespec st_ctim;		/* Time of last status change.  */
-#  else
+#else
     __time_t st_atime;			/* Time of last access.  */
     unsigned long int st_atimensec;	/* Nscecs of last access.  */
     __time_t st_mtime;			/* Time of last modification.  */
     unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
     __time_t st_ctime;			/* Time of last status change.  */
     unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
-#  endif
-    __ino64_t st_ino;			/* File serial number.		*/
-# endif /* __USE_TIME_BITS64  */
+#endif
+    int __glibc_reserved[2];
   };
 #endif
 
@@ -135,5 +124,4 @@ struct stat64
 /* Nanosecond resolution time values are supported.  */
 #define _STATBUF_ST_NSEC
 
-
 #endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/bits/uio-ext.h b/sysdeps/unix/sysv/linux/bits/uio-ext.h
index 5b0dba08c5..e49b66facd 100644
--- a/sysdeps/unix/sysv/linux/bits/uio-ext.h
+++ b/sysdeps/unix/sysv/linux/bits/uio-ext.h
@@ -47,6 +47,7 @@ extern ssize_t process_vm_writev (pid_t __pid, const struct iovec *__lvec,
 #define RWF_SYNC	0x00000004 /* per-IO O_SYNC.  */
 #define RWF_NOWAIT	0x00000008 /* per-IO nonblocking mode.  */
 #define RWF_APPEND	0x00000010 /* per-IO O_APPEND.  */
+#define RWF_NOAPPEND	0x00000020 /* per-IO negation of O_APPEND */
 
 __END_DECLS
 
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index fe73fe3ba8..ca20043408 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -292,6 +292,14 @@ make_request (int fd, pid_t pid)
   return NULL;
 }
 
+#ifdef __EXCEPTIONS
+static void
+cancel_handler (void *arg __attribute__((unused)))
+{
+  /* Release the lock.  */
+  __libc_lock_unlock (lock);
+}
+#endif
 
 void
 attribute_hidden
@@ -304,6 +312,10 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
   struct cached_data *olddata = NULL;
   struct cached_data *data = NULL;
 
+#ifdef __EXCEPTIONS
+  /* Make sure that lock is released when the thread is cancelled.  */
+  __libc_cleanup_push (cancel_handler, NULL);
+#endif
   __libc_lock_lock (lock);
 
   if (cache_valid_p ())
@@ -338,6 +350,9 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
 	}
     }
 
+#ifdef __EXCEPTIONS
+  __libc_cleanup_pop (0);
+#endif
   __libc_lock_unlock (lock);
 
   if (data != NULL)
diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
index 15b7a3a925..24f72b797a 100644
--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
@@ -23,18 +23,38 @@
 struct cmsghdr *
 __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
 {
+  /* We may safely assume that cmsg lies between mhdr->msg_control and
+     mhdr->msg_controllen because the user is required to obtain the first
+     cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
+     via CMSG_NXTHDR, setting lengths along the way.  However, we don't yet
+     trust the value of cmsg->cmsg_len and therefore do not use it in any
+     pointer arithmetic until we check its value.  */
+
+  unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
+  unsigned char * cmsg_ptr = (unsigned char *) cmsg;
+
+  size_t size_needed = sizeof (struct cmsghdr)
+                       + __CMSG_PADDING (cmsg->cmsg_len);
+
+  /* The current header is malformed, too small to be a full header.  */
   if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
-    /* The kernel header does this so there may be a reason.  */
-    return NULL;
+    return (struct cmsghdr *) 0;
+
+  /* There isn't enough space between cmsg and the end of the buffer to
+  hold the current cmsg *and* the next one.  */
+  if (((size_t)
+         (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
+       < size_needed)
+      || ((size_t)
+            (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
+             - size_needed)
+          < cmsg->cmsg_len))
+
+    return (struct cmsghdr *) 0;
 
+  /* Now, we trust cmsg_len and can use it to find the next header.  */
   cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
 			     + CMSG_ALIGN (cmsg->cmsg_len));
-  if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
-				      + mhdr->msg_controllen)
-      || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
-	  > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
-    /* No more entries.  */
-    return NULL;
   return cmsg;
 }
 libc_hidden_def (__cmsg_nxthdr)
diff --git a/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
new file mode 100644
index 0000000000..f0ee455748
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
@@ -0,0 +1,135 @@
+/* Definition for struct stat.  Linux/csky version.
+   Copyright (C) 2020-2022 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/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H	1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+#if defined __USE_FILE_OFFSET64
+# define __field64(type, type64, name) type64 name
+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
+#  error "ino_t and off_t must both be the same type"
+# endif
+# define __field64(type, type64, name) type name
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define __field64(type, type64, name) \
+  type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
+#else
+# define __field64(type, type64, name) \
+  int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
+#endif
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
+    __dev_t st_dev;		/* Device.  */
+    __field64(__ino_t, __ino64_t, st_ino);  /* File serial number. */
+    __mode_t st_mode;		/* File mode.  */
+    __nlink_t st_nlink;		/* Link count.  */
+    __uid_t st_uid;		/* User ID of the file's owner.	*/
+    __gid_t st_gid;		/* Group ID of the file's group.*/
+    __dev_t st_rdev;		/* Device number, if device.  */
+    __dev_t __pad1;
+    __field64(__off_t, __off64_t, st_size);  /* Size of file, in bytes. */
+    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
+    int __pad2;
+    __field64(__blkcnt_t, __blkcnt64_t, st_blocks);  /* 512-byte blocks */
+# ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#  define st_mtime st_mtim.tv_sec
+#  define st_ctime st_ctim.tv_sec
+# else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
+    int __glibc_reserved[2];
+#endif
+  };
+
+#undef __field64
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+  {
+# ifdef __USE_TIME_BITS64
+#  include <bits/struct_stat_time64_helper.h>
+# else
+    __dev_t st_dev;		/* Device.  */
+    __ino64_t st_ino;		/* File serial number.	*/
+    __mode_t st_mode;		/* File mode.  */
+    __nlink_t st_nlink;		/* Link count.  */
+    __uid_t st_uid;		/* User ID of the file's owner.	*/
+    __gid_t st_gid;		/* Group ID of the file's group.*/
+    __dev_t st_rdev;		/* Device number, if device.  */
+    __dev_t __pad1;
+    __off64_t st_size;		/* Size of file, in bytes.  */
+    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
+    int __pad2;
+    __blkcnt64_t st_blocks;	/* Nr. 512-byte blocks allocated.  */
+#  ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+#  endif
+    int __glibc_reserved[2];
+# endif
+  };
+#endif
+
+/* Tell code we have these members.  */
+#define	_STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported.  */
+#define _STATBUF_ST_NSEC
+
+#endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/dl-rseq-symbols.S b/sysdeps/unix/sysv/linux/dl-rseq-symbols.S
new file mode 100644
index 0000000000..b4bba06a99
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-rseq-symbols.S
@@ -0,0 +1,64 @@
+/* Define symbols used by rseq.
+   Copyright (C) 2024 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>
+
+#if __WORDSIZE == 64
+#define RSEQ_OFFSET_SIZE	8
+#else
+#define RSEQ_OFFSET_SIZE	4
+#endif
+
+/* Some targets define a macro to denote the zero register.  */
+#undef zero
+
+/* Define 2 symbols: '__rseq_size' is public const and '_rseq_size' (an
+   alias of '__rseq_size') is hidden and writable for internal use by the
+   dynamic linker which will initialize the value both symbols point to
+   before copy relocations take place. */
+
+	.globl	__rseq_size
+	.type	__rseq_size, %object
+	.size	__rseq_size, 4
+	.hidden _rseq_size
+	.globl	_rseq_size
+	.type	_rseq_size, %object
+	.size	_rseq_size, 4
+	.section .data.rel.ro
+	.balign 4
+__rseq_size:
+_rseq_size:
+	.zero	4
+
+/* Define 2 symbols: '__rseq_offset' is public const and '_rseq_offset' (an
+   alias of '__rseq_offset') is hidden and writable for internal use by the
+   dynamic linker which will initialize the value both symbols point to
+   before copy relocations take place. */
+
+	.globl	__rseq_offset
+	.type	__rseq_offset, %object
+	.size	__rseq_offset, RSEQ_OFFSET_SIZE
+	.hidden _rseq_offset
+	.globl	_rseq_offset
+	.type	_rseq_offset, %object
+	.size	_rseq_offset, RSEQ_OFFSET_SIZE
+	.section .data.rel.ro
+	.balign RSEQ_OFFSET_SIZE
+__rseq_offset:
+_rseq_offset:
+	.zero	RSEQ_OFFSET_SIZE
diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h
deleted file mode 100644
index fb11a3fba4..0000000000
--- a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Definition for struct stat.
-   Copyright (C) 2020-2022 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/>.  */
-
-#if !defined _SYS_STAT_H && !defined _FCNTL_H
-# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
-#endif
-
-#ifndef _BITS_STRUCT_STAT_H
-#define _BITS_STRUCT_STAT_H	1
-
-#include <bits/endian.h>
-#include <bits/wordsize.h>
-
-#if defined __USE_FILE_OFFSET64
-# define __field64(type, type64, name) type64 name
-#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
-# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
-#  error "ino_t and off_t must both be the same type"
-# endif
-# define __field64(type, type64, name) type name
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-# define __field64(type, type64, name) \
-  type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
-#else
-# define __field64(type, type64, name) \
-  int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
-#endif
-
-struct stat
-  {
-    __dev_t st_dev;		/* Device.  */
-    __field64(__ino_t, __ino64_t, st_ino);  /* File serial number. */
-    __mode_t st_mode;		/* File mode.  */
-    __nlink_t st_nlink;		/* Link count.  */
-    __uid_t st_uid;		/* User ID of the file's owner.	*/
-    __gid_t st_gid;		/* Group ID of the file's group.*/
-    __dev_t st_rdev;		/* Device number, if device.  */
-    __dev_t __pad1;
-    __field64(__off_t, __off64_t, st_size);  /* Size of file, in bytes. */
-    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
-    int __pad2;
-    __field64(__blkcnt_t, __blkcnt64_t, st_blocks);  /* 512-byte blocks */
-#ifdef __USE_XOPEN2K8
-    /* Nanosecond resolution timestamps are stored in a format
-       equivalent to 'struct timespec'.  This is the type used
-       whenever possible but the Unix namespace rules do not allow the
-       identifier 'timespec' to appear in the <sys/stat.h> header.
-       Therefore we have to handle the use of this header in strictly
-       standard-compliant sources special.  */
-    struct timespec st_atim;		/* Time of last access.  */
-    struct timespec st_mtim;		/* Time of last modification.  */
-    struct timespec st_ctim;		/* Time of last status change.  */
-# define st_atime st_atim.tv_sec	/* Backward compatibility.  */
-# define st_mtime st_mtim.tv_sec
-# define st_ctime st_ctim.tv_sec
-#else
-    __time_t st_atime;			/* Time of last access.  */
-    unsigned long int st_atimensec;	/* Nscecs of last access.  */
-    __time_t st_mtime;			/* Time of last modification.  */
-    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
-    __time_t st_ctime;			/* Time of last status change.  */
-    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
-#endif
-    int __glibc_reserved[2];
-  };
-
-#undef __field64
-
-#ifdef __USE_LARGEFILE64
-struct stat64
-  {
-    __dev_t st_dev;		/* Device.  */
-    __ino64_t st_ino;		/* File serial number.	*/
-    __mode_t st_mode;		/* File mode.  */
-    __nlink_t st_nlink;		/* Link count.  */
-    __uid_t st_uid;		/* User ID of the file's owner.	*/
-    __gid_t st_gid;		/* Group ID of the file's group.*/
-    __dev_t st_rdev;		/* Device number, if device.  */
-    __dev_t __pad1;
-    __off64_t st_size;		/* Size of file, in bytes.  */
-    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
-    int __pad2;
-    __blkcnt64_t st_blocks;	/* Nr. 512-byte blocks allocated.  */
-#ifdef __USE_XOPEN2K8
-    /* Nanosecond resolution timestamps are stored in a format
-       equivalent to 'struct timespec'.  This is the type used
-       whenever possible but the Unix namespace rules do not allow the
-       identifier 'timespec' to appear in the <sys/stat.h> header.
-       Therefore we have to handle the use of this header in strictly
-       standard-compliant sources special.  */
-    struct timespec st_atim;		/* Time of last access.  */
-    struct timespec st_mtim;		/* Time of last modification.  */
-    struct timespec st_ctim;		/* Time of last status change.  */
-#else
-    __time_t st_atime;			/* Time of last access.  */
-    unsigned long int st_atimensec;	/* Nscecs of last access.  */
-    __time_t st_mtime;			/* Time of last modification.  */
-    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
-    __time_t st_ctime;			/* Time of last status change.  */
-    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
-#endif
-    int __glibc_reserved[2];
-  };
-#endif
-
-/* Tell code we have these members.  */
-#define	_STATBUF_ST_BLKSIZE
-#define _STATBUF_ST_RDEV
-/* Nanosecond resolution time values are supported.  */
-#define _STATBUF_ST_NSEC
-
-#endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
index 064eaa08ae..4d01786120 100644
--- a/sysdeps/unix/sysv/linux/getsysstats.c
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
@@ -29,7 +29,7 @@
 #include <sys/sysinfo.h>
 #include <sysdep.h>
 
-int
+static int
 __get_nprocs_sched (void)
 {
   enum
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h
new file mode 100644
index 0000000000..38b6e13e68
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h
@@ -0,0 +1,139 @@
+/* Definition for struct stat.  Linux/hppa version.
+   Copyright (C) 2020-2022 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/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H	1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
+    __dev_t st_dev;			/* Device.  */
+    unsigned short int __pad1;
+# ifndef __USE_FILE_OFFSET64
+    __ino_t st_ino;			/* File serial number.	*/
+# else
+    __ino_t __st_ino;			/* 32bit file serial number.	*/
+# endif
+    __mode_t st_mode;			/* File mode.  */
+    __nlink_t st_nlink;			/* Link count.  */
+    __uid_t st_uid;			/* User ID of the file's owner.	*/
+    __gid_t st_gid;			/* Group ID of the file's group.*/
+    __dev_t st_rdev;			/* Device number, if device.  */
+    unsigned short int __pad2;
+# ifndef __USE_FILE_OFFSET64
+    __off_t st_size;			/* Size of file, in bytes.  */
+# else
+    __off64_t st_size;			/* Size of file, in bytes.  */
+# endif
+    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+
+# ifndef __USE_FILE_OFFSET64
+    __blkcnt_t st_blocks;		/* Number 512-byte blocks allocated. */
+# else
+    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
+# endif
+# ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#  define st_mtime st_mtim.tv_sec
+#  define st_ctime st_ctim.tv_sec
+# else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
+# ifndef __USE_FILE_OFFSET64
+    unsigned long int __glibc_reserved4;
+    unsigned long int __glibc_reserved5;
+# else
+    __ino64_t st_ino;			/* File serial number.	*/
+# endif
+#endif /* __USE_TIME_BITS64  */
+  };
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+  {
+# ifdef __USE_TIME_BITS64
+#  include <bits/struct_stat_time64_helper.h>
+# else
+    __dev_t st_dev;			/* Device.  */
+    unsigned int __pad1;
+
+    __ino_t __st_ino;			/* 32bit file serial number.	*/
+    __mode_t st_mode;			/* File mode.  */
+    __nlink_t st_nlink;			/* Link count.  */
+    __uid_t st_uid;			/* User ID of the file's owner.	*/
+    __gid_t st_gid;			/* Group ID of the file's group.*/
+    __dev_t st_rdev;			/* Device number, if device.  */
+    unsigned int __pad2;
+    __off64_t st_size;			/* Size of file, in bytes.  */
+    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+
+    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
+#  ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+#  endif
+    __ino64_t st_ino;			/* File serial number.		*/
+# endif /* __USE_TIME_BITS64  */
+  };
+#endif
+
+/* Tell code we have these members.  */
+#define	_STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported.  */
+#define _STATBUF_ST_NSEC
+
+
+#endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h b/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h
new file mode 100644
index 0000000000..6ecbfe7c86
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h
@@ -0,0 +1,21 @@
+/* Copyright (C) 1999-2024 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/>.  */
+
+#define __WORDSIZE			32
+#define __WORDSIZE_TIME64_COMPAT32	1
+#define __WORDSIZE32_SIZE_ULONG		0
+#define __WORDSIZE32_PTRDIFF_LONG	0
diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h
index 0cd21ef0fa..079612e4aa 100644
--- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h
@@ -30,3 +30,6 @@
 
 #undef __ASSUME_CLONE_DEFAULT
 #define __ASSUME_CLONE_BACKWARDS 1
+
+/* QEMU does not support set_robust_list.  */
+#undef __ASSUME_SET_ROBUST_LIST
diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h
index 87893a6757..2f50c31a8e 100644
--- a/sysdeps/unix/sysv/linux/ipc_priv.h
+++ b/sysdeps/unix/sysv/linux/ipc_priv.h
@@ -63,4 +63,10 @@ struct __old_ipc_perm
 # define __IPC_TIME64 0
 #endif
 
+#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T
+# define IPC_CTL_NEED_TRANSLATION 1
+#else
+# define IPC_CTL_NEED_TRANSLATION 0
+#endif
+
 #include <ipc_ops.h>
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
new file mode 100644
index 0000000000..1844bbaf6f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h
@@ -0,0 +1,25 @@
+/* Private libc-internal arch-specific definitions.  m68k version.
+   Copyright (C) 2022 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC_LOCK_ARCH_H
+#define _LIBC_LOCK_ARCH_H
+
+/* Linux enforces 4-bytes alignment on futex inputs.  */
+#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4)))
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c
new file mode 100644
index 0000000000..fe6c3a0dda
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c
@@ -0,0 +1,51 @@
+/* Get file status.  Linux/MIPSn64 version.
+   Copyright (C) 2022 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 <sys/stat.h>
+#include <sysdep.h>
+
+/* Different than other ABIs, mips64 has different layouts for non-LFS
+   and LFS struct stat.  */
+int
+__fstatat (int fd, const char *file, struct stat *buf, int flag)
+{
+  struct __stat64_t64 st64;
+  int r = __fstatat64_time64 (fd, file, &st64, flag);
+  if (r == 0)
+    {
+      /* Clear internal pad and reserved fields.  */
+      memset (buf, 0, sizeof (*buf));
+
+      buf->st_dev = st64.st_dev;
+      buf->st_ino = st64.st_ino;
+      buf->st_mode = st64.st_mode;
+      buf->st_nlink = st64.st_nlink;
+      buf->st_uid = st64.st_uid;
+      buf->st_gid = st64.st_gid;
+      buf->st_rdev = st64.st_rdev;
+      buf->st_size = st64.st_size;
+      buf->st_blksize = st64.st_blksize;
+      buf->st_blocks  = st64.st_blocks;
+      buf->st_atim = st64.st_atim;
+      buf->st_mtim = st64.st_mtim;
+      buf->st_ctim = st64.st_ctim;
+    }
+  return r;
+}
+
+weak_alias (__fstatat, fstatat)
diff --git a/sysdeps/unix/sysv/linux/mremap-failure.h b/sysdeps/unix/sysv/linux/mremap-failure.h
new file mode 100644
index 0000000000..c99ab30ca9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mremap-failure.h
@@ -0,0 +1,30 @@
+/* mremap failure handling.  Linux version.
+   Copyright (C) 2024 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 <support/check.h>
+
+/* Return exit value on mremap failure with errno ERR.  */
+
+static int
+mremap_failure_exit (int err)
+{
+  if (err != EINVAL)
+    return EXIT_FAILURE;
+
+  return EXIT_UNSUPPORTED;
+}
diff --git a/sysdeps/unix/sysv/linux/mremap.c b/sysdeps/unix/sysv/linux/mremap.c
index e829a29dbd..c48932e569 100644
--- a/sysdeps/unix/sysv/linux/mremap.c
+++ b/sysdeps/unix/sysv/linux/mremap.c
@@ -20,6 +20,12 @@
 #include <sysdep.h>
 #include <stdarg.h>
 #include <stddef.h>
+#include <errno.h>
+
+#define MREMAP_KNOWN_BITS \
+  (MREMAP_MAYMOVE \
+   | MREMAP_FIXED \
+   | MREMAP_DONTUNMAP)
 
 void *
 __mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
@@ -27,7 +33,13 @@ __mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
   va_list va;
   void *new_addr = NULL;
 
-  if (flags & MREMAP_FIXED)
+  if (flags & ~(MREMAP_KNOWN_BITS))
+    {
+      __set_errno (EINVAL);
+      return MAP_FAILED;
+    }
+
+  if (flags & (MREMAP_FIXED | MREMAP_DONTUNMAP))
     {
       va_start (va, flags);
       new_addr = va_arg (va, void *);
diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
index e824ebb095..2072205252 100644
--- a/sysdeps/unix/sysv/linux/msgctl.c
+++ b/sysdeps/unix/sysv/linux/msgctl.c
@@ -85,11 +85,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
 int
 __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
 {
-#if __IPC_TIME64
+#if IPC_CTL_NEED_TRANSLATION
+# if __IPC_TIME64
   struct kernel_msqid64_ds ksemid, *arg = NULL;
-#else
+# else
   msgctl_arg_t *arg;
-#endif
+# endif
+
+  /* Some applications pass the __IPC_64 flag in cmd, to invoke
+     previously unsupported commands back when there was no EINVAL
+     error checking in glibc.  Mask the flag for the switch statements
+     below.  msgctl_syscall adds back the __IPC_64 flag for the actual
+     system call.  */
+  cmd &= ~__IPC_64;
 
   switch (cmd)
     {
@@ -101,19 +109,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
     case IPC_STAT:
     case MSG_STAT:
     case MSG_STAT_ANY:
-#if __IPC_TIME64
+# if __IPC_TIME64
       if (buf != NULL)
 	{
 	  msqid64_to_kmsqid64 (buf, &ksemid);
 	  arg = &ksemid;
 	}
-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
+#  ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
       if (cmd == IPC_SET)
 	arg->msg_perm.mode *= 0x10000U;
-# endif
-#else
+#  endif
+# else
       arg = buf;
-#endif
+# endif
       break;
 
     case IPC_INFO:
@@ -137,21 +145,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
     case IPC_STAT:
     case MSG_STAT:
     case MSG_STAT_ANY:
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
       arg->msg_perm.mode >>= 16;
-#else
+# else
       /* Old Linux kernel versions might not clear the mode padding.  */
       if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
           != sizeof (__kernel_mode_t))
 	arg->msg_perm.mode &= 0xFFFF;
-#endif
+# endif
 
-#if __IPC_TIME64
+# if __IPC_TIME64
       kmsqid64_to_msqid64 (arg, buf);
-#endif
+# endif
     }
 
   return ret;
+
+#else /* !IPC_CTL_NEED_TRANSLATION */
+  return msgctl_syscall (msqid, cmd, buf);
+#endif
 }
 #if __TIMESIZE != 64
 libc_hidden_def (__msgctl64)
diff --git a/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h
new file mode 100644
index 0000000000..e00e71173e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h
@@ -0,0 +1,135 @@
+/* Definition for struct stat.  Linux/nios2 version.
+   Copyright (C) 2020-2022 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/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H	1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+#if defined __USE_FILE_OFFSET64
+# define __field64(type, type64, name) type64 name
+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
+#  error "ino_t and off_t must both be the same type"
+# endif
+# define __field64(type, type64, name) type name
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define __field64(type, type64, name) \
+  type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
+#else
+# define __field64(type, type64, name) \
+  int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
+#endif
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
+    __dev_t st_dev;		/* Device.  */
+    __field64(__ino_t, __ino64_t, st_ino);  /* File serial number. */
+    __mode_t st_mode;		/* File mode.  */
+    __nlink_t st_nlink;		/* Link count.  */
+    __uid_t st_uid;		/* User ID of the file's owner.	*/
+    __gid_t st_gid;		/* Group ID of the file's group.*/
+    __dev_t st_rdev;		/* Device number, if device.  */
+    __dev_t __pad1;
+    __field64(__off_t, __off64_t, st_size);  /* Size of file, in bytes. */
+    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
+    int __pad2;
+    __field64(__blkcnt_t, __blkcnt64_t, st_blocks);  /* 512-byte blocks */
+# ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#  define st_mtime st_mtim.tv_sec
+#  define st_ctime st_ctim.tv_sec
+# else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
+    int __glibc_reserved[2];
+#endif
+  };
+
+#undef __field64
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+  {
+# ifdef __USE_TIME_BITS64
+#  include <bits/struct_stat_time64_helper.h>
+# else
+    __dev_t st_dev;		/* Device.  */
+    __ino64_t st_ino;		/* File serial number.	*/
+    __mode_t st_mode;		/* File mode.  */
+    __nlink_t st_nlink;		/* Link count.  */
+    __uid_t st_uid;		/* User ID of the file's owner.	*/
+    __gid_t st_gid;		/* Group ID of the file's group.*/
+    __dev_t st_rdev;		/* Device number, if device.  */
+    __dev_t __pad1;
+    __off64_t st_size;		/* Size of file, in bytes.  */
+    __blksize_t st_blksize;	/* Optimal block size for I/O.  */
+    int __pad2;
+    __blkcnt64_t st_blocks;	/* Nr. 512-byte blocks allocated.  */
+#  ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+#  endif
+    int __glibc_reserved[2];
+# endif
+  };
+#endif
+
+/* Tell code we have these members.  */
+#define	_STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported.  */
+#define _STATBUF_ST_NSEC
+
+#endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
index a263d294b1..cf35c8bfc9 100644
--- a/sysdeps/unix/sysv/linux/not-cancel.h
+++ b/sysdeps/unix/sysv/linux/not-cancel.h
@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
   INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt);
 }
 
-static inline int
+static inline ssize_t
 __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
 {
   return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags);
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
index d7cf158b33..0ca6e69ee9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
@@ -33,6 +33,12 @@
 # define __O_LARGEFILE	0200000
 #endif
 
+#if __WORDSIZE == 64 && !defined __USE_FILE_OFFSET64
+# define F_GETLK	5
+# define F_SETLK	6
+# define F_SETLKW	7
+#endif
+
 struct flock
   {
     short int l_type;	/* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK.	*/
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h b/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h
index 04ca9debf0..6993fb6b29 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h
@@ -2,10 +2,9 @@
 
 #if defined __powerpc64__
 # define __WORDSIZE	64
-# define __WORDSIZE_TIME64_COMPAT32	1
 #else
 # define __WORDSIZE	32
-# define __WORDSIZE_TIME64_COMPAT32	0
 # define __WORDSIZE32_SIZE_ULONG	0
 # define __WORDSIZE32_PTRDIFF_LONG	0
 #endif
+#define __WORDSIZE_TIME64_COMPAT32	1
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
index bf4be80f8d..202520ee25 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
@@ -122,6 +122,7 @@
 #define __NR_mbind 235
 #define __NR_membarrier 283
 #define __NR_memfd_create 279
+#define __NR_memfd_secret 447
 #define __NR_migrate_pages 238
 #define __NR_mincore 232
 #define __NR_mkdirat 34
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
index d656aedcc2..4e65f337d4 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
@@ -127,6 +127,7 @@
 #define __NR_mbind 235
 #define __NR_membarrier 283
 #define __NR_memfd_create 279
+#define __NR_memfd_secret 447
 #define __NR_migrate_pages 238
 #define __NR_mincore 232
 #define __NR_mkdirat 34
diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h
index 210f3ec566..1aa63eca67 100644
--- a/sysdeps/unix/sysv/linux/rseq-internal.h
+++ b/sysdeps/unix/sysv/linux/rseq-internal.h
@@ -25,18 +25,48 @@
 #include <stdio.h>
 #include <sys/rseq.h>
 
+/* 32 is the initially required value for the area size.  The
+   actually used rseq size may be less (20 bytes initially).  */
+#define RSEQ_AREA_SIZE_INITIAL 32
+#define RSEQ_AREA_SIZE_INITIAL_USED 20
+
+/* The variables are in .data.relro but are not yet write-protected.  */
+extern unsigned int _rseq_size attribute_hidden;
+extern ptrdiff_t _rseq_offset attribute_hidden;
+
 #ifdef RSEQ_SIG
 static inline bool
 rseq_register_current_thread (struct pthread *self, bool do_rseq)
 {
   if (do_rseq)
     {
+      unsigned int size;
+#if IS_IN (rtld)
+      /* Use the hidden symbol in ld.so.  */
+      size = _rseq_size;
+#else
+      size = __rseq_size;
+#endif
+      if (size < RSEQ_AREA_SIZE_INITIAL)
+        /* The initial implementation used only 20 bytes out of 32,
+           but still expected size 32.  */
+        size = RSEQ_AREA_SIZE_INITIAL;
+
+      /* Initialize the rseq fields that are read by the kernel on
+         registration, there is no guarantee that struct pthread is
+         cleared on all architectures.  */
+      THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_UNINITIALIZED);
+      THREAD_SETMEM (self, rseq_area.cpu_id_start, 0);
+      THREAD_SETMEM (self, rseq_area.rseq_cs, 0);
+      THREAD_SETMEM (self, rseq_area.flags, 0);
+
       int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area,
-                                       sizeof (self->rseq_area),
-                                       0, RSEQ_SIG);
+                                       size, 0, RSEQ_SIG);
       if (!INTERNAL_SYSCALL_ERROR_P (ret))
         return true;
     }
+  /* When rseq is disabled by tunables or the registration fails, inform
+     userspace by setting 'cpu_id' to RSEQ_CPU_ID_REGISTRATION_FAILED.  */
   THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED);
   return false;
 }
diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c
index 5c3301004c..3a2f712386 100644
--- a/sysdeps/unix/sysv/linux/sched_getcpu.c
+++ b/sysdeps/unix/sysv/linux/sched_getcpu.c
@@ -33,17 +33,9 @@ vsyscall_sched_getcpu (void)
   return r == -1 ? r : cpu;
 }
 
-#ifdef RSEQ_SIG
 int
 sched_getcpu (void)
 {
   int cpu_id = THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id);
   return __glibc_likely (cpu_id >= 0) ? cpu_id : vsyscall_sched_getcpu ();
 }
-#else /* RSEQ_SIG */
-int
-sched_getcpu (void)
-{
-  return vsyscall_sched_getcpu ();
-}
-#endif /* RSEQ_SIG */
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
index 77a8130c18..3458b018bc 100644
--- a/sysdeps/unix/sysv/linux/semctl.c
+++ b/sysdeps/unix/sysv/linux/semctl.c
@@ -140,6 +140,13 @@ __semctl64 (int semid, int semnum, int cmd, ...)
   union semun64 arg64 = { 0 };
   va_list ap;
 
+  /* Some applications pass the __IPC_64 flag in cmd, to invoke
+     previously unsupported commands back when there was no EINVAL
+     error checking in glibc.  Mask the flag for the switch statements
+     below.  semctl_syscall adds back the __IPC_64 flag for the actual
+     system call.  */
+  cmd &= ~__IPC_64;
+
   /* Get the argument only if required.  */
   switch (cmd)
     {
diff --git a/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h
new file mode 100644
index 0000000000..0f7c9cdc89
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h
@@ -0,0 +1,139 @@
+/* Definition for struct stat.  Linux/sh version.
+   Copyright (C) 2020-2022 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/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H	1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#else
+    __dev_t st_dev;			/* Device.  */
+    unsigned short int __pad1;
+# ifndef __USE_FILE_OFFSET64
+    __ino_t st_ino;			/* File serial number.	*/
+# else
+    __ino_t __st_ino;			/* 32bit file serial number.	*/
+# endif
+    __mode_t st_mode;			/* File mode.  */
+    __nlink_t st_nlink;			/* Link count.  */
+    __uid_t st_uid;			/* User ID of the file's owner.	*/
+    __gid_t st_gid;			/* Group ID of the file's group.*/
+    __dev_t st_rdev;			/* Device number, if device.  */
+    unsigned short int __pad2;
+# ifndef __USE_FILE_OFFSET64
+    __off_t st_size;			/* Size of file, in bytes.  */
+# else
+    __off64_t st_size;			/* Size of file, in bytes.  */
+# endif
+    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+
+# ifndef __USE_FILE_OFFSET64
+    __blkcnt_t st_blocks;		/* Number 512-byte blocks allocated. */
+# else
+    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
+# endif
+# ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+#  define st_mtime st_mtim.tv_sec
+#  define st_ctime st_ctim.tv_sec
+# else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
+# ifndef __USE_FILE_OFFSET64
+    unsigned long int __glibc_reserved4;
+    unsigned long int __glibc_reserved5;
+# else
+    __ino64_t st_ino;			/* File serial number.	*/
+# endif
+#endif /* __USE_TIME_BITS64  */
+  };
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+  {
+# ifdef __USE_TIME_BITS64
+#  include <bits/struct_stat_time64_helper.h>
+# else
+    __dev_t st_dev;			/* Device.  */
+    unsigned int __pad1;
+
+    __ino_t __st_ino;			/* 32bit file serial number.	*/
+    __mode_t st_mode;			/* File mode.  */
+    __nlink_t st_nlink;			/* Link count.  */
+    __uid_t st_uid;			/* User ID of the file's owner.	*/
+    __gid_t st_gid;			/* Group ID of the file's group.*/
+    __dev_t st_rdev;			/* Device number, if device.  */
+    unsigned int __pad2;
+    __off64_t st_size;			/* Size of file, in bytes.  */
+    __blksize_t st_blksize;		/* Optimal block size for I/O.  */
+
+    __blkcnt64_t st_blocks;		/* Number 512-byte blocks allocated. */
+#  ifdef __USE_XOPEN2K8
+    /* Nanosecond resolution timestamps are stored in a format
+       equivalent to 'struct timespec'.  This is the type used
+       whenever possible but the Unix namespace rules do not allow the
+       identifier 'timespec' to appear in the <sys/stat.h> header.
+       Therefore we have to handle the use of this header in strictly
+       standard-compliant sources special.  */
+    struct timespec st_atim;		/* Time of last access.  */
+    struct timespec st_mtim;		/* Time of last modification.  */
+    struct timespec st_ctim;		/* Time of last status change.  */
+#  else
+    __time_t st_atime;			/* Time of last access.  */
+    unsigned long int st_atimensec;	/* Nscecs of last access.  */
+    __time_t st_mtime;			/* Time of last modification.  */
+    unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
+    __time_t st_ctime;			/* Time of last status change.  */
+    unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+#  endif
+    __ino64_t st_ino;			/* File serial number.		*/
+# endif /* __USE_TIME_BITS64  */
+  };
+#endif
+
+/* Tell code we have these members.  */
+#define	_STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported.  */
+#define _STATBUF_ST_NSEC
+
+
+#endif /* _BITS_STRUCT_STAT_H  */
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
index ea38935497..f00817a6f6 100644
--- a/sysdeps/unix/sysv/linux/shmctl.c
+++ b/sysdeps/unix/sysv/linux/shmctl.c
@@ -85,11 +85,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
 int
 __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
 {
-#if __IPC_TIME64
+#if IPC_CTL_NEED_TRANSLATION
+# if __IPC_TIME64
   struct kernel_shmid64_ds kshmid, *arg = NULL;
-#else
+# else
   shmctl_arg_t *arg;
-#endif
+# endif
+
+  /* Some applications pass the __IPC_64 flag in cmd, to invoke
+     previously unsupported commands back when there was no EINVAL
+     error checking in glibc.  Mask the flag for the switch statements
+     below.  shmctl_syscall adds back the __IPC_64 flag for the actual
+     system call.  */
+  cmd &= ~__IPC_64;
 
   switch (cmd)
     {
@@ -103,19 +111,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
     case IPC_STAT:
     case SHM_STAT:
     case SHM_STAT_ANY:
-#if __IPC_TIME64
+# if __IPC_TIME64
       if (buf != NULL)
 	{
 	  shmid64_to_kshmid64 (buf, &kshmid);
 	  arg = &kshmid;
 	}
-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
+#  ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
       if (cmd == IPC_SET)
         arg->shm_perm.mode *= 0x10000U;
-# endif
-#else
+#  endif
+# else
       arg = buf;
-#endif
+# endif
       break;
 
     case IPC_INFO:
@@ -140,21 +148,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
       case IPC_STAT:
       case SHM_STAT:
       case SHM_STAT_ANY:
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
         arg->shm_perm.mode >>= 16;
-#else
+# else
       /* Old Linux kernel versions might not clear the mode padding.  */
       if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
 	  != sizeof (__kernel_mode_t))
 	arg->shm_perm.mode &= 0xFFFF;
-#endif
+# endif
 
-#if __IPC_TIME64
+# if __IPC_TIME64
       kshmid64_to_shmid64 (arg, buf);
-#endif
+# endif
     }
 
   return ret;
+
+#else /* !IPC_CTL_NEED_TRANSLATION */
+  return shmctl_syscall (shmid, cmd, buf);
+#endif
 }
 #if __TIMESIZE != 64
 libc_hidden_def (__shmctl64)
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h b/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h
index 7562875ee2..ea103e5970 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h
@@ -2,10 +2,9 @@
 
 #if defined __arch64__ || defined __sparcv9
 # define __WORDSIZE	64
-# define __WORDSIZE_TIME64_COMPAT32	1
 #else
 # define __WORDSIZE	32
 # define __WORDSIZE32_SIZE_ULONG	0
 # define __WORDSIZE32_PTRDIFF_LONG	0
-# define __WORDSIZE_TIME64_COMPAT32	0
 #endif
+#define __WORDSIZE_TIME64_COMPAT32	1
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S b/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S
index 2829e881eb..a1492ea59e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S
@@ -23,12 +23,15 @@
 
    [1] https://lkml.org/lkml/2016/5/27/465  */
 
-ENTRY (__rt_sigreturn_stub)
+	nop
+	nop
+
+ENTRY_NOCFI (__rt_sigreturn_stub)
 	mov	__NR_rt_sigreturn, %g1
 	ta	0x10
-END (__rt_sigreturn_stub)
+END_NOCFI (__rt_sigreturn_stub)
 
-ENTRY (__sigreturn_stub)
+ENTRY_NOCFI (__sigreturn_stub)
 	mov	__NR_sigreturn, %g1
 	ta	0x10
-END (__sigreturn_stub)
+END_NOCFI (__sigreturn_stub)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S b/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S
index ac6af95e36..23b8b93f56 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S
@@ -23,7 +23,10 @@
 
    [1] https://lkml.org/lkml/2016/5/27/465  */
 
-ENTRY (__rt_sigreturn_stub)
+	nop
+	nop
+
+ENTRY_NOCFI (__rt_sigreturn_stub)
 	mov	__NR_rt_sigreturn, %g1
 	ta	0x6d
-END (__rt_sigreturn_stub)
+END_NOCFI (__rt_sigreturn_stub)
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
index f965986ba8..19841d0738 100644
--- a/sysdeps/unix/sysv/linux/sys/mount.h
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
@@ -27,77 +27,113 @@
 #include <stddef.h>
 #include <sys/ioctl.h>
 
-#define BLOCK_SIZE	1024
+#ifdef __has_include
+# if __has_include ("linux/mount.h")
+#  include "linux/mount.h"
+# endif
+#endif
+
+
 #define BLOCK_SIZE_BITS	10
+#define BLOCK_SIZE	(1<<BLOCK_SIZE_BITS)
 
 
 /* These are the fs-independent mount-flags: up to 16 flags are
    supported  */
 enum
 {
+#undef MS_RDONLY
   MS_RDONLY = 1,		/* Mount read-only.  */
 #define MS_RDONLY	MS_RDONLY
+#undef MS_NOSUID
   MS_NOSUID = 2,		/* Ignore suid and sgid bits.  */
 #define MS_NOSUID	MS_NOSUID
+#undef MS_NODEV
   MS_NODEV = 4,			/* Disallow access to device special files.  */
 #define MS_NODEV	MS_NODEV
+#undef MS_NOEXEC
   MS_NOEXEC = 8,		/* Disallow program execution.  */
 #define MS_NOEXEC	MS_NOEXEC
+#undef MS_SYNCHRONOUS
   MS_SYNCHRONOUS = 16,		/* Writes are synced at once.  */
 #define MS_SYNCHRONOUS	MS_SYNCHRONOUS
+#undef MS_REMOUNT
   MS_REMOUNT = 32,		/* Alter flags of a mounted FS.  */
 #define MS_REMOUNT	MS_REMOUNT
+#undef MS_MANDLOCK
   MS_MANDLOCK = 64,		/* Allow mandatory locks on an FS.  */
 #define MS_MANDLOCK	MS_MANDLOCK
+#undef MS_DIRSYNC
   MS_DIRSYNC = 128,		/* Directory modifications are synchronous.  */
 #define MS_DIRSYNC	MS_DIRSYNC
+#undef MS_NOSYMFOLLOW
   MS_NOSYMFOLLOW = 256,		/* Do not follow symlinks.  */
 #define MS_NOSYMFOLLOW	MS_NOSYMFOLLOW
+#undef MS_NOATIME
   MS_NOATIME = 1024,		/* Do not update access times.  */
 #define MS_NOATIME	MS_NOATIME
+#undef MS_NODIRATIME
   MS_NODIRATIME = 2048,		/* Do not update directory access times.  */
 #define MS_NODIRATIME	MS_NODIRATIME
+#undef MS_BIND
   MS_BIND = 4096,		/* Bind directory at different place.  */
 #define MS_BIND		MS_BIND
+#undef MS_MOVE
   MS_MOVE = 8192,
 #define MS_MOVE		MS_MOVE
+#undef MS_REC
   MS_REC = 16384,
 #define MS_REC		MS_REC
+#undef MS_SILENT
   MS_SILENT = 32768,
 #define MS_SILENT	MS_SILENT
+#undef MS_POSIXACL
   MS_POSIXACL = 1 << 16,	/* VFS does not apply the umask.  */
 #define MS_POSIXACL	MS_POSIXACL
+#undef MS_UNBINDABLE
   MS_UNBINDABLE = 1 << 17,	/* Change to unbindable.  */
 #define MS_UNBINDABLE	MS_UNBINDABLE
+#undef MS_PRIVATE
   MS_PRIVATE = 1 << 18,		/* Change to private.  */
 #define MS_PRIVATE	MS_PRIVATE
+#undef MS_SLAVE
   MS_SLAVE = 1 << 19,		/* Change to slave.  */
 #define MS_SLAVE	MS_SLAVE
+#undef MS_SHARED
   MS_SHARED = 1 << 20,		/* Change to shared.  */
 #define MS_SHARED	MS_SHARED
+#undef MS_RELATIME
   MS_RELATIME = 1 << 21,	/* Update atime relative to mtime/ctime.  */
 #define MS_RELATIME	MS_RELATIME
+#undef MS_KERNMOUNT
   MS_KERNMOUNT = 1 << 22,	/* This is a kern_mount call.  */
 #define MS_KERNMOUNT	MS_KERNMOUNT
+#undef MS_I_VERSION
   MS_I_VERSION =  1 << 23,	/* Update inode I_version field.  */
 #define MS_I_VERSION	MS_I_VERSION
+#undef MS_STRICTATIME
   MS_STRICTATIME = 1 << 24,	/* Always perform atime updates.  */
 #define MS_STRICTATIME	MS_STRICTATIME
+#undef MS_LAZYTIME
   MS_LAZYTIME = 1 << 25,	/* Update the on-disk [acm]times lazily.  */
 #define MS_LAZYTIME	MS_LAZYTIME
+#undef MS_ACTIVE
   MS_ACTIVE = 1 << 30,
 #define MS_ACTIVE	MS_ACTIVE
+#undef MS_NOUSER
   MS_NOUSER = 1 << 31
 #define MS_NOUSER	MS_NOUSER
 };
 
 /* Flags that can be altered by MS_REMOUNT  */
+#undef MS_RMT_MASK
 #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
 		     |MS_LAZYTIME)
 
 
 /* Magic mount flag number. Has to be or-ed to the flag values.  */
 
+#undef MS_MGC_VAL
 #define MS_MGC_VAL 0xc0ed0000	/* Magic flag number to indicate "new" flags */
 #define MS_MGC_MSK 0xffff0000	/* Magic flag number mask */
 
@@ -106,20 +142,35 @@ enum
    is probably as bad and I don't want to create yet another include
    file.  */
 
+#undef BLKROSET
 #define BLKROSET   _IO(0x12, 93) /* Set device read-only (0 = read-write).  */
+#undef BLKROGET
 #define BLKROGET   _IO(0x12, 94) /* Get read-only status (0 = read_write).  */
+#undef BLKRRPART
 #define BLKRRPART  _IO(0x12, 95) /* Re-read partition table.  */
+#undef BLKGETSIZE
 #define BLKGETSIZE _IO(0x12, 96) /* Return device size.  */
+#undef BLKFLSBUF
 #define BLKFLSBUF  _IO(0x12, 97) /* Flush buffer cache.  */
+#undef BLKRASET
 #define BLKRASET   _IO(0x12, 98) /* Set read ahead for block device.  */
+#undef BLKRAGET
 #define BLKRAGET   _IO(0x12, 99) /* Get current read ahead setting.  */
+#undef BLKFRASET
 #define BLKFRASET  _IO(0x12,100) /* Set filesystem read-ahead.  */
+#undef BLKFRAGET
 #define BLKFRAGET  _IO(0x12,101) /* Get filesystem read-ahead.  */
+#undef BLKSECTSET
 #define BLKSECTSET _IO(0x12,102) /* Set max sectors per request.  */
+#undef BLKSECTGET
 #define BLKSECTGET _IO(0x12,103) /* Get max sectors per request.  */
+#undef BLKSSZGET
 #define BLKSSZGET  _IO(0x12,104) /* Get block device sector size.  */
+#undef BLKBSZGET
 #define BLKBSZGET  _IOR(0x12,112,size_t)
+#undef BLKBSZSET
 #define BLKBSZSET  _IOW(0x12,113,size_t)
+#undef BLKGETSIZE64
 #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size.  */
 
 
@@ -137,9 +188,6 @@ enum
 };
 
 
-/* fsopen flags.  */
-#define FSOPEN_CLOEXEC          0x00000001
-
 /* fsmount flags.  */
 #define FSMOUNT_CLOEXEC         0x00000001
 
@@ -157,6 +205,7 @@ enum
 #define MOUNT_ATTR_NOSYMFOLLOW  0x00200000 /* Do not follow symlinks.  */
 
 
+#ifndef MOUNT_ATTR_SIZE_VER0
 /* For mount_setattr.  */
 struct mount_attr
 {
@@ -165,6 +214,7 @@ struct mount_attr
   uint64_t propagation;
   uint64_t userns_fd;
 };
+#endif
 
 #define MOUNT_ATTR_SIZE_VER0    32 /* sizeof first published struct */
 
@@ -185,26 +235,31 @@ struct mount_attr
 #define FSPICK_EMPTY_PATH       0x00000008
 
 
+#ifndef FSOPEN_CLOEXEC
 /* The type of fsconfig call made.   */
 enum fsconfig_command
 {
   FSCONFIG_SET_FLAG       = 0,    /* Set parameter, supplying no value */
-#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
+# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
   FSCONFIG_SET_STRING     = 1,    /* Set parameter, supplying a string value */
-#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
+# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
   FSCONFIG_SET_BINARY     = 2,    /* Set parameter, supplying a binary blob value */
-#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
+# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
   FSCONFIG_SET_PATH       = 3,    /* Set parameter, supplying an object by path */
-#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
+# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
   FSCONFIG_SET_PATH_EMPTY = 4,    /* Set parameter, supplying an object by (empty) path */
-#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
+# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
   FSCONFIG_SET_FD         = 5,    /* Set parameter, supplying an object by fd */
-#define FSCONFIG_SET_FD FSCONFIG_SET_FD
+# define FSCONFIG_SET_FD FSCONFIG_SET_FD
   FSCONFIG_CMD_CREATE     = 6,    /* Invoke superblock creation */
-#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
+# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
   FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
-#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
+# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
 };
+#endif
+
+/* fsopen flags.  */
+#define FSOPEN_CLOEXEC          0x00000001
 
 /* open_tree flags.  */
 #define OPEN_TREE_CLONE    1         /* Clone the target tree and attach the clone */
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index 6c7b2f7011..028ad3107a 100644
--- a/sysdeps/unix/sysv/linux/syscall-names.list
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
@@ -21,8 +21,8 @@
 # This file can list all potential system calls.  The names are only
 # used if the installed kernel headers also provide them.
 
-# The list of system calls is current as of Linux 5.18.
-kernel 5.18
+# The list of system calls is current as of Linux 5.19.
+kernel 5.19
 
 FAST_atomic_update
 FAST_cmpxchg
diff --git a/sysdeps/unix/sysv/linux/tst-linux-mremap1.c b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c
new file mode 100644
index 0000000000..408e8af2ab
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c
@@ -0,0 +1,63 @@
+/* Test mremap with MREMAP_DONTUNMAP.
+   Copyright (C) 2024 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 <errno.h>
+#include <sys/mman.h>
+#include <support/xstdlib.h>
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <mremap-failure.h>
+
+static int
+do_test (void)
+{
+  size_t old_size = getpagesize ();
+  size_t new_size = old_size;
+  char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+			  MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  old_addr[0] = 1;
+  old_addr[old_size - 1] = 2;
+
+  /* Create an available 64-page mmap region.  */
+  size_t fixed_size = old_size * 64;
+  char *fixed_addr = xmmap (NULL, fixed_size, PROT_READ | PROT_WRITE,
+			    MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  xmunmap (fixed_addr, fixed_size);
+
+  /* Add 3 * pagesize.  */
+  fixed_size += 3 * old_size;
+
+  /* Test MREMAP_DONTUNMAP.  It should return FIXED_ADDR created above.  */
+  char *new_addr = mremap (old_addr, old_size, new_size,
+			   MREMAP_DONTUNMAP | MREMAP_MAYMOVE,
+			   fixed_addr);
+  if (new_addr == MAP_FAILED)
+    return mremap_failure_exit (errno);
+  TEST_VERIFY_EXIT (fixed_addr == new_addr);
+  old_addr[0] = 3;
+  old_addr[old_size - 1] = 4;
+  new_addr[0] = 1;
+  new_addr[new_size - 1] = 2;
+  xmunmap (new_addr, new_size);
+  xmunmap (old_addr, old_size);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
new file mode 100755
index 0000000000..0ec74d4e0b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-mount-compile.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python3
+# Check if glibc provided sys/mount.h can be used along related kernel
+# headers.
+# Copyright (C) 2022 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/>.
+
+import argparse
+import sys
+
+import glibcextract
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description='Check if glibc provided sys/mount.h can be '
+                    ' used along related kernel headers.')
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+
+    if glibcextract.compile_c_snippet(
+            '#include <linux/mount.h>',
+            args.cc).returncode != 0:
+        sys.exit (77)
+
+    def check(testname, snippet):
+        # Add -Werror to catch macro redefinitions and _ISOMAC to avoid
+        # internal glibc definitions.
+        r = glibcextract.compile_c_snippet(snippet, args.cc,
+                '-Werror -D_ISOMAC')
+        if r.returncode != 0:
+            print('error: test {}:\n{}'.format(testname, r.output.decode()))
+        return r.returncode
+
+    status = max(
+        check("sys/mount.h + linux/mount.h",
+              "#include <sys/mount.h>\n"
+              "#include <linux/mount.h>"),
+        check("sys/mount.h + linux/fs.h",
+              "#include <sys/mount.h>\n"
+              "#include <linux/fs.h>"),
+        check("linux/mount.h + sys/mount.h",
+              "#include <linux/mount.h>\n"
+              "#include <sys/mount.h>"),
+        check("linux/fs.h + sys/mount.h",
+              "#include <linux/fs.h>\n"
+              "#include <sys/mount.h>"))
+    sys.exit(status)
+
+if __name__ == '__main__':
+    main()
diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py
index a62f803123..be2ef2daf1 100755
--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py
@@ -33,6 +33,11 @@ def main():
                         help='C compiler (including options) to use')
     args = parser.parse_args()
 
+    if glibcextract.compile_c_snippet(
+            '#include <linux/mount.h>',
+            args.cc).returncode != 0:
+        sys.exit (77)
+
     linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
     # Constants in glibc were updated to match Linux v5.16.  When glibc
     # constants are updated this value should be updated to match the
diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
index 90cbb9be64..d732173abd 100644
--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
@@ -33,11 +33,13 @@ def main():
                         help='C compiler (including options) to use')
     args = parser.parse_args()
 
-    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
-    # Linux started to provide pidfd.h with 5.10.
-    if linux_version_headers < (5, 10):
+    if glibcextract.compile_c_snippet(
+            '#include <linux/pidfd.h>',
+            args.cc).returncode != 0:
         sys.exit (77)
-    linux_version_glibc = (5, 18)
+
+    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+    linux_version_glibc = (5, 19)
     sys.exit(glibcextract.compare_macro_consts(
                 '#include <sys/pidfd.h>\n',
                 '#include <asm/fcntl.h>\n'
diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
index 037af22290..5711d1c312 100644
--- a/sysdeps/unix/sysv/linux/tst-pidfd.c
+++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
@@ -147,8 +147,11 @@ do_test (void)
        may be denied if the process doesn't have CAP_SYS_PTRACE or
        if a LSM security_ptrace_access_check denies access.  */
     if (fd == -1 && errno == EPERM)
-      FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
-			"skipping test");
+      {
+	TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
+	FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
+			  "skipping test");
+      }
     TEST_VERIFY (fd > 0);
 
     char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
diff --git a/sysdeps/unix/sysv/linux/tst-rseq-disable.c b/sysdeps/unix/sysv/linux/tst-rseq-disable.c
index e1a2c02f78..a46b0d0562 100644
--- a/sysdeps/unix/sysv/linux/tst-rseq-disable.c
+++ b/sysdeps/unix/sysv/linux/tst-rseq-disable.c
@@ -22,6 +22,7 @@
 #include <support/xthread.h>
 #include <sysdep.h>
 #include <thread_pointer.h>
+#include <sys/rseq.h>
 #include <unistd.h>
 
 #ifdef RSEQ_SIG
diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c
index fa6a89541f..613593f7f9 100644
--- a/sysdeps/unix/sysv/linux/tst-rseq.c
+++ b/sysdeps/unix/sysv/linux/tst-rseq.c
@@ -29,6 +29,7 @@
 # include <stdlib.h>
 # include <string.h>
 # include <syscall.h>
+# include <sys/auxv.h>
 # include <thread_pointer.h>
 # include <tls.h>
 # include "tst-rseq.h"
@@ -42,7 +43,8 @@ do_rseq_main_test (void)
   TEST_COMPARE (__rseq_flags, 0);
   TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset
                == (char *) &pd->rseq_area);
-  TEST_COMPARE (__rseq_size, sizeof (pd->rseq_area));
+  /* The current implementation only supports the initial size.  */
+  TEST_COMPARE (__rseq_size, 20);
 }
 
 static void
@@ -52,6 +54,12 @@ do_rseq_test (void)
     {
       FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test");
     }
+  printf ("info: __rseq_size: %u\n", __rseq_size);
+  printf ("info: __rseq_offset: %td\n", __rseq_offset);
+  printf ("info: __rseq_flags: %u\n", __rseq_flags);
+  printf ("info: getauxval (AT_RSEQ_FEATURE_SIZE): %ld\n",
+          getauxval (AT_RSEQ_FEATURE_SIZE));
+  printf ("info: getauxval (AT_RSEQ_ALIGN): %ld\n", getauxval (AT_RSEQ_ALIGN));
   do_rseq_main_test ();
 }
 #else /* RSEQ_SIG */
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 56fd5fc805..d680a92695 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -10,38 +10,53 @@ sysdep_headers += sys/platform/x86.h bits/platform/x86.h
 CFLAGS-dl-get-cpu-features.os += $(rtld-early-cflags)
 CFLAGS-get-cpuid-feature-leaf.o += $(no-stack-protector)
 
-tests += tst-get-cpu-features tst-get-cpu-features-static \
-	 tst-cpu-features-cpuinfo tst-cpu-features-cpuinfo-static \
-	 tst-cpu-features-supports tst-cpu-features-supports-static
-tests-static += tst-get-cpu-features-static \
-		tst-cpu-features-cpuinfo-static \
-		tst-cpu-features-supports-static
+tests += \
+  tst-get-cpu-features \
+  tst-get-cpu-features-static \
+  tst-cpu-features-cpuinfo \
+  tst-cpu-features-cpuinfo-static \
+  tst-cpu-features-supports \
+  tst-cpu-features-supports-static \
+# tests
+tests-static += \
+  tst-get-cpu-features-static \
+  tst-cpu-features-cpuinfo-static \
+  tst-cpu-features-supports-static \
+# tests-static
 ifeq (yes,$(have-ifunc))
 ifeq (yes,$(have-gcc-ifunc))
 tests += \
   tst-ifunc-isa-1 \
-  tst-ifunc-isa-1-static
+  tst-ifunc-isa-1-static \
+# tests
 tests-static += \
-  tst-ifunc-isa-1-static
+  tst-ifunc-isa-1-static \
+# tests-static
 test-xfail-tst-ifunc-isa-1 = $(with-lld)
 test-xfail-tst-ifunc-isa-1-static = $(with-lld)
 ifneq ($(have-tunables),no)
 tests += \
   tst-ifunc-isa-2 \
-  tst-ifunc-isa-2-static
+  tst-ifunc-isa-2-static \
+# tests
 tests-static += \
-  tst-ifunc-isa-2-static
+  tst-ifunc-isa-2-static \
+# tests-static
 test-xfail-tst-ifunc-isa-2 = $(with-lld)
 test-xfail-tst-ifunc-isa-2-static = $(with-lld)
 endif
 endif
 endif
 ifeq (yes,$(enable-x86-isa-level))
-tests += tst-isa-level-1
-modules-names += tst-isa-level-mod-1-baseline \
-		 tst-isa-level-mod-1-v2 \
-		 tst-isa-level-mod-1-v3 \
-		 tst-isa-level-mod-1-v4 \
+tests += \
+  tst-isa-level-1 \
+# tests
+modules-names += \
+  tst-isa-level-mod-1-baseline \
+  tst-isa-level-mod-1-v2 \
+  tst-isa-level-mod-1-v3 \
+  tst-isa-level-mod-1-v4 \
+# modules-names
 
 # X86 ISA level baseline
 CFLAGS-tst-isa-level-mod-1-baseline.c += -DINCLUDE_X86_ISA_LEVEL \
@@ -72,7 +87,9 @@ endif
 endif
 
 ifeq ($(subdir),math)
-tests += tst-ldbl-nonnormal-printf
+tests += \
+ tst-ldbl-nonnormal-printf \
+# tests
 endif # $(subdir) == math
 
 ifeq ($(subdir),setjmp)
@@ -80,7 +97,9 @@ gen-as-const-headers += jmp_buf-ssp.sym
 sysdep_routines += __longjmp_cancel
 ifneq ($(enable-cet),no)
 ifneq ($(have-tunables),no)
-tests += tst-setjmp-cet
+tests += \
+  tst-setjmp-cet \
+# tests
 tst-setjmp-cet-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on
 endif
 endif
@@ -128,22 +147,47 @@ ifneq ($(enable-cet),no)
 ifeq ($(subdir),elf)
 sysdep-dl-routines += dl-cet
 
-tests += tst-cet-legacy-1 tst-cet-legacy-1a tst-cet-legacy-2 \
-	 tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4 \
-	 tst-cet-legacy-5a tst-cet-legacy-6a tst-cet-legacy-7 \
-	 tst-cet-legacy-8 tst-cet-legacy-9 tst-cet-legacy-9-static \
-	 tst-cet-legacy-10 tst-cet-legacy-10-static
-tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static
+tests += \
+  tst-cet-legacy-1 \
+  tst-cet-legacy-1a \
+  tst-cet-legacy-2 \
+  tst-cet-legacy-2a \
+  tst-cet-legacy-3 \
+  tst-cet-legacy-4 \
+  tst-cet-legacy-5a \
+  tst-cet-legacy-6a \
+  tst-cet-legacy-7 \
+  tst-cet-legacy-8 \
+  tst-cet-legacy-9 \
+  tst-cet-legacy-9-static \
+  tst-cet-legacy-10 \
+  tst-cet-legacy-10-static \
+# tests
+tests-static += \
+  tst-cet-legacy-9-static \
+  tst-cet-legacy-10-static \
+# tests-static
 tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd)
 ifneq (no,$(have-tunables))
-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \
-	 tst-cet-legacy-5b tst-cet-legacy-6b
+tests += \
+  tst-cet-legacy-4a \
+  tst-cet-legacy-4b \
+  tst-cet-legacy-4c \
+  tst-cet-legacy-5b \
+  tst-cet-legacy-6b \
+# tests
 endif
-modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \
-		 tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \
-		 tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \
-		 tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \
-		 tst-cet-legacy-mod-6c
+modules-names += \
+  tst-cet-legacy-mod-1 \
+  tst-cet-legacy-mod-2 \
+  tst-cet-legacy-mod-4 \
+  tst-cet-legacy-mod-5a \
+  tst-cet-legacy-mod-5b \
+  tst-cet-legacy-mod-5c \
+  tst-cet-legacy-mod-6a \
+  tst-cet-legacy-mod-6b \
+  tst-cet-legacy-mod-6c \
+# modules-names
 
 CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch
 CFLAGS-tst-cet-legacy-2a.c += -fcf-protection
@@ -253,7 +297,9 @@ endif
 ifeq ($(subdir),posix)
 tests += \
   tst-sysconf-cache-linesize \
-  tst-sysconf-cache-linesize-static
+  tst-sysconf-cache-linesize-static \
+# tests
 tests-static += \
-  tst-sysconf-cache-linesize-static
+  tst-sysconf-cache-linesize-static \
+# tests-static
 endif
diff --git a/sysdeps/x86/bits/wordsize.h b/sysdeps/x86/bits/wordsize.h
index 70f652bca1..3f40aa76f9 100644
--- a/sysdeps/x86/bits/wordsize.h
+++ b/sysdeps/x86/bits/wordsize.h
@@ -8,10 +8,9 @@
 #define __WORDSIZE32_PTRDIFF_LONG	0
 #endif
 
+#define __WORDSIZE_TIME64_COMPAT32 1
+
 #ifdef __x86_64__
-# define __WORDSIZE_TIME64_COMPAT32	1
 /* Both x86-64 and x32 use the 64-bit system call interface.  */
 # define __SYSCALL_WORDSIZE		64
-#else
-# define __WORDSIZE_TIME64_COMPAT32	0
 #endif
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index e9f3382108..16ee0f5b36 100644
--- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h
@@ -187,7 +187,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
 	      ++round;
 	    }
 	  /* There is no other cache information anywhere else.  */
-	  break;
+	  return -1;
 	}
       else
 	{
@@ -257,28 +257,23 @@ handle_intel (int name, const struct cpu_features *cpu_features)
 
   /* OK, we can use the CPUID instruction to get all info about the
      caches.  */
-  unsigned int cnt = 0;
-  unsigned int max = 1;
   long int result = 0;
   bool no_level_2_or_3 = false;
   bool has_level_2 = false;
+  unsigned int eax;
+  unsigned int ebx;
+  unsigned int ecx;
+  unsigned int edx;
+  __cpuid (2, eax, ebx, ecx, edx);
 
-  while (cnt++ < max)
+  /* The low byte of EAX of CPUID leaf 2 should always return 1 and it
+     should be ignored.  If it isn't 1, use CPUID leaf 4 instead.  */
+  if ((eax & 0xff) != 1)
+    return intel_check_word (name, 0xff, &has_level_2, &no_level_2_or_3,
+			     cpu_features);
+  else
     {
-      unsigned int eax;
-      unsigned int ebx;
-      unsigned int ecx;
-      unsigned int edx;
-      __cpuid (2, eax, ebx, ecx, edx);
-
-      /* The low byte of EAX in the first round contain the number of
-	 rounds we have to make.  At least one, the one we are already
-	 doing.  */
-      if (cnt == 1)
-	{
-	  max = eax & 0xff;
-	  eax &= 0xffffff00;
-	}
+      eax &= 0xffffff00;
 
       /* Process the individual registers' value.  */
       result = intel_check_word (name, eax, &has_level_2,
@@ -478,7 +473,7 @@ handle_zhaoxin (int name)
 }
 
 static void
-get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr,
+get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr,
                 long int core)
 {
   unsigned int eax;
@@ -497,6 +492,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr,
   unsigned int family = cpu_features->basic.family;
   unsigned int model = cpu_features->basic.model;
   long int shared = *shared_ptr;
+  long int shared_per_thread = *shared_per_thread_ptr;
   unsigned int threads = *threads_ptr;
   bool inclusive_cache = true;
   bool support_count_mask = true;
@@ -512,6 +508,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr,
       /* Try L2 otherwise.  */
       level  = 2;
       shared = core;
+      shared_per_thread = core;
       threads_l2 = 0;
       threads_l3 = -1;
     }
@@ -668,29 +665,27 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr,
         }
       else
         {
-intel_bug_no_cache_info:
-          /* Assume that all logical threads share the highest cache
-             level.  */
-          threads
-            = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16)
-	       & 0xff);
-        }
-
-        /* Cap usage of highest cache level to the number of supported
-           threads.  */
-        if (shared > 0 && threads > 0)
-          shared /= threads;
+	intel_bug_no_cache_info:
+	  /* Assume that all logical threads share the highest cache
+	     level.  */
+	  threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16)
+		     & 0xff);
+	}
+      /* Get per-thread size of highest level cache.  */
+      if (shared_per_thread > 0 && threads > 0)
+	shared_per_thread /= threads;
     }
 
   /* Account for non-inclusive L2 and L3 caches.  */
   if (!inclusive_cache)
     {
-      if (threads_l2 > 0)
-        core /= threads_l2;
+      long int core_per_thread = threads_l2 > 0 ? (core / threads_l2) : core;
+      shared_per_thread += core_per_thread;
       shared += core;
     }
 
   *shared_ptr = shared;
+  *shared_per_thread_ptr = shared_per_thread;
   *threads_ptr = threads;
 }
 
@@ -704,6 +699,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
   int max_cpuid_ex;
   long int data = -1;
   long int shared = -1;
+  long int shared_per_thread = -1;
   long int core = -1;
   unsigned int threads = 0;
   unsigned long int level1_icache_size = -1;
@@ -724,6 +720,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features);
       core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
       shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features);
+      shared_per_thread = shared;
 
       level1_icache_size
 	= handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features);
@@ -747,13 +744,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       level4_cache_size
 	= handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features);
 
-      get_common_cache_info (&shared, &threads, core);
+      get_common_cache_info (&shared, &shared_per_thread, &threads, core);
     }
   else if (cpu_features->basic.kind == arch_kind_zhaoxin)
     {
       data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE);
       core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE);
       shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE);
+      shared_per_thread = shared;
 
       level1_icache_size = handle_zhaoxin (_SC_LEVEL1_ICACHE_SIZE);
       level1_icache_linesize = handle_zhaoxin (_SC_LEVEL1_ICACHE_LINESIZE);
@@ -767,13 +765,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       level3_cache_assoc = handle_zhaoxin (_SC_LEVEL3_CACHE_ASSOC);
       level3_cache_linesize = handle_zhaoxin (_SC_LEVEL3_CACHE_LINESIZE);
 
-      get_common_cache_info (&shared, &threads, core);
+      get_common_cache_info (&shared, &shared_per_thread, &threads, core);
     }
   else if (cpu_features->basic.kind == arch_kind_amd)
     {
       data  = handle_amd (_SC_LEVEL1_DCACHE_SIZE);
       core = handle_amd (_SC_LEVEL2_CACHE_SIZE);
       shared = handle_amd (_SC_LEVEL3_CACHE_SIZE);
+      shared_per_thread = shared;
 
       level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE);
       level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE);
@@ -791,8 +790,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx);
 
       if (shared <= 0)
-	/* No shared L3 cache.  All we have is the L2 cache.  */
-	shared = core;
+	{
+	  /* No shared L3 cache.  All we have is the L2 cache.  */
+	  shared = core;
+	  shared_per_thread = core;
+	}
       else
 	{
 	  /* Figure out the number of logical threads that share L3.  */
@@ -816,7 +818,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
 	  /* Cap usage of highest cache level to the number of
 	     supported threads.  */
 	  if (threads > 0)
-	    shared /= threads;
+	    shared_per_thread /= threads;
 
 	  /* Get shared cache per ccx for Zen architectures.  */
 	  if (cpu_features->basic.family >= 0x17)
@@ -827,12 +829,13 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
 	      __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx);
 
 	      unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1;
-	      shared *= threads_per_ccx;
+	      shared_per_thread *= threads_per_ccx;
 	    }
 	  else
 	    {
 	      /* Account for exclusive L2 and L3 caches.  */
 	      shared += core;
+	      shared_per_thread += core;
             }
 	}
     }
@@ -850,26 +853,55 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
   cpu_features->level3_cache_linesize = level3_cache_linesize;
   cpu_features->level4_cache_size = level4_cache_size;
 
-  /* The default setting for the non_temporal threshold is 3/4 of one
-     thread's share of the chip's cache. For most Intel and AMD processors
-     with an initial release date between 2017 and 2020, a thread's typical
-     share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4
-     threshold leaves 125 KBytes to 500 KBytes of the thread's data
-     in cache after a maximum temporal copy, which will maintain
-     in cache a reasonable portion of the thread's stack and other
-     active data. If the threshold is set higher than one thread's
-     share of the cache, it has a substantial risk of negatively
-     impacting the performance of other threads running on the chip. */
-  unsigned long int non_temporal_threshold = shared * 3 / 4;
+  /* The default setting for the non_temporal threshold is 1/4 of size
+     of the chip's cache. For most Intel and AMD processors with an
+     initial release date between 2017 and 2023, a thread's typical
+     share of the cache is from 18-64MB. Using the 1/4 L3 is meant to
+     estimate the point where non-temporal stores begin out-competing
+     REP MOVSB. As well the point where the fact that non-temporal
+     stores are forced back to main memory would already occurred to the
+     majority of the lines in the copy. Note, concerns about the
+     entire L3 cache being evicted by the copy are mostly alleviated
+     by the fact that modern HW detects streaming patterns and
+     provides proper LRU hints so that the maximum thrashing
+     capped at 1/associativity. */
+  unsigned long int non_temporal_threshold = shared / 4;
+
+  /* If the computed non_temporal_threshold <= 3/4 * per-thread L3, we most
+     likely have incorrect/incomplete cache info in which case, default to
+     3/4 * per-thread L3 to avoid regressions.  */
+  unsigned long int non_temporal_threshold_lowbound
+      = shared_per_thread * 3 / 4;
+  if (non_temporal_threshold < non_temporal_threshold_lowbound)
+    non_temporal_threshold = non_temporal_threshold_lowbound;
+
+  /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run
+     a higher risk of actually thrashing the cache as they don't have a HW LRU
+     hint. As well, their performance in highly parallel situations is
+     noticeably worse.  */
+  if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+    non_temporal_threshold = non_temporal_threshold_lowbound;
+  /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of
+     'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best
+     if that operation cannot overflow. Minimum of 0x4040 (16448) because the
+     L(large_memset_4x) loops need 64-byte to cache align and enough space for
+     at least 1 iteration of 4x PAGE_SIZE unrolled loop.  Both values are
+     reflected in the manual.  */
+  unsigned long int maximum_non_temporal_threshold = SIZE_MAX >> 4;
+  unsigned long int minimum_non_temporal_threshold = 0x4040;
+  if (non_temporal_threshold < minimum_non_temporal_threshold)
+    non_temporal_threshold = minimum_non_temporal_threshold;
+  else if (non_temporal_threshold > maximum_non_temporal_threshold)
+    non_temporal_threshold = maximum_non_temporal_threshold;
 
 #if HAVE_TUNABLES
   /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8.  */
-  unsigned int minimum_rep_movsb_threshold;
+  unsigned long int minimum_rep_movsb_threshold;
 #endif
   /* NB: The default REP MOVSB threshold is 4096 * (VEC_SIZE / 16) for
      VEC_SIZE == 64 or 32.  For VEC_SIZE == 16, the default REP MOVSB
      threshold is 2048 * (VEC_SIZE / 16).  */
-  unsigned int rep_movsb_threshold;
+  unsigned long int rep_movsb_threshold;
   if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
       && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512))
     {
@@ -915,8 +947,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
     shared = tunable_size;
 
   tunable_size = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL);
-  /* NB: Ignore the default value 0.  */
-  if (tunable_size != 0)
+  if (tunable_size > minimum_non_temporal_threshold
+      && tunable_size <= maximum_non_temporal_threshold)
     non_temporal_threshold = tunable_size;
 
   tunable_size = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL);
@@ -931,14 +963,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
 
   TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX);
   TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX);
-  /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of
-     'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best
-     if that operation cannot overflow. Minimum of 0x4040 (16448) because the
-     L(large_memset_4x) loops need 64-byte to cache align and enough space for
-     at least 1 iteration of 4x PAGE_SIZE unrolled loop.  Both values are
-     reflected in the manual.  */
   TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold,
-			   0x4040, SIZE_MAX >> 4);
+			   minimum_non_temporal_threshold,
+			   maximum_non_temporal_threshold);
   TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold,
 			   minimum_rep_movsb_threshold, SIZE_MAX);
   TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,
diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h
index 1ade78ab73..5b4dd5f062 100644
--- a/sysdeps/x86/get-isa-level.h
+++ b/sysdeps/x86/get-isa-level.h
@@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features)
 	  isa_level |= GNU_PROPERTY_X86_ISA_1_V2;
 	  if (CPU_FEATURE_USABLE_P (cpu_features, AVX)
 	      && CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+	      && CPU_FEATURE_USABLE_P (cpu_features, BMI1)
+	      && CPU_FEATURE_USABLE_P (cpu_features, BMI2)
 	      && CPU_FEATURE_USABLE_P (cpu_features, F16C)
 	      && CPU_FEATURE_USABLE_P (cpu_features, FMA)
 	      && CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h
index 3c4480aba7..06f6c9663e 100644
--- a/sysdeps/x86/isa-level.h
+++ b/sysdeps/x86/isa-level.h
@@ -79,7 +79,9 @@
 /* ISA level >= 3 guaranteed includes.  */
 #define AVX_X86_ISA_LEVEL 3
 #define AVX2_X86_ISA_LEVEL 3
+#define BMI1_X86_ISA_LEVEL 3
 #define BMI2_X86_ISA_LEVEL 3
+#define LZCNT_X86_ISA_LEVEL 3
 #define MOVBE_X86_ISA_LEVEL 3
 
 /* ISA level >= 2 guaranteed includes.  */
diff --git a/sysdeps/x86/utmp-size.h b/sysdeps/x86/utmp-size.h
new file mode 100644
index 0000000000..8f21ebe1b6
--- /dev/null
+++ b/sysdeps/x86/utmp-size.h
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
index 24a6e643b0..86517573dc 100644
--- a/sysdeps/x86_64/dl-tls.c
+++ b/sysdeps/x86_64/dl-tls.c
@@ -40,9 +40,12 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
 {
   dtv_t *dtv = THREAD_DTV ();
 
-  size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
-  if (__glibc_unlikely (dtv[0].counter != gen))
-    return update_get_addr (GET_ADDR_PARAM);
+  size_t gen = atomic_load_acquire (&GL(dl_tls_generation));
+  if (__glibc_unlikely (dtv[0].counter != gen)
+      /* See comment in __tls_get_addr in elf/dl-tls.c.  */
+      && !(_dl_tls_allocate_active ()
+           && GET_ADDR_MODULE < _dl_tls_initial_modid_limit))
+    return update_get_addr (GET_ADDR_PARAM, gen);
 
   return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
 }
diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S
index 0db2cb4152..7619e743e1 100644
--- a/sysdeps/x86_64/dl-tlsdesc.S
+++ b/sysdeps/x86_64/dl-tlsdesc.S
@@ -61,7 +61,7 @@ _dl_tlsdesc_return:
 _dl_tlsdesc_undefweak:
 	_CET_ENDBR
 	movq	8(%rax), %rax
-	subq	%fs:0, %rax
+	sub	%fs:0, %RAX_LP
 	ret
 	cfi_endproc
 	.size	_dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
@@ -102,7 +102,7 @@ _dl_tlsdesc_dynamic:
 	/* Preserve call-clobbered registers that we modify.
 	   We need two scratch regs anyway.  */
 	movq	%rsi, -16(%rsp)
-	movq	%fs:DTV_OFFSET, %rsi
+	mov	%fs:DTV_OFFSET, %RSI_LP
 	movq	%rdi, -8(%rsp)
 	movq	TLSDESC_ARG(%rax), %rdi
 	movq	(%rsi), %rax
@@ -116,7 +116,7 @@ _dl_tlsdesc_dynamic:
 	addq	TLSDESC_MODOFF(%rdi), %rax
 .Lret:
 	movq	-16(%rsp), %rsi
-	subq	%fs:0, %rax
+	sub	%fs:0, %RAX_LP
 	movq	-8(%rsp), %rdi
 	ret
 .Lslow:
diff --git a/sysdeps/x86_64/ffsll.c b/sysdeps/x86_64/ffsll.c
index 842ebaeb4c..d352866d9f 100644
--- a/sysdeps/x86_64/ffsll.c
+++ b/sysdeps/x86_64/ffsll.c
@@ -26,13 +26,13 @@ int
 ffsll (long long int x)
 {
   long long int cnt;
-  long long int tmp;
 
-  asm ("bsfq %2,%0\n"		/* Count low bits in X and store in %1.  */
-       "cmoveq %1,%0\n"		/* If number was zero, use -1 as result.  */
-       : "=&r" (cnt), "=r" (tmp) : "rm" (x), "1" (-1));
+  asm ("mov $-1,%k0\n"	/* Initialize cnt to -1.  */
+       "bsf %1,%0\n"	/* Count low bits in x and store in cnt.  */
+       "inc %k0\n"	/* Increment cnt by 1.  */
+       : "=&r" (cnt) : "r" (x));
 
-  return cnt + 1;
+  return cnt;
 }
 
 #ifndef __ILP32__
diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c
index 864f4777a2..23446ff4ac 100644
--- a/sysdeps/x86_64/fpu/fraiseexcpt.c
+++ b/sysdeps/x86_64/fpu/fraiseexcpt.c
@@ -33,7 +33,7 @@ __feraiseexcept (int excepts)
       /* One example of an invalid operation is 0.0 / 0.0.  */
       float f = 0.0;
 
-      __asm__ __volatile__ ("divss %0, %0 " : : "x" (f));
+      __asm__ __volatile__ ("divss %0, %0 " : "+x" (f));
       (void) &f;
     }
 
@@ -43,7 +43,7 @@ __feraiseexcept (int excepts)
       float f = 1.0;
       float g = 0.0;
 
-      __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g));
+      __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g));
       (void) &f;
     }
 
diff --git a/sysdeps/x86_64/fpu/multiarch/Makefile b/sysdeps/x86_64/fpu/multiarch/Makefile
index 248162525b..ea81753b70 100644
--- a/sysdeps/x86_64/fpu/multiarch/Makefile
+++ b/sysdeps/x86_64/fpu/multiarch/Makefile
@@ -1,32 +1,78 @@
 ifeq ($(subdir),math)
-libm-sysdep_routines += s_floor-c s_ceil-c s_floorf-c s_ceilf-c \
-			s_rint-c s_rintf-c s_nearbyint-c s_nearbyintf-c \
-			s_roundeven-c s_roundevenf-c s_trunc-c s_truncf-c
+libm-sysdep_routines += \
+  s_ceil-c \
+  s_ceilf-c \
+  s_floor-c \
+  s_floorf-c \
+  s_rint-c \
+  s_rintf-c \
+  s_nearbyint-c \
+  s_nearbyintf-c \
+  s_roundeven-c \
+  s_roundevenf-c \
+  s_trunc-c \
+  s_truncf-c \
+# libm-sysdep_routines
 
-libm-sysdep_routines += s_ceil-sse4_1 s_ceilf-sse4_1 s_floor-sse4_1 \
-			s_floorf-sse4_1 s_nearbyint-sse4_1 \
-			s_nearbyintf-sse4_1 s_roundeven-sse4_1 \
-			s_roundevenf-sse4_1 s_rint-sse4_1 s_rintf-sse4_1 \
-			s_trunc-sse4_1 s_truncf-sse4_1
+libm-sysdep_routines += \
+  s_ceil-sse4_1 \
+  s_ceilf-sse4_1 \
+  s_floor-sse4_1 \
+  s_floorf-sse4_1 \
+  s_nearbyint-sse4_1 \
+  s_nearbyintf-sse4_1 \
+  s_roundeven-sse4_1 \
+  s_roundevenf-sse4_1 \
+  s_rint-sse4_1 \
+  s_rintf-sse4_1 \
+  s_trunc-sse4_1 \
+  s_truncf-sse4_1 \
+# libm-sysdep_routines
 
-libm-sysdep_routines += e_exp-fma e_log-fma e_pow-fma s_atan-fma \
-			e_asin-fma e_atan2-fma s_sin-fma s_tan-fma \
-			s_sincos-fma
+libm-sysdep_routines += \
+  e_asin-fma \
+  e_atan2-fma \
+  e_exp-fma \
+  e_log-fma \
+  e_log2-fma \
+  e_pow-fma \
+  s_atan-fma \
+  s_expm1-fma \
+  s_log1p-fma \
+  s_sin-fma \
+  s_sincos-fma \
+  s_tan-fma \
+# libm-sysdep_routines
 
 CFLAGS-e_asin-fma.c = -mfma -mavx2
 CFLAGS-e_atan2-fma.c = -mfma -mavx2
 CFLAGS-e_exp-fma.c = -mfma -mavx2
 CFLAGS-e_log-fma.c = -mfma -mavx2
+CFLAGS-e_log2-fma.c = -mfma -mavx2
 CFLAGS-e_pow-fma.c = -mfma -mavx2
 CFLAGS-s_atan-fma.c = -mfma -mavx2
+CFLAGS-s_expm1-fma.c = -mfma -mavx2
+CFLAGS-s_log1p-fma.c = -mfma -mavx2
 CFLAGS-s_sin-fma.c = -mfma -mavx2
 CFLAGS-s_tan-fma.c = -mfma -mavx2
 CFLAGS-s_sincos-fma.c = -mfma -mavx2
 
-libm-sysdep_routines += s_sinf-sse2 s_cosf-sse2 s_sincosf-sse2
+libm-sysdep_routines += \
+  s_cosf-sse2 \
+  s_sincosf-sse2 \
+  s_sinf-sse2 \
+# libm-sysdep_routines
 
-libm-sysdep_routines += e_exp2f-fma e_expf-fma e_log2f-fma e_logf-fma \
-			e_powf-fma s_sinf-fma s_cosf-fma s_sincosf-fma
+libm-sysdep_routines += \
+  e_exp2f-fma \
+  e_expf-fma \
+  e_log2f-fma \
+  e_logf-fma \
+  e_powf-fma \
+  s_cosf-fma \
+  s_sincosf-fma \
+  s_sinf-fma \
+# libm-sysdep_routines
 
 CFLAGS-e_exp2f-fma.c = -mfma -mavx2
 CFLAGS-e_expf-fma.c = -mfma -mavx2
@@ -37,9 +83,17 @@ CFLAGS-s_sinf-fma.c = -mfma -mavx2
 CFLAGS-s_cosf-fma.c = -mfma -mavx2
 CFLAGS-s_sincosf-fma.c = -mfma -mavx2
 
-libm-sysdep_routines += e_exp-fma4 e_log-fma4 e_pow-fma4 s_atan-fma4 \
-			e_asin-fma4 e_atan2-fma4 s_sin-fma4 s_tan-fma4 \
-			s_sincos-fma4
+libm-sysdep_routines += \
+  e_exp-fma4 \
+  e_log-fma4 \
+  e_pow-fma4 \
+  e_asin-fma4 \
+  s_atan-fma4 \
+  e_atan2-fma4 \
+  s_sin-fma4 \
+  s_sincos-fma4 \
+  s_tan-fma4 \
+# libm-sysdep_routines
 
 CFLAGS-e_asin-fma4.c = -mfma4
 CFLAGS-e_atan2-fma4.c = -mfma4
@@ -51,9 +105,15 @@ CFLAGS-s_sin-fma4.c = -mfma4
 CFLAGS-s_tan-fma4.c = -mfma4
 CFLAGS-s_sincos-fma4.c = -mfma4
 
-libm-sysdep_routines += e_exp-avx e_log-avx s_atan-avx \
-			e_atan2-avx s_sin-avx s_tan-avx \
-			s_sincos-avx
+libm-sysdep_routines += \
+  e_exp-avx \
+  e_log-avx \
+  s_atan-avx \
+  e_atan2-avx \
+  s_sin-avx \
+  s_sincos-avx \
+  s_tan-avx \
+# libm-sysdep_routines
 
 CFLAGS-e_atan2-avx.c = -msse2avx -DSSE2AVX
 CFLAGS-e_exp-avx.c = -msse2avx -DSSE2AVX
diff --git a/sysdeps/x86_64/fpu/multiarch/e_log2-fma.c b/sysdeps/x86_64/fpu/multiarch/e_log2-fma.c
new file mode 100644
index 0000000000..9fbebc1b47
--- /dev/null
+++ b/sysdeps/x86_64/fpu/multiarch/e_log2-fma.c
@@ -0,0 +1,3 @@
+#define __log2 __log2_fma
+
+#include <sysdeps/ieee754/dbl-64/e_log2.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/e_log2.c b/sysdeps/x86_64/fpu/multiarch/e_log2.c
new file mode 100644
index 0000000000..c0320caf36
--- /dev/null
+++ b/sysdeps/x86_64/fpu/multiarch/e_log2.c
@@ -0,0 +1,43 @@
+/* Multiple versions of log2.
+   Copyright (C) 2023 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 <libm-alias-double.h>
+#include <libm-alias-finite.h>
+
+extern double __redirect_log2 (double);
+
+#define SYMBOL_NAME log2
+#include "ifunc-fma.h"
+
+libc_ifunc_redirected (__redirect_log2, __log2, IFUNC_SELECTOR ());
+
+#ifdef SHARED
+__hidden_ver1 (__log2, __GI___log2, __redirect_log2)
+  __attribute__ ((visibility ("hidden")));
+
+versioned_symbol (libm, __ieee754_log2, log2, GLIBC_2_29);
+libm_alias_double_other (__log2, log2)
+#else
+libm_alias_double (__log2, log2)
+#endif
+
+strong_alias (__log2, __ieee754_log2)
+libm_alias_finite (__log2, __log2)
+
+#define __log2 __log2_sse2
+#include <sysdeps/ieee754/dbl-64/e_log2.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_expm1-fma.c b/sysdeps/x86_64/fpu/multiarch/s_expm1-fma.c
new file mode 100644
index 0000000000..3ee2bd804e
--- /dev/null
+++ b/sysdeps/x86_64/fpu/multiarch/s_expm1-fma.c
@@ -0,0 +1,10 @@
+#define __expm1 __expm1_fma
+
+/* NB: __expm1 may be expanded to __expm1_fma in the following
+   prototypes.  */
+extern long double __expm1l (long double);
+extern long double __expm1f128 (long double);
+
+#define SECTION __attribute__ ((section (".text.fma")))
+
+#include <sysdeps/ieee754/dbl-64/s_expm1.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_expm1.c b/sysdeps/x86_64/fpu/multiarch/s_expm1.c
new file mode 100644
index 0000000000..2cae83fb7f
--- /dev/null
+++ b/sysdeps/x86_64/fpu/multiarch/s_expm1.c
@@ -0,0 +1,36 @@
+/* Multiple versions of expm1.
+   Copyright (C) 2023 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 <libm-alias-double.h>
+
+extern double __redirect_expm1 (double);
+
+#define SYMBOL_NAME expm1
+#include "ifunc-fma.h"
+
+libc_ifunc_redirected (__redirect_expm1, __expm1, IFUNC_SELECTOR ());
+libm_alias_double (__expm1, expm1)
+
+#define __expm1 __expm1_sse2
+
+/* NB: __expm1 may be expanded to __expm1_sse2 in the following
+   prototypes.  */
+extern long double __expm1l (long double);
+extern long double __expm1f128 (long double);
+
+#include <sysdeps/ieee754/dbl-64/s_expm1.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_log1p-fma.c b/sysdeps/x86_64/fpu/multiarch/s_log1p-fma.c
new file mode 100644
index 0000000000..8952df8f9e
--- /dev/null
+++ b/sysdeps/x86_64/fpu/multiarch/s_log1p-fma.c
@@ -0,0 +1,4 @@
+#define __log1p __log1p_fma
+#define SECTION __attribute__ ((section (".text.fma")))
+
+#include <sysdeps/ieee754/dbl-64/s_log1p.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_log1p.c b/sysdeps/x86_64/fpu/multiarch/s_log1p.c
new file mode 100644
index 0000000000..6ce5198d6d
--- /dev/null
+++ b/sysdeps/x86_64/fpu/multiarch/s_log1p.c
@@ -0,0 +1,29 @@
+/* Multiple versions of log1p.
+   Copyright (C) 2023 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 <libm-alias-double.h>
+
+extern double __redirect_log1p (double);
+
+#define SYMBOL_NAME log1p
+#include "ifunc-fma.h"
+
+libc_ifunc_redirected (__redirect_log1p, __log1p, IFUNC_SELECTOR ());
+
+#define __log1p __log1p_sse2
+#include <sysdeps/ieee754/dbl-64/s_log1p.c>
diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h
index a57a9952f3..f2f5e8a211 100644
--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h
+++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h
@@ -36,7 +36,9 @@ IFUNC_SELECTOR (void)
   const struct cpu_features *cpu_features = __get_cpu_features ();
 
   if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+      && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI1)
       && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
+      && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT)
       && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
 				      AVX_Fast_Unaligned_Load, ))
     {
diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c
index a71444eccb..00a91123d3 100644
--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c
@@ -69,10 +69,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __memchr_evex_rtm)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, memchr,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __memchr_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, memchr,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __memchr_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -207,13 +209,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, memrchr,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, memrchr,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI2)
+				      && CPU_FEATURE_USABLE (LZCNT)),
 				     __memrchr_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
+				      && CPU_FEATURE_USABLE (LZCNT)),
 				     __memrchr_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
+				      && CPU_FEATURE_USABLE (LZCNT)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __memrchr_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -335,10 +343,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __rawmemchr_evex_rtm)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __rawmemchr_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __rawmemchr_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -448,13 +458,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, strcasecmp,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strcasecmp_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strcasecmp_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strcasecmp_avx2_rtm)
 	      X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp,
@@ -470,13 +483,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, strcasecmp_l,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strcasecmp_l_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strcasecmp_l_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strcasecmp_l_avx2_rtm)
 	      X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp_l,
@@ -562,13 +578,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, strrchr,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, strrchr,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI1)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strrchr_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI1)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strrchr_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI1)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strrchr_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -585,10 +607,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strcmp_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strcmp_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strcmp_avx2_rtm)
 	      X86_IFUNC_IMPL_ADD_V2 (array, i, strcmp,
@@ -638,13 +662,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, strncasecmp,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strncasecmp_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strncasecmp_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strncasecmp_avx2_rtm)
 	      X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp,
@@ -660,13 +687,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, strncasecmp_l,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      & CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strncasecmp_l_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strncasecmp_l_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strncasecmp_l_avx2_rtm)
 	      X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp_l,
@@ -773,13 +803,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, wcsrchr,
 				     (CPU_FEATURE_USABLE (AVX512VL)
 				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI1)
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wcsrchr_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI1)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wcsrchr_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI1)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __wcsrchr_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -796,10 +831,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wcscmp_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wcscmp_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __wcscmp_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -816,10 +853,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wcsncmp_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wcsncmp_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __wcsncmp_avx2_rtm)
 	      /* ISA V2 wrapper for GENERIC implementation because the
@@ -909,10 +948,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wmemchr_evex_rtm)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __wmemchr_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __wmemchr_avx2_rtm)
 	      /* ISA V2 wrapper for SSE2 implementation because the SSE2
@@ -1162,13 +1203,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
   IFUNC_IMPL (i, name, strncmp,
 	      X86_IFUNC_IMPL_ADD_V4 (array, i, strncmp,
 				     (CPU_FEATURE_USABLE (AVX512VL)
-				      && CPU_FEATURE_USABLE (AVX512BW)),
+				      && CPU_FEATURE_USABLE (AVX512BW)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strncmp_evex)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp,
-				     CPU_FEATURE_USABLE (AVX2),
+				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)),
 				     __strncmp_avx2)
 	      X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp,
 				     (CPU_FEATURE_USABLE (AVX2)
+				      && CPU_FEATURE_USABLE (BMI2)
 				      && CPU_FEATURE_USABLE (RTM)),
 				     __strncmp_avx2_rtm)
 	      X86_IFUNC_IMPL_ADD_V2 (array, i, strncmp,
diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
index 68646ef199..7622af259c 100644
--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
+++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
@@ -34,6 +34,7 @@ IFUNC_SELECTOR (void)
   const struct cpu_features *cpu_features = __get_cpu_features ();
 
   if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+      && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
       && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
 				      AVX_Fast_Unaligned_Load, ))
     {
diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S
index afd450d020..51bc9344f0 100644
--- a/sysdeps/x86_64/multiarch/memcmp-sse2.S
+++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S
@@ -308,7 +308,17 @@ L(ret_nonzero_vec_end_0):
 	setg	%dl
 	leal	-1(%rdx, %rdx), %eax
 #  else
-	addl	%edx, %eax
+	/* Use `addq` instead of `addl` here so that even if `rax` + `rdx`
+       is negative value of the sum will be usable as a 64-bit offset
+       (negative 32-bit numbers zero-extend to a large and often
+       out-of-bounds 64-bit offsets).  Note that `rax` + `rdx` >= 0 is
+       an invariant when `memcmp` is used correctly, but if the input
+       strings `rsi`/`rdi` are concurrently modified as the function
+       runs (there is a Data-Race) it is possible for `rax` + `rdx` to
+       be negative.  Given that there is virtually no extra to cost
+       using `addq` instead of `addl` we may as well protect the
+       data-race case.  */
+	addq	%rdx, %rax
 	movzbl	(VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx
 	movzbl	(VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rax), %eax
 	subl	%ecx, %eax
diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
index 905d0fa464..bc4053d1c5 100644
--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
+++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
@@ -301,7 +301,7 @@ L(more_2x_vec):
 	leaq	(VEC_SIZE * 4)(%rax), %LOOP_REG
 #endif
 	/* Align dst for loop.  */
-	andq	$(VEC_SIZE * -2), %LOOP_REG
+	andq	$(VEC_SIZE * -1), %LOOP_REG
 	.p2align 4
 L(loop):
 	VMOVA	%VEC(0), LOOP_4X_OFFSET(%LOOP_REG)
diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S
new file mode 100644
index 0000000000..19439c553d
--- /dev/null
+++ b/sysdeps/x86_64/multiarch/rtld-strcpy.S
@@ -0,0 +1,18 @@
+/* Copyright (C) 2022 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 "../strcpy.S"
diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c
index fdd5afe3af..9d6c9f66ba 100644
--- a/sysdeps/x86_64/multiarch/strcmp.c
+++ b/sysdeps/x86_64/multiarch/strcmp.c
@@ -45,12 +45,12 @@ IFUNC_SELECTOR (void)
   const struct cpu_features *cpu_features = __get_cpu_features ();
 
   if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+      && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
       && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
 				      AVX_Fast_Unaligned_Load, ))
     {
       if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
-	  && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
-	  && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2))
+	  && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
 	return OPTIMIZE (evex);
 
       if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S
index 0593fb303b..b9b58ef599 100644
--- a/sysdeps/x86_64/multiarch/strlen-avx2.S
+++ b/sysdeps/x86_64/multiarch/strlen-avx2.S
@@ -544,14 +544,11 @@ L(return_vzeroupper):
 L(cross_page_less_vec):
 	tzcntl	%eax, %eax
 #  ifdef USE_AS_WCSLEN
-	/* NB: Multiply length by 4 to get byte count.  */
-	sall	$2, %esi
+	/* NB: Divide by 4 to convert from byte-count to length.  */
+	shrl	$2, %eax
 #  endif
 	cmpq	%rax, %rsi
 	cmovb	%esi, %eax
-#  ifdef USE_AS_WCSLEN
-	shrl	$2, %eax
-#  endif
 	VZEROUPPER_RETURN
 # endif
 
diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c
index 4ebe4bde30..c4f8b6bbb5 100644
--- a/sysdeps/x86_64/multiarch/strncmp.c
+++ b/sysdeps/x86_64/multiarch/strncmp.c
@@ -41,12 +41,12 @@ IFUNC_SELECTOR (void)
   const struct cpu_features *cpu_features = __get_cpu_features ();
 
   if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
+      && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)
       && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
 				      AVX_Fast_Unaligned_Load, ))
     {
       if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
-	  && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
-	  && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2))
+	  && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
 	return OPTIMIZE (evex);
 
       if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
diff --git a/time/Makefile b/time/Makefile
index 470275b90c..2f4aa2d528 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -50,7 +50,7 @@ tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
 	   tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \
 	   tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \
 	   tst-settimeofday tst-itimer tst-gmtime tst-timegm \
-	   tst-timespec_get tst-timespec_getres
+	   tst-timespec_get tst-timespec_getres tst-strftime4
 
 tests-time64 := \
   tst-adjtime-time64 \
@@ -65,6 +65,7 @@ tests-time64 := \
   tst-itimer-time64 \
   tst-mktime4-time64 \
   tst-settimeofday-time64 \
+  tst-strftime4-time64 \
   tst-timegm-time64 \
   tst-timespec_get-time64 \
   tst-timespec_getres-time64 \
diff --git a/time/mktime.c b/time/mktime.c
index 494c89bf54..e9a6006710 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp,
 	 time with the right value, and use its UTC offset.
 
 	 Heuristic: probe the adjacent timestamps in both directions,
-	 looking for the desired isdst.  This should work for all real
-	 time zone histories in the tz database.  */
+	 looking for the desired isdst.  If none is found within a
+	 reasonable duration bound, assume a one-hour DST difference.
+	 This should work for all real time zone histories in the tz
+	 database.  */
+
+      /* +1 if we wanted standard time but got DST, -1 if the reverse.  */
+      int dst_difference = (isdst == 0) - (tm.tm_isdst == 0);
 
       /* Distance between probes when looking for a DST boundary.  In
 	 tzdata2003a, the shortest period of DST is 601200 seconds
@@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp,
 	 periods when probing.  */
       int stride = 601200;
 
-      /* The longest period of DST in tzdata2003a is 536454000 seconds
-	 (e.g., America/Jujuy starting 1946-10-01 01:00).  The longest
-	 period of non-DST is much longer, but it makes no real sense
-	 to search for more than a year of non-DST, so use the DST
-	 max.  */
-      int duration_max = 536454000;
+      /* In TZDB 2021e, the longest period of DST (or of non-DST), in
+	 which the DST (or adjacent DST) difference is not one hour,
+	 is 457243209 seconds: e.g., America/Cambridge_Bay with leap
+	 seconds, starting 1965-10-31 00:00 in a switch from
+	 double-daylight time (-05) to standard time (-07), and
+	 continuing to 1980-04-27 02:00 in a switch from standard time
+	 (-07) to daylight time (-06).  */
+      int duration_max = 457243209;
 
       /* Search in both directions, so the maximum distance is half
 	 the duration; add the stride to avoid off-by-1 problems.  */
@@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp,
 	      }
 	  }
 
+      /* No unusual DST offset was found nearby.  Assume one-hour DST.  */
+      t += 60 * 60 * dst_difference;
+      if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm))
+	goto offset_found;
+
       __set_errno (EOVERFLOW);
       return -1;
     }
diff --git a/time/strftime_l.c b/time/strftime_l.c
index 75554fee7c..4d7c4ea828 100644
--- a/time/strftime_l.c
+++ b/time/strftime_l.c
@@ -159,6 +159,10 @@ extern char *tzname[];
 #ifdef _LIBC
 # define tzname __tzname
 # define tzset __tzset
+
+# define time_t __time64_t
+# define __gmtime_r(t, tp) __gmtime64_r (t, tp)
+# define mktime(tp) __mktime64 (tp)
 #endif
 
 #if !HAVE_TM_GMTOFF
diff --git a/time/strptime_l.c b/time/strptime_l.c
index a3c5681fc2..f927448204 100644
--- a/time/strptime_l.c
+++ b/time/strptime_l.c
@@ -30,8 +30,10 @@
 #ifdef _LIBC
 # define HAVE_LOCALTIME_R 0
 # include "../locale/localeinfo.h"
-#endif
 
+# define time_t __time64_t
+# define __localtime_r(t, tp) __localtime64_r (t, tp)
+#endif
 
 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
 # ifdef _LIBC
diff --git a/time/tst-strftime4-time64.c b/time/tst-strftime4-time64.c
new file mode 100644
index 0000000000..4d47ee7d79
--- /dev/null
+++ b/time/tst-strftime4-time64.c
@@ -0,0 +1 @@
+#include "tst-strftime4.c"
diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c
new file mode 100644
index 0000000000..659716d0fa
--- /dev/null
+++ b/time/tst-strftime4.c
@@ -0,0 +1,52 @@
+/* Test strftime and strptime after 2038-01-19 03:14:07 UTC (bug 30053).
+   Copyright (C) 2023 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 <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  TEST_VERIFY_EXIT (setenv ("TZ", "UTC0", 1) == 0);
+  tzset ();
+  if (sizeof (time_t) > 4)
+    {
+      time_t wrap = (time_t) 2147483648LL;
+      char buf[80];
+      struct tm *tm = gmtime (&wrap);
+      TEST_VERIFY_EXIT (tm != NULL);
+      TEST_VERIFY_EXIT (strftime (buf, sizeof buf, "%s", tm) > 0);
+      puts (buf);
+      TEST_VERIFY (strcmp (buf, "2147483648") == 0);
+
+      struct tm tm2;
+      char *p = strptime (buf, "%s", &tm2);
+      TEST_VERIFY_EXIT (p != NULL && *p == '\0');
+      time_t t = mktime (&tm2);
+      printf ("%lld\n", (long long) t);
+      TEST_VERIFY (t == wrap);
+    }
+  else
+    FAIL_UNSUPPORTED ("32-bit time_t");
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/time/tzfile.c b/time/tzfile.c
index dd75848ba9..8bba4e5b8d 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -32,7 +32,7 @@
 int __use_tzfile;
 static dev_t tzfile_dev;
 static ino64_t tzfile_ino;
-static time_t tzfile_mtime;
+static __time64_t tzfile_mtime;
 
 struct ttinfo
   {
@@ -61,6 +61,10 @@ static size_t num_leaps;
 static struct leap *leaps;
 static char *tzspec;
 
+/* Used to restore the daylight variable during time conversion, as if
+   tzset had been called.  */
+static int daylight_saved;
+
 #include <endian.h>
 #include <byteswap.h>
 
@@ -438,36 +442,35 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
   if (__tzname[1] == NULL)
     __tzname[1] = __tzname[0];
 
+  daylight_saved = 0;
   if (num_transitions == 0)
     /* Use the first rule (which should also be the only one).  */
     rule_stdoff = rule_dstoff = types[0].offset;
   else
     {
-      int stdoff_set = 0, dstoff_set = 0;
-      rule_stdoff = rule_dstoff = 0;
+      rule_stdoff = 0;
+
+      /* Search for the last rule with a standard time offset.  This
+	 will be used for the global timezone variable.  */
       i = num_transitions - 1;
       do
-	{
-	  if (!stdoff_set && !types[type_idxs[i]].isdst)
-	    {
-	      stdoff_set = 1;
-	      rule_stdoff = types[type_idxs[i]].offset;
-	    }
-	  else if (!dstoff_set && types[type_idxs[i]].isdst)
-	    {
-	      dstoff_set = 1;
-	      rule_dstoff = types[type_idxs[i]].offset;
-	    }
-	  if (stdoff_set && dstoff_set)
+	if (!types[type_idxs[i]].isdst)
+	  {
+	    rule_stdoff = types[type_idxs[i]].offset;
 	    break;
-	}
+	  }
+	else
+	  daylight_saved = 1;
       while (i-- > 0);
 
-      if (!dstoff_set)
-	rule_dstoff = rule_stdoff;
+      /* Keep searching to see if there is a DST rule.  This
+	 information will be used to set the global daylight
+	 variable.  */
+      while (i-- > 0 && !daylight_saved)
+	daylight_saved = types[type_idxs[i]].isdst;
     }
 
-  __daylight = rule_stdoff != rule_dstoff;
+  __daylight = daylight_saved;
   __timezone = -rule_stdoff;
 
  done:
@@ -731,7 +734,7 @@ __tzfile_compute (__time64_t timer, int use_localtime,
 	}
 
       struct ttinfo *info = &types[i];
-      __daylight = rule_stdoff != rule_dstoff;
+      __daylight = daylight_saved;
       __timezone = -rule_stdoff;
 
       if (__tzname[0] == NULL)
diff --git a/timezone/Makefile b/timezone/Makefile
index a789c22d26..5002de39ad 100644
--- a/timezone/Makefile
+++ b/timezone/Makefile
@@ -23,7 +23,7 @@ subdir	:= timezone
 include ../Makeconfig
 
 others	:= zdump zic
-tests	:= test-tz tst-timezone tst-tzset tst-bz28707
+tests	:= test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951
 
 generated-dirs += testdata
 
@@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \
 				       Europe/London)
 $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4)
 $(objpfx)tst-bz28707.out: $(testdata)/XT5
+$(objpfx)tst-bz29951.out: $(testdata)/XT6
 
 test-tz-ENV = TZDIR=$(testdata)
 tst-timezone-ENV = TZDIR=$(testdata)
 tst-tzset-ENV = TZDIR=$(testdata)
 tst-bz28707-ENV = TZDIR=$(testdata)
+tst-bz29951-ENV = TZDIR=$(testdata)
 
 # Note this must come second in the deps list for $(built-program-cmd) to work.
 zic-deps = $(objpfx)zic $(leapseconds) yearistype
diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6
new file mode 100644
index 0000000000..07b393bb7d
Binary files /dev/null and b/timezone/testdata/XT6 differ
diff --git a/timezone/tst-bz29951.c b/timezone/tst-bz29951.c
new file mode 100644
index 0000000000..abd334683b
--- /dev/null
+++ b/timezone/tst-bz29951.c
@@ -0,0 +1,68 @@
+/* Check that daylight is set if the last DST transition did not change offset.
+   Copyright (C) 2023 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 <errno.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <time.h>
+
+/* Set the specified time zone with error checking.  */
+static void
+set_timezone (const char *name)
+{
+  TEST_VERIFY (setenv ("TZ", name, 1) == 0);
+  errno = 0;
+  tzset ();
+  TEST_COMPARE (errno, 0);
+}
+
+static int
+do_test (void)
+{
+  /* Test zone based on tz-2022g version of Africa/Tripoli.  The last
+     DST transition coincided with a change in the standard time
+     offset, effectively making it a no-op.
+
+     Africa/Tripoli  Thu Oct 24 23:59:59 2013 UT
+       = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200
+     Africa/Tripoli  Fri Oct 25 00:00:00 2013 UT
+       = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200
+   */
+  set_timezone ("XT6");
+  TEST_VERIFY (daylight != 0);
+  TEST_COMPARE (timezone, -7200);
+
+  /* Check that localtime re-initializes the two variables.  */
+  daylight = timezone = 17;
+  time_t t = 844034401;
+  struct tm *tm = localtime (&t);
+  TEST_VERIFY (daylight != 0);
+  TEST_COMPARE (timezone, -7200);
+  TEST_COMPARE (tm->tm_year, 96);
+  TEST_COMPARE (tm->tm_mon, 8);
+  TEST_COMPARE (tm->tm_mday, 29);
+  TEST_COMPARE (tm->tm_hour, 23);
+  TEST_COMPARE (tm->tm_min, 0);
+  TEST_COMPARE (tm->tm_sec, 1);
+  TEST_COMPARE (tm->tm_gmtoff, 3600);
+  TEST_COMPARE (tm->tm_isdst, 0);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile
index e6b9e8743a..4af102a3f6 100644
--- a/wcsmbs/Makefile
+++ b/wcsmbs/Makefile
@@ -22,8 +22,9 @@ subdir	:= wcsmbs
 
 include ../Makeconfig
 
-headers	:= wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \
-	   bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h
+headers	:= wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \
+	   bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \
+	   bits/types/mbstate_t.h bits/types/wint_t.h
 
 routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales)
 $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales)
 $(objpfx)tst-c16-surrogate.out: $(gen-locales)
 $(objpfx)tst-c32-state.out: $(gen-locales)
+$(objpfx)test-c8rtomb.out: $(gen-locales)
+$(objpfx)test-mbrtoc8.out: $(gen-locales)
 endif
 
 $(objpfx)tst-wcstod-round: $(libm)
diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h
new file mode 100644
index 0000000000..8e1735c33b
--- /dev/null
+++ b/wcsmbs/bits/wchar2-decl.h
@@ -0,0 +1,124 @@
+/* Checking macros for wchar functions.  Declarations only.
+   Copyright (C) 2004-2022 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/>.  */
+
+#ifndef _BITS_WCHAR2_DECL_H
+#define _BITS_WCHAR2_DECL_H 1
+
+#ifndef _WCHAR_H
+# error "Never include <bits/wchar2-decl.h> directly; use <wchar.h> instead."
+#endif
+
+
+extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
+			       const wchar_t *__restrict __s2, size_t __n,
+			       size_t __ns1) __THROW;
+extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
+				size_t __n, size_t __ns1) __THROW;
+
+
+#ifdef __USE_GNU
+
+extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
+				const wchar_t *__restrict __s2, size_t __n,
+				size_t __ns1) __THROW;
+
+#endif
+
+
+extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
+			       size_t __ns) __THROW;
+extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
+			      const wchar_t *__restrict __src,
+			      size_t __n) __THROW;
+extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
+			      const wchar_t *__restrict __src,
+			      size_t __destlen) __THROW;
+extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
+			       const wchar_t *__restrict __src, size_t __n,
+			       size_t __destlen) __THROW;
+extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
+			       const wchar_t *__restrict __src, size_t __n,
+			       size_t __destlen) __THROW;
+extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
+			      const wchar_t *__restrict __src,
+			      size_t __destlen) __THROW;
+extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
+			       const wchar_t *__restrict __src,
+			       size_t __n, size_t __destlen) __THROW;
+extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
+			   int __flag, size_t __s_len,
+			   const wchar_t *__restrict __format, ...)
+     __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
+extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
+			    int __flag, size_t __s_len,
+			    const wchar_t *__restrict __format,
+			    __gnuc_va_list __arg)
+     __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
+
+#if __USE_FORTIFY_LEVEL > 1
+
+extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
+			   const wchar_t *__restrict __format, ...);
+extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
+			  ...);
+extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
+			    const wchar_t *__restrict __format,
+			    __gnuc_va_list __ap);
+extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
+			   __gnuc_va_list __ap);
+
+#endif
+
+extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
+			      __FILE *__restrict __stream) __wur;
+
+#ifdef __USE_GNU
+
+extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
+				       int __n, __FILE *__restrict __stream)
+       __wur;
+
+#endif
+
+extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
+			     mbstate_t *__restrict __p,
+			     size_t __buflen) __THROW __wur;
+extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
+			       const char **__restrict __src,
+			       size_t __len, mbstate_t *__restrict __ps,
+			       size_t __dstlen) __THROW;
+extern size_t __wcsrtombs_chk (char *__restrict __dst,
+			       const wchar_t **__restrict __src,
+			       size_t __len, mbstate_t *__restrict __ps,
+			       size_t __dstlen) __THROW;
+
+#ifdef	__USE_XOPEN2K8
+
+extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
+				const char **__restrict __src, size_t __nmc,
+				size_t __len, mbstate_t *__restrict __ps,
+				size_t __dstlen) __THROW;
+extern size_t __wcsnrtombs_chk (char *__restrict __dst,
+				const wchar_t **__restrict __src,
+				size_t __nwc, size_t __len,
+				mbstate_t *__restrict __ps, size_t __dstlen)
+       __THROW;
+
+#endif
+
+#endif /* bits/wchar2-decl.h.  */
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
index 0e017f458b..1181d36c24 100644
--- a/wcsmbs/bits/wchar2.h
+++ b/wcsmbs/bits/wchar2.h
@@ -21,9 +21,6 @@
 #endif
 
 
-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
-			       const wchar_t *__restrict __s2, size_t __n,
-			       size_t __ns1) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias,
 				(wchar_t *__restrict __s1,
 				 const wchar_t *__restrict __s2, size_t __n),
@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
 }
 
 
-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
-				size_t __n, size_t __ns1) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1,
 						   const wchar_t *__s2,
 						   size_t __n), wmemmove);
@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
 
 
 #ifdef __USE_GNU
-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1,
-				const wchar_t *__restrict __s2, size_t __n,
-				size_t __ns1) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias,
 				(wchar_t *__restrict __s1,
 				 const wchar_t *__restrict __s2,
@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
 #endif
 
 
-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
-			       size_t __ns) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c,
 						  size_t __n), wmemset);
 extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
 }
 
 
-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
-			      const wchar_t *__restrict __src,
-			      size_t __n) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src), wcscpy);
@@ -120,16 +107,13 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
 __fortify_function wchar_t *
 __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcscpy_chk (__dest, __src, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcscpy_chk (__dest, __src, __sz / sizeof (wchar_t));
   return __wcscpy_alias (__dest, __src);
 }
 
 
-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest,
-			      const wchar_t *__restrict __src,
-			      size_t __destlen) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src), wcpcpy);
@@ -137,16 +121,13 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
 __fortify_function wchar_t *
 __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcpcpy_chk (__dest, __src, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcpcpy_chk (__dest, __src, __sz / sizeof (wchar_t));
   return __wcpcpy_alias (__dest, __src);
 }
 
 
-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest,
-			       const wchar_t *__restrict __src, size_t __n,
-			       size_t __destlen) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src,
@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
 }
 
 
-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
-			       const wchar_t *__restrict __src, size_t __n,
-			       size_t __destlen) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src,
@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
 }
 
 
-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
-			      const wchar_t *__restrict __src,
-			      size_t __destlen) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src), wcscat);
@@ -202,16 +177,13 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
 __fortify_function wchar_t *
 __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcscat_chk (__dest, __src, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcscat_chk (__dest, __src, __sz / sizeof (wchar_t));
   return __wcscat_alias (__dest, __src);
 }
 
 
-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest,
-			       const wchar_t *__restrict __src,
-			       size_t __n, size_t __destlen) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wcsncat_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src,
@@ -221,17 +193,13 @@ __fortify_function wchar_t *
 __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
 		size_t __n))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcsncat_chk (__dest, __src, __n, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcsncat_chk (__dest, __src, __n, __sz / sizeof (wchar_t));
   return __wcsncat_alias (__dest, __src, __n);
 }
 
 
-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n,
-			   int __flag, size_t __s_len,
-			   const wchar_t *__restrict __format, ...)
-     __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */;
 
 extern int __REDIRECT_NTH_LDBL (__swprintf_alias,
 				(wchar_t *__restrict __s, size_t __n,
@@ -243,10 +211,10 @@ __fortify_function int
 __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
 		 const wchar_t *__restrict __fmt, ...))
 {
-  size_t sz = __glibc_objsize (__s);
-  if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+  size_t __sz = __glibc_objsize (__s);
+  if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
     return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-			   sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
+			   __sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
   return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
 }
 #elif !defined __cplusplus
@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
    : swprintf (s, n, __VA_ARGS__))
 #endif
 
-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
-			    int __flag, size_t __s_len,
-			    const wchar_t *__restrict __format,
-			    __gnuc_va_list __arg)
-     __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
 
 extern int __REDIRECT_NTH_LDBL (__vswprintf_alias,
 				(wchar_t *__restrict __s, size_t __n,
@@ -273,26 +236,16 @@ __fortify_function int
 __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
 		  const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
 {
-  size_t sz = __glibc_objsize (__s);
-  if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+  size_t __sz = __glibc_objsize (__s);
+  if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
     return __vswprintf_chk (__s, __n,  __USE_FORTIFY_LEVEL - 1,
-			    sz / sizeof (wchar_t), __fmt, __ap);
+			    __sz / sizeof (wchar_t), __fmt, __ap);
   return __vswprintf_alias (__s, __n, __fmt, __ap);
 }
 
 
 #if __USE_FORTIFY_LEVEL > 1
 
-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag,
-			   const wchar_t *__restrict __format, ...);
-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format,
-			  ...);
-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
-			    const wchar_t *__restrict __format,
-			    __gnuc_va_list __ap);
-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
-			   __gnuc_va_list __ap);
-
 # ifdef __va_arg_pack
 __fortify_function int
 wprintf (const wchar_t *__restrict __fmt, ...)
@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream,
 
 #endif
 
-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
-			      __FILE *__restrict __stream) __wur;
 extern wchar_t *__REDIRECT (__fgetws_alias,
 			    (wchar_t *__restrict __s, int __n,
 			     __FILE *__restrict __stream), fgetws) __wur;
@@ -342,18 +293,15 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn,
 __fortify_function __wur wchar_t *
 fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
     return __fgetws_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
-    return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
-  return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+  if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
+    return __fgetws_chk_warn (__s, __sz / sizeof (wchar_t), __n, __stream);
+  return __fgetws_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
 }
 
 #ifdef __USE_GNU
-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
-				       int __n, __FILE *__restrict __stream)
-  __wur;
 extern wchar_t *__REDIRECT (__fgetws_unlocked_alias,
 			    (wchar_t *__restrict __s, int __n,
 			     __FILE *__restrict __stream), fgetws_unlocked)
@@ -368,20 +316,17 @@ extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn,
 __fortify_function __wur wchar_t *
 fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
     return __fgetws_unlocked_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
-    return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
+  if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
+    return __fgetws_unlocked_chk_warn (__s, __sz / sizeof (wchar_t), __n,
 				       __stream);
-  return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+  return __fgetws_unlocked_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
 }
 #endif
 
 
-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar,
-			     mbstate_t *__restrict __p,
-			     size_t __buflen) __THROW __wur;
 extern size_t __REDIRECT_NTH (__wcrtomb_alias,
 			      (char *__restrict __s, wchar_t __wchar,
 			       mbstate_t *__restrict __ps), wcrtomb) __wur;
@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
 }
 
 
-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst,
-			       const char **__restrict __src,
-			       size_t __len, mbstate_t *__restrict __ps,
-			       size_t __dstlen) __THROW;
 extern size_t __REDIRECT_NTH (__mbsrtowcs_alias,
 			      (wchar_t *__restrict __dst,
 			       const char **__restrict __src,
@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
 }
 
 
-extern size_t __wcsrtombs_chk (char *__restrict __dst,
-			       const wchar_t **__restrict __src,
-			       size_t __len, mbstate_t *__restrict __ps,
-			       size_t __dstlen) __THROW;
 extern size_t __REDIRECT_NTH (__wcsrtombs_alias,
 			      (char *__restrict __dst,
 			       const wchar_t **__restrict __src,
@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
 
 
 #ifdef	__USE_XOPEN2K8
-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst,
-				const char **__restrict __src, size_t __nmc,
-				size_t __len, mbstate_t *__restrict __ps,
-				size_t __dstlen) __THROW;
 extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias,
 			      (wchar_t *__restrict __dst,
 			       const char **__restrict __src, size_t __nmc,
@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
 }
 
 
-extern size_t __wcsnrtombs_chk (char *__restrict __dst,
-				const wchar_t **__restrict __src,
-				size_t __nwc, size_t __len,
-				mbstate_t *__restrict __ps, size_t __dstlen)
-     __THROW;
 extern size_t __REDIRECT_NTH (__wcsnrtombs_alias,
 			      (char *__restrict __dst,
 			       const wchar_t **__restrict __src,
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index c37e8619a0..5f7139f279 100644
--- a/wcsmbs/uchar.h
+++ b/wcsmbs/uchar.h
@@ -34,8 +34,16 @@
 /* Declare the C2x char8_t typedef in C2x modes, but only if the C++
   __cpp_char8_t feature test macro is not defined.  */
 #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t
+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
+/* Suppress the diagnostic regarding char8_t being a keyword in C++20.  */
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++20-compat"
+#endif
 /* Define the 8-bit character type.  */
 typedef unsigned char char8_t;
+#if __GNUC_PREREQ (10, 0) && defined __cplusplus
+# pragma GCC diagnostic pop
+#endif
 #endif
 
 #ifndef __USE_ISOCXX11
diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
index 5d6a40853d..c1321c7518 100644
--- a/wcsmbs/wchar.h
+++ b/wcsmbs/wchar.h
@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
 
 /* Define some macros helping to catch buffer overflows.  */
 #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
-# include <bits/wchar2.h>
+/* Declare all functions from bits/wchar2-decl.h first.  */
+# include <bits/wchar2-decl.h>
 #endif
 
-#include <bits/floatn.h>
+/* The following headers provide asm redirections.  These redirections must
+   appear before the first usage of these functions, e.g. in bits/wchar.h.  */
 #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
 # include <bits/wchar-ldbl.h>
 #endif
 
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+/* Now include the function definitions and redirects too.  */
+# include <bits/wchar2.h>
+#endif
+
 __END_DECLS
 
 #endif /* wchar.h  */
